[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:
Alexey Bataev 2015-02-19 04:28:23 +00:00
parent 3966c61536
commit 054829b1bd
2 changed files with 135 additions and 38 deletions

View File

@ -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

View File

@ -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 {