forked from OSchip/llvm-project
[MSVC] Improved lookup into dependent/non-dependent bases of dependent class
Patch improves lookup into dependendt bases of dependent class and adds lookup into non-dependent bases. Differential Revision: http://reviews.llvm.org/D7173 llvm-svn: 229817
This commit is contained in:
parent
3966c61536
commit
054829b1bd
|
@ -128,45 +128,85 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
enum class UnqualifiedTypeNameLookupResult {
|
||||
NotFound,
|
||||
FoundNonType,
|
||||
FoundType
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/// \brief Tries to perform unqualified lookup of the type decls in bases for
|
||||
/// dependent class.
|
||||
/// \return \a NotFound if no any decls is found, \a FoundNotType if found not a
|
||||
/// type decl, \a FoundType if only type decls are found.
|
||||
static UnqualifiedTypeNameLookupResult
|
||||
lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II,
|
||||
SourceLocation NameLoc,
|
||||
const CXXRecordDecl *RD) {
|
||||
if (!RD->hasDefinition())
|
||||
return UnqualifiedTypeNameLookupResult::NotFound;
|
||||
// Look for type decls in base classes.
|
||||
UnqualifiedTypeNameLookupResult FoundTypeDecl =
|
||||
UnqualifiedTypeNameLookupResult::NotFound;
|
||||
for (const auto &Base : RD->bases()) {
|
||||
const CXXRecordDecl *BaseRD = nullptr;
|
||||
if (auto *BaseTT = Base.getType()->getAs<TagType>())
|
||||
BaseRD = BaseTT->getAsCXXRecordDecl();
|
||||
else if (auto *TST = Base.getType()->getAs<TemplateSpecializationType>()) {
|
||||
// Look for type decls in dependent base classes that have known primary
|
||||
// templates.
|
||||
if (!TST || !TST->isDependentType())
|
||||
continue;
|
||||
auto *TD = TST->getTemplateName().getAsTemplateDecl();
|
||||
if (!TD)
|
||||
continue;
|
||||
auto *BasePrimaryTemplate =
|
||||
dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
|
||||
if (!BasePrimaryTemplate)
|
||||
continue;
|
||||
BaseRD = BasePrimaryTemplate;
|
||||
}
|
||||
if (BaseRD) {
|
||||
for (NamedDecl *ND : BaseRD->lookup(&II)) {
|
||||
if (!isa<TypeDecl>(ND))
|
||||
return UnqualifiedTypeNameLookupResult::FoundNonType;
|
||||
FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType;
|
||||
}
|
||||
if (FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound) {
|
||||
switch (lookupUnqualifiedTypeNameInBase(S, II, NameLoc, BaseRD)) {
|
||||
case UnqualifiedTypeNameLookupResult::FoundNonType:
|
||||
return UnqualifiedTypeNameLookupResult::FoundNonType;
|
||||
case UnqualifiedTypeNameLookupResult::FoundType:
|
||||
FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType;
|
||||
break;
|
||||
case UnqualifiedTypeNameLookupResult::NotFound:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FoundTypeDecl;
|
||||
}
|
||||
|
||||
static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
|
||||
const IdentifierInfo &II,
|
||||
SourceLocation NameLoc) {
|
||||
// Find the first parent class template context, if any.
|
||||
// FIXME: Perform the lookup in all enclosing class templates.
|
||||
// Lookup in the parent class template context, if any.
|
||||
const CXXRecordDecl *RD = nullptr;
|
||||
for (DeclContext *DC = S.CurContext; DC; DC = DC->getParent()) {
|
||||
UnqualifiedTypeNameLookupResult FoundTypeDecl =
|
||||
UnqualifiedTypeNameLookupResult::NotFound;
|
||||
for (DeclContext *DC = S.CurContext;
|
||||
DC && FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound;
|
||||
DC = DC->getParent()) {
|
||||
// Look for type decls in dependent base classes that have known primary
|
||||
// templates.
|
||||
RD = dyn_cast<CXXRecordDecl>(DC);
|
||||
if (RD && RD->getDescribedClassTemplate())
|
||||
break;
|
||||
FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD);
|
||||
}
|
||||
if (!RD)
|
||||
return ParsedType();
|
||||
|
||||
// Look for type decls in dependent base classes that have known primary
|
||||
// templates.
|
||||
bool FoundTypeDecl = false;
|
||||
for (const auto &Base : RD->bases()) {
|
||||
auto *TST = Base.getType()->getAs<TemplateSpecializationType>();
|
||||
if (!TST || !TST->isDependentType())
|
||||
continue;
|
||||
auto *TD = TST->getTemplateName().getAsTemplateDecl();
|
||||
if (!TD)
|
||||
continue;
|
||||
auto *BasePrimaryTemplate =
|
||||
dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
|
||||
if (!BasePrimaryTemplate)
|
||||
continue;
|
||||
// FIXME: Allow lookup into non-dependent bases of dependent bases, possibly
|
||||
// by calling or integrating with the main LookupQualifiedName mechanism.
|
||||
for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) {
|
||||
if (FoundTypeDecl)
|
||||
return ParsedType();
|
||||
FoundTypeDecl = isa<TypeDecl>(ND);
|
||||
if (!FoundTypeDecl)
|
||||
return ParsedType();
|
||||
}
|
||||
}
|
||||
if (!FoundTypeDecl)
|
||||
if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType)
|
||||
return ParsedType();
|
||||
|
||||
// We found some types in dependent base classes. Recover as if the user
|
||||
|
|
|
@ -303,12 +303,12 @@ static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), "");
|
|||
}
|
||||
|
||||
namespace two_types_in_base {
|
||||
template <typename T> struct A { typedef T NameFromBase; };
|
||||
template <typename T> struct B { struct NameFromBase { T m; }; };
|
||||
template <typename T> struct A { typedef T NameFromBase; }; // expected-note {{member found by ambiguous name lookup}}
|
||||
template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-note {{member found by ambiguous name lookup}}
|
||||
template <typename T> struct C : A<T>, B<T> {
|
||||
NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
|
||||
NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
};
|
||||
static_assert(sizeof(C<int>) == 4, "");
|
||||
static_assert(sizeof(C<int>) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
|
||||
}
|
||||
|
||||
namespace type_and_decl_in_base {
|
||||
|
@ -386,9 +386,66 @@ namespace type_in_base_of_dependent_base {
|
|||
struct A { typedef int NameFromBase; };
|
||||
template <typename T>
|
||||
struct B : A {};
|
||||
// FIXME: MSVC accepts this.
|
||||
template <typename T>
|
||||
struct C : B<T> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
|
||||
struct C : B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
}
|
||||
|
||||
namespace type_in_second_dependent_base {
|
||||
template <typename T>
|
||||
struct A {};
|
||||
template<typename T>
|
||||
struct B { typedef T NameFromBase; };
|
||||
template <typename T>
|
||||
struct D : A<T>, B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
}
|
||||
|
||||
namespace type_in_second_non_dependent_base {
|
||||
struct A {};
|
||||
struct B { typedef int NameFromBase; };
|
||||
template<typename T>
|
||||
struct C : A, B {};
|
||||
template <typename T>
|
||||
struct D : C<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
}
|
||||
|
||||
namespace type_in_virtual_base_of_dependent_base {
|
||||
template <typename T>
|
||||
struct A { typedef T NameFromBase; };
|
||||
template <typename T>
|
||||
struct B : virtual A<T> {};
|
||||
template <typename T>
|
||||
struct C : B<T>, virtual A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
C<int> c;
|
||||
}
|
||||
|
||||
namespace type_in_base_of_multiple_dependent_bases {
|
||||
template <typename T>
|
||||
struct A { typedef T NameFromBase; };
|
||||
template <typename T>
|
||||
struct B : public A<T> {};
|
||||
template <typename T>
|
||||
struct C : B<T>, public A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-warning {{direct base 'A<int>' is inaccessible due to ambiguity:}}
|
||||
C<int> c; // expected-note {{in instantiation of template class 'type_in_base_of_multiple_dependent_bases::C<int>' requested here}}
|
||||
}
|
||||
|
||||
namespace type_in_dependent_base_of_non_dependent_type {
|
||||
template<typename T> struct A { typedef int NameFromBase; };
|
||||
template<typename T> struct B : A<T> {
|
||||
struct C;
|
||||
template<typename TT>
|
||||
struct D : C {
|
||||
NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
};
|
||||
struct E : C {
|
||||
NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
};
|
||||
};
|
||||
template<typename T> struct B<T>::C : B {
|
||||
NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
};
|
||||
template<typename T> struct F : B<T>::C {
|
||||
NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace lookup_in_function_contexts {
|
||||
|
|
Loading…
Reference in New Issue