Update after review
http://reviews.llvm.org/D8100
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplate.cpp
test/SemaCXX/MicrosoftCompatibility.cpp
test/SemaTemplate/ms-lookup-template-base-classes.cpp
test/SemaTemplate/typename-specifier.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/SemaTemplate/typename-specifier.cpp
===================================================================
--- test/SemaTemplate/typename-specifier.cpp
+++ test/SemaTemplate/typename-specifier.cpp
@@ -211,14 +211,19 @@
template <typename T> void f();
template <int N> void f();
-// expected-error@+1 {{missing 'typename' prior to dependent type name 'S<int>::type'}}
+#ifndef MSVC
+// expected-error@+2 {{missing 'typename' prior to dependent type name 'S<int>::type'}}
+#endif
template <typename T> void g() { f</*typename*/ S<T>::type(int())>(); }
// Adding typename does fix the diagnostic.
template <typename T> void h() { f<typename S<T>::type(int())>(); }
void j() {
- g<int>(); // expected-note-re {{in instantiation {{.*}} requested here}}
+#ifndef MSVC
+ // expected-note-re@+2 {{in instantiation {{.*}} requested here}}
+#endif
+ g<int>();
h<int>();
}
} // namespace func_type_vs_construct_tmp
Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp
===================================================================
--- test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -64,7 +64,7 @@
class B : public A<T> {
public:
void f() {
- var = 3; // expected-warning {{use of undeclared identifier 'var'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}}
+ var = 3; // expected-warning {{use of identifier 'var' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
}
};
@@ -160,7 +160,7 @@
class A : public T {
public:
void f(int hWnd) {
- m_hWnd = 1; // expected-warning {{use of undeclared identifier 'm_hWnd'; unqualified lookup into dependent bases of class template 'A' is a Microsoft extension}}
+ m_hWnd = 1; // expected-warning {{use of identifier 'm_hWnd' found via unqualified lookup into dependent bases of class template 'A<T>' is a Microsoft extension}}
}
};
@@ -281,32 +281,32 @@
namespace typedef_in_base {
template <typename T> struct A { typedef T NameFromBase; };
template <typename T> struct B : A<T> {
- NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
};
static_assert(sizeof(B<int>) == 4, "");
}
namespace struct_in_base {
template <typename T> struct A { struct NameFromBase {}; };
template <typename T> struct B : A<T> {
- NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
};
static_assert(sizeof(B<int>) == 1, "");
}
namespace enum_in_base {
template <typename T> struct A { enum NameFromBase { X }; };
template <typename T> struct B : A<T> {
- NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
};
static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), "");
}
namespace two_types_in_base {
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 {{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}}
+ 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 template 'C<T>' is a Microsoft extension}}
};
static_assert(sizeof(C<int>) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
}
@@ -322,7 +322,7 @@
namespace classify_type_from_base {
template <typename T> struct A { struct NameFromBase {}; };
template <typename T> struct B : A<T> {
- A<NameFromBase> m; // expected-warning {{found via unqualified lookup into dependent bases}}
+ A<NameFromBase> m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
};
}
@@ -387,34 +387,34 @@
template <typename T>
struct B : A {};
template <typename T>
-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}}
+struct C : B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'C<T>' 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}}
+struct D : A<T>, B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'D<T>' 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}}
+struct D : C<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'D<T>' 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}}
+struct C : B<T>, virtual A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'C<T>' is a Microsoft extension}}
C<int> c;
}
@@ -424,7 +424,7 @@
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:}}
+struct C : B<T>, public A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'C<T>' 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}}
}
@@ -434,14 +434,14 @@
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}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' 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}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' 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}}
+ NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
};
template<typename T> struct F : B<T>::C {
NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
@@ -508,14 +508,14 @@
struct A { typedef T NameFromBase; };
template <typename T>
struct B : A<T> {
- // expected-warning@+1 {{found via unqualified lookup into dependent bases}}
+ // expected-warning@+1 {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class template 'B<T>' is a Microsoft extension}}
int x = f<NameFromBase>();
};
// Dependent base class with enum.
template <typename T> struct C { enum { NameFromBase = 4 }; };
template <typename T> struct D : C<T> {
- // expected-warning@+1 {{use of undeclared identifier 'NameFromBase'; unqualified lookup into dependent bases}}
+ // expected-warning@+1 {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases}}
int x = f<NameFromBase>();
};
}
@@ -547,3 +547,119 @@
XXX x; // expected-error {{unknown type name}}
};
}
+
+namespace complex_qualified_and_unqualified_lookup {
+template <class T> struct Base {
+ T a;
+ // expected-note@+2 4 {{template is declared here}}
+ // expected-note@+1 2 {{must qualify identifier to find this declaration in dependent base class}}
+ template <class U> struct InnerBase {};
+ typedef InnerBase<T> TDInnerBase;
+ // expected-note@+1 {{must qualify identifier to find this declaration in dependent base class}}
+ template <class G> void f(G t) {}
+ // expected-note@+1 {{must qualify identifier to find this declaration in dependent base class}}
+ template <class G> static void fs(G t) {}
+};
+
+template <class T> struct Sub : Base<T> {
+ // expected-note@+2 4 {{template is declared here}}
+ // expected-note@+1 2 {{must qualify identifier to find this declaration in dependent base class}}
+ template <class U> struct InnerSub {};
+ typedef InnerSub<T> TDInnerSub;
+ void g() {}
+};
+
+template <class T> struct SubSub : Sub<T> {
+ // expected-warning@+1 {{use of identifier 'TDInnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ TDInnerBase b;
+ void g() {
+ typedef Base<T> BaseTD;
+ BaseTD::TDInnerBase();
+ typename Sub<T>::template InnerBase<T>();
+ // expected-warning@+1 {{use of identifier 'a' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ a = T();
+ // expected-warning@+1 {{use of identifier 'TDInnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ b = TDInnerBase();
+ // expected-warning@+1 {{use of identifier 'f' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ f(4);
+ // expected-warning@+2 {{use of identifier 'f' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ // expected-warning@+1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ f<int>(4);
+ // expected-warning@+2 {{use of identifier 'f' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ // expected-warning@+1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ f<T>(4);
+ this->f(4);
+ // expected-warning@+1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ this->f<int>(4);
+ // expected-warning@+1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ this->f<T>(4);
+ Sub<T>::template f<int>(4);
+ this->template f<int>(4);
+ Sub<T>::template f<T>(4);
+ this->template f<T>(4);
+ // expected-warning@+1 {{use of identifier 'InnerBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ InnerBase(); // expected-error {{cannot refer to class template 'InnerBase' without a template argument list}}
+ // expected-warning@+1 {{use of identifier 'InnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ InnerBase<T>();
+ // expected-warning@+1 {{use of identifier 'TDInnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ TDInnerBase();
+ // expected-warning@+1 {{use of identifier 'InnerSub' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ InnerSub(); // expected-error {{cannot refer to class template 'InnerSub' without a template argument list}}
+ // expected-warning@+1 {{use of identifier 'InnerSub' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ InnerSub<T>();
+ // expected-warning@+1 {{use of identifier 'TDInnerSub' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ TDInnerSub();
+ Sub<T>::InnerBase<T>();
+ Sub<T>::InnerBase(); // expected-error {{cannot refer to class template 'InnerBase' without a template argument list}}
+ Sub<T>::TDInnerBase();
+ Sub<T>::InnerSub<T>();
+ Sub<T>::InnerSub(); // expected-error {{cannot refer to class template 'InnerSub' without a template argument list}}
+ Sub<T>::TDInnerSub();
+ }
+ static void gs() {
+ typedef Base<T> BaseTD;
+ BaseTD::TDInnerBase();
+ // expected-warning@+1 {{use of identifier 'fs' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ fs(4);
+ // expected-warning@+2 {{use of identifier 'fs' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ // expected-warning@+1 {{use 'template' keyword to treat 'fs' as a dependent template name}}
+ fs<int>(4);
+ // expected-warning@+2 {{use of identifier 'fs' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ // expected-warning@+1 {{use 'template' keyword to treat 'fs' as a dependent template name}}
+ fs<T>(4);
+ // expected-warning@+1 {{use of identifier 'InnerBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ InnerBase(); // expected-error {{cannot refer to class template 'InnerBase' without a template argument list}}
+ // expected-warning@+1 {{use of identifier 'InnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ InnerBase<T>();
+ // expected-warning@+1 {{use of identifier 'TDInnerBase' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ TDInnerBase();
+ // expected-warning@+1 {{use of identifier 'InnerSub' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ InnerSub<T>();
+ // expected-warning@+1 {{use of identifier 'InnerSub' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ InnerSub(); // expected-error {{cannot refer to class template 'InnerSub' without a template argument list}}
+ // expected-warning@+1 {{use of identifier 'TDInnerSub' found via unqualified lookup into dependent bases of class template 'SubSub<T>' is a Microsoft extension}}
+ TDInnerSub();
+ Sub<T>::fs(4);
+ // expected-warning@+1 {{use 'template' keyword to treat 'fs' as a dependent template name}}
+ Sub<T>::fs<int>(4);
+ // expected-warning@+1 {{use 'template' keyword to treat 'fs' as a dependent template name}}
+ Sub<T>::fs<T>(4);
+ Sub<T>::InnerBase<T>();
+ Sub<T>::InnerBase(); // expected-error {{cannot refer to class template 'InnerBase' without a template argument list}}
+ Sub<T>::TDInnerBase();
+ Sub<T>::InnerSub<T>();
+ Sub<T>::InnerSub(); // expected-error {{cannot refer to class template 'InnerSub' without a template argument list}}
+ Sub<T>::TDInnerSub();
+ }
+};
+
+void foo() {
+ Sub<int> i;
+ SubSub<int> ii;
+ i.g();
+ // expected-note@+1 {{in instantiation of member function 'complex_qualified_and_unqualified_lookup::SubSub<int>::g' requested here}}
+ ii.g();
+ // expected-note@+1 {{in instantiation of member function 'complex_qualified_and_unqualified_lookup::SubSub<int>::gs' requested here}}
+ SubSub<int>::gs();
+}
+}
Index: test/SemaCXX/MicrosoftCompatibility.cpp
===================================================================
--- test/SemaCXX/MicrosoftCompatibility.cpp
+++ test/SemaCXX/MicrosoftCompatibility.cpp
@@ -166,14 +166,14 @@
typedef B<U> Base2;
typedef A<U> Base3;
- A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+ A<T>::TYPE a1;
+ Base1::TYPE a2;
- B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
+ B<U>::TYPE a3;
+ Base2::TYPE a4;
- A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
- Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
+ A<U>::TYPE a5;
+ Base3::TYPE a6;
};
class D {
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3864,6 +3864,9 @@
def ext_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 "
"found via unqualified lookup into dependent bases of class templates is a "
"Microsoft extension">, InGroup<Microsoft>;
+def ext_found_via_dependent_base_lookup : ExtWarn<"use of identifier %0 "
+ "found via unqualified lookup into dependent bases of class template %1 is a "
+ "Microsoft extension">, InGroup<Microsoft>;
def note_dependent_var_use : Note<"must qualify identifier to find this "
"declaration in dependent base class">;
def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3497,6 +3497,40 @@
// Primary Expressions.
SourceRange getExprRange(Expr *E) const;
+ /// \brief Checks if currently looking for symbols in a class with dependent
+ /// bases. Used in Microsoft Compatibility mode for better compatibility
+ /// during lookup into classes with dependent bases.
+ /// \param LastChanceToRecover true if no need to check for decl existence in
+ /// base dependent classes, false if still need to check.
+ /// \param SS If not nullptr and not empty the base class is calculated from
+ /// this scope. If not nullptr and empty and \a ObjectType is empty then it is
+ /// calculated in this method from the current context.
+ /// \param ObjectType If specified the base class is calculated from this
+ /// type.
+ /// \param II Used for diagnostic only. If \a SS is not nullptr and empty and
+ /// \a ObjectType is empty and \a is not nullptr \a SS is calculated and a
+ /// diagnostic is emitted.
+ /// \return true if currently trying to lookup in class with the dependent
+ /// base, false otherwise.
+ bool isInClassWithAnyDependentBase(SourceLocation Loc,
+ bool IsLastChanceToRecover,
+ CXXScopeSpec *SS, QualType ObjectType,
+ const IdentifierInfo *II);
+
+ /// \brief Checks if the specified identifier \a II is a class template
+ /// declaration declared in a class with dependent bases (specified in \a SS
+ /// scope).
+ bool isClassTemplateInClassWithAnyDependentBase(CXXScopeSpec &SS,
+ SourceLocation Loc,
+ const IdentifierInfo &II);
+
+ /// \brief Checks if the specified identifier \a II is any member declared in
+ /// a class with dependent bases (specified in \a SS scope).
+ bool isMemberInClassWithAnyDependentBase(CXXScopeSpec &SS, SourceLocation Loc,
+ const IdentifierInfo &II,
+ bool NonInstanceMemberOnly,
+ bool SupposeExistInBaseParm);
+
ExprResult ActOnIdExpression(
Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -129,98 +129,166 @@
}
namespace {
-enum class UnqualifiedTypeNameLookupResult {
+/// \brief Result of lookup for members with the specified identifier into a
+/// class with any dependent base.
+enum class IdNameLookupResult {
+ /// \brief No members found at all.
NotFound,
- FoundNonType,
- FoundType
+ /// \brief If found a member, but its type does not match the expected one.
+ FoundNotSpecifiedKind,
+ /// \brief There are no members is found, but class has a base of class
+ /// TemplateTypeParmType and we are allowed to suppose that the specified
+ /// identifier may be a member of this base.
+ SupposeFoundSpecifiedKind,
+ /// \brief Found a member of the expected type.
+ FoundSpecifiedKind,
};
} // namespace
-/// \brief Tries to perform unqualified lookup of the type decls in bases for
+/// \brief Tries to perform unqualified lookup of the 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) {
+/// \return \a NotFound if no any decls is found, \a FoundNotSpecifiedKind if
+/// found a decl of different type, \a FoundSpecifiedKind if only decls of the
+/// expected types are found. If \a SupposeExistInBaseParm is true and one of
+/// the base classes is a TemplateTypeParmType then it is supposed that the
+/// specified identifier may be a field of that base class. If there are no
+/// other identifiers is found, \a SupposeFoundSpecifiedKind is returned in this
+/// case.
+static IdNameLookupResult lookupIdNameInDependentClass(
+ Sema &S, const IdentifierInfo &II, SourceLocation NameLoc,
+ const CXXRecordDecl *RD, bool SupposeExistInBaseParm,
+ const llvm::function_ref<bool(NamedDecl *)> &CheckKind) {
if (!RD->hasDefinition())
- return UnqualifiedTypeNameLookupResult::NotFound;
+ return IdNameLookupResult::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;
+ IdNameLookupResult FoundDecl = IdNameLookupResult::NotFound;
+ for (NamedDecl *ND : RD->lookup(&II)) {
+ if (!CheckKind(ND))
+ return IdNameLookupResult::FoundNotSpecifiedKind;
+ FoundDecl = IdNameLookupResult::FoundSpecifiedKind;
+ }
+ if (FoundDecl == IdNameLookupResult::NotFound) {
+ for (const auto &Base : RD->bases()) {
+ const CXXRecordDecl *BaseRD = nullptr;
+ auto BaseTy = S.getASTContext().getCanonicalType(Base.getType());
+ if (const TagType *BaseTT = BaseTy->getAs<TagType>())
+ BaseRD = BaseTT->getAsCXXRecordDecl();
+ else if (const TemplateSpecializationType *TST =
+ BaseTy->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;
+ } else if (SupposeExistInBaseParm &&
+ BaseTy->getAs<TemplateTypeParmType>() &&
+ FoundDecl == IdNameLookupResult::NotFound) {
+ FoundDecl = IdNameLookupResult::SupposeFoundSpecifiedKind;
+ }
+ if (BaseRD) {
+ switch (lookupIdNameInDependentClass(
+ S, II, NameLoc, BaseRD, SupposeExistInBaseParm, CheckKind)) {
+ case IdNameLookupResult::FoundNotSpecifiedKind:
+ return IdNameLookupResult::FoundNotSpecifiedKind;
+ case IdNameLookupResult::FoundSpecifiedKind:
+ FoundDecl = IdNameLookupResult::FoundSpecifiedKind;
+ break;
+ case IdNameLookupResult::SupposeFoundSpecifiedKind:
+ if (FoundDecl == IdNameLookupResult::NotFound)
+ FoundDecl = IdNameLookupResult::SupposeFoundSpecifiedKind;
break;
- case UnqualifiedTypeNameLookupResult::NotFound:
+ case IdNameLookupResult::NotFound:
break;
}
}
}
}
- return FoundTypeDecl;
+ return FoundDecl;
}
-static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
- const IdentifierInfo &II,
- SourceLocation NameLoc) {
+static bool
+isDeclInDependentClass(Sema &S, CXXScopeSpec &SS, SourceLocation Loc,
+ const IdentifierInfo &II, bool SupposeExistInBaseParm,
+ const std::function<bool(NamedDecl *)> &CheckKind) {
// Lookup in the parent class template context, if any.
const CXXRecordDecl *RD = nullptr;
- UnqualifiedTypeNameLookupResult FoundTypeDecl =
- UnqualifiedTypeNameLookupResult::NotFound;
- for (DeclContext *DC = S.CurContext;
- DC && FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound;
+ IdNameLookupResult FoundDecl = IdNameLookupResult::NotFound;
+ auto *DC = S.computeDeclContext(SS, /*EnteringContext=*/true);
+ if (!DC)
+ DC = S.CurContext;
+ for (; DC && FoundDecl == IdNameLookupResult::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())
- FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD);
+ FoundDecl = lookupIdNameInDependentClass(
+ S, II, Loc, RD, SupposeExistInBaseParm, CheckKind);
}
- if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType)
+ if (FoundDecl == IdNameLookupResult::FoundSpecifiedKind ||
+ FoundDecl == IdNameLookupResult::SupposeFoundSpecifiedKind) {
+ if (SS.isEmpty()) {
+ auto *NNS =
+ NestedNameSpecifier::Create(S.getASTContext(),
+ /*Prefix=*/nullptr,
+ /*Template=*/false, RD->getTypeForDecl());
+ SS.MakeTrivial(S.getASTContext(), NNS, SourceRange(Loc, Loc));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Sema::isClassTemplateInClassWithAnyDependentBase(
+ CXXScopeSpec &SS, SourceLocation Loc, const IdentifierInfo &II) {
+ return isDeclInDependentClass(
+ *this, SS, Loc, II, /*SupposeExistInBaseParm=*/false,
+ [](NamedDecl *ND) -> bool { return isa<ClassTemplateDecl>(ND); });
+}
+
+bool Sema::isMemberInClassWithAnyDependentBase(CXXScopeSpec &SS,
+ SourceLocation Loc,
+ const IdentifierInfo &II,
+ bool NonInstanceMemberOnly,
+ bool SupposeExistInBaseParm) {
+ if (NonInstanceMemberOnly)
+ return isDeclInDependentClass(
+ *this, SS, Loc, II, SupposeExistInBaseParm, [](NamedDecl *ND) {
+ return ND->isCXXClassMember() && !ND->isCXXInstanceMember();
+ });
+ return isDeclInDependentClass(
+ *this, SS, Loc, II, SupposeExistInBaseParm,
+ [](NamedDecl *ND) { return ND->isCXXClassMember(); });
+}
+
+static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
+ CXXScopeSpec &SS,
+ const IdentifierInfo &II,
+ SourceLocation NameLoc) {
+ bool IsUnqualifiedLookup = SS.isEmpty();
+ if (!isDeclInDependentClass(
+ S, SS, NameLoc, II, /*SupposeExistInBaseParm=*/false,
+ [](NamedDecl *ND) -> bool { return isa<TypeDecl>(ND); }))
return ParsedType();
// We found some types in dependent base classes. Recover as if the user
// wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the
// lookup during template instantiation.
- S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II;
-
ASTContext &Context = S.Context;
- auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false,
- cast<Type>(Context.getRecordType(RD)));
- QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II);
-
- CXXScopeSpec SS;
- SS.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+ if (IsUnqualifiedLookup)
+ S.Diag(NameLoc, diag::ext_found_via_dependent_base_lookup)
+ << &II << S.computeDeclContext(SS, /*EnteringContext=*/true);
+ QualType T =
+ Context.getDependentNameType(ETK_Typename, SS.getScopeRep(), &II);
TypeLocBuilder Builder;
DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
@@ -265,8 +333,16 @@
//
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
- if (!isClassName && !IsCtorOrDtorName)
+ if (!isClassName && !IsCtorOrDtorName) {
+ // For qualified lookup in a class template in MSVC mode, look into
+ // dependent base classes where the primary class template is known.
+ if (getLangOpts().MSVCCompat) {
+ if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(
+ *this, *SS, II, NameLoc))
+ return TypeInBase;
+ }
return ParsedType();
+ }
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
@@ -312,13 +388,17 @@
// Perform unqualified name lookup.
LookupName(Result, S);
- // For unqualified lookup in a class template in MSVC mode, look into
- // dependent base classes where the primary class template is known.
- if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) {
- if (ParsedType TypeInBase =
- recoverFromTypeInKnownDependentBase(*this, II, NameLoc))
- return TypeInBase;
- }
+ }
+
+ // For unqualified lookup in a class template in MSVC mode, look into
+ // dependent base classes where the primary class template is known.
+ CXXScopeSpec NewSS;
+ if (SS && SS->isValid())
+ NewSS = *SS;
+ if (Result.empty() && getLangOpts().MSVCCompat) {
+ if (ParsedType TypeInBase =
+ recoverFromTypeInKnownDependentBase(*this, NewSS, II, NameLoc))
+ return TypeInBase;
}
NamedDecl *IIDecl = nullptr;
@@ -745,9 +825,10 @@
// For unqualified lookup in a class template in MSVC mode, look into
// dependent base classes where the primary class template is known.
- if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) {
+ CXXScopeSpec NewSS = SS;
+ if (Result.empty() && getLangOpts().MSVCCompat) {
if (ParsedType TypeInBase =
- recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc))
+ recoverFromTypeInKnownDependentBase(*this, NewSS, *Name, NameLoc))
return TypeInBase;
}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -168,7 +168,34 @@
LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName);
LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
MemberOfUnknownSpecialization);
- if (R.empty()) return TNK_Non_template;
+ if (R.empty()) {
+ // In MSVC mode resolve symbol in a class with dependent bases on
+ // instantiation.
+ if (getLangOpts().MSVCCompat && !hasTemplateKeyword &&
+ Name.getKind() == UnqualifiedId::IK_Identifier) {
+ if (S && S->getFnParent() &&
+ isInClassWithAnyDependentBase(Name.getLocStart(),
+ /*IsLastChanceToRecover=*/false, &SS,
+ ObjectType, Name.Identifier)) {
+ R.suppressDiagnostics();
+ // Mark class template declaration as a TNK_Type_template for proper AST
+ // node generation if it used in expression in constructs like
+ // typecasts/constructor calls:
+ // if (Templ<T>(a))
+ // ^~~~~
+ // typename
+ // use of undeclared identifier 'Templ'
+ if (isClassTemplateInClassWithAnyDependentBase(SS, Name.getLocStart(),
+ *Name.Identifier)) {
+ TemplateResult = TemplateTy::make(Context.getDependentTemplateName(
+ SS.getScopeRep(), Name.Identifier));
+ return TNK_Type_template;
+ }
+ MemberOfUnknownSpecialization = true;
+ }
+ }
+ return TNK_Non_template;
+ }
if (R.isAmbiguous()) {
// Suppress diagnostics; we'll redo this lookup later.
R.suppressDiagnostics();
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1950,51 +1950,51 @@
return true;
}
-/// In Microsoft mode, if we are inside a template class whose parent class has
-/// dependent base classes, and we can't resolve an unqualified identifier, then
-/// assume the identifier is a member of a dependent base class. We can only
-/// recover successfully in static methods, instance methods, and other contexts
-/// where 'this' is available. This doesn't precisely match MSVC's
-/// instantiation model, but it's close enough.
-static Expr *
-recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
- DeclarationNameInfo &NameInfo,
- SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo *TemplateArgs) {
- // Only try to recover from lookup into dependent bases in static methods or
- // contexts where 'this' is available.
- QualType ThisType = S.getCurrentThisType();
- const CXXRecordDecl *RD = nullptr;
- if (!ThisType.isNull())
- RD = ThisType->getPointeeType()->getAsCXXRecordDecl();
- else if (auto *MD = dyn_cast<CXXMethodDecl>(S.CurContext))
- RD = MD->getParent();
+bool Sema::isInClassWithAnyDependentBase(SourceLocation Loc,
+ bool IsLastChanceToRecover,
+ CXXScopeSpec *SS, QualType ObjectType,
+ const IdentifierInfo *II) {
+ CXXRecordDecl *RD = nullptr;
+ if (!ObjectType.isNull()) {
+ // If ObjectType is defined - get cxx scope from this type.
+ RD = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(ObjectType));
+ } else if (!SS || SS->isEmpty()) {
+ // Only try to recover from lookup into dependent bases in static methods
+ // or contexts where 'this' is available.
+ QualType ThisType = getCurrentThisType();
+ if (!ThisType.isNull())
+ RD = ThisType->getPointeeType()->getAsCXXRecordDecl();
+ else if (auto *MD = dyn_cast<CXXMethodDecl>(CurContext))
+ RD = MD->getParent();
+ } else {
+ // Cxx scope is set - get class from this scope.
+ RD = dyn_cast_or_null<CXXRecordDecl>(
+ computeDeclContext(*SS, /*EnteringContext=*/true));
+ }
if (!RD || !RD->hasAnyDependentBases())
- return nullptr;
-
- // Diagnose this as unqualified lookup into a dependent base class. If 'this'
- // is available, suggest inserting 'this->' as a fixit.
- SourceLocation Loc = NameInfo.getLoc();
- auto DB = S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base);
- DB << NameInfo.getName() << RD;
-
- if (!ThisType.isNull()) {
- DB << FixItHint::CreateInsertion(Loc, "this->");
- return CXXDependentScopeMemberExpr::Create(
- Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,
- /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
- /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs);
- }
-
- // Synthesize a fake NNS that points to the derived class. This will
- // perform name lookup during template instantiation.
- CXXScopeSpec SS;
- auto *NNS =
- NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl());
- SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc));
- return DependentScopeDeclRefExpr::Create(
- Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
- TemplateArgs);
+ return false;
+ // Compute temp cxx scope to check that II member decl exists in this scope.
+ CXXScopeSpec TempSS;
+ if (!SS || SS->isEmpty()) {
+ auto *NNS = NestedNameSpecifier::Create(
+ Context, /*Prefix=*/nullptr, /*Template=*/false, RD->getTypeForDecl());
+ TempSS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc));
+ } else {
+ TempSS = *SS;
+ }
+ if (isMemberInClassWithAnyDependentBase(TempSS, Loc, *II,
+ getCurrentThisType().isNull(),
+ IsLastChanceToRecover)) {
+ // Found specified member decl in dependent class.
+ if (ObjectType.isNull() && SS && SS->isEmpty()) {
+ *SS = TempSS;
+ if (II)
+ Diag(Loc, diag::ext_found_via_dependent_base_lookup)
+ << II << computeDeclContext(*SS, /*EnteringContext=*/true);
+ }
+ return true;
+ }
+ return false;
}
ExprResult
@@ -2102,10 +2102,24 @@
bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
if (R.empty() && !ADL) {
- if (SS.isEmpty() && getLangOpts().MSVCCompat) {
- if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo,
- TemplateKWLoc, TemplateArgs))
- return E;
+ // In Microsoft mode, if we are inside a template class whose parent class
+ // has dependent base classes, and we can't resolve an unqualified
+ // identifier, then assume the identifier is a member of a dependent base
+ // class. We can only recover successfully in static methods, instance
+ // methods, and other contexts where 'this' is available. This doesn't
+ // precisely match MSVC's instantiation model, but it's close enough.
+ if (SS.isEmpty() && getLangOpts().MSVCCompat &&
+ isInClassWithAnyDependentBase(NameLoc, /*IsLastChanceToRecover=*/true,
+ &SS, QualType(), II)) {
+ if (getCurrentThisType().isNull())
+ return DependentScopeDeclRefExpr::Create(
+ Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
+ TemplateArgs);
+ return CXXDependentScopeMemberExpr::Create(
+ Context, /*This=*/nullptr, getCurrentThisType(),
+ /*IsArrow=*/true,
+ /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
+ /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs);
}
// Don't diagnose an empty lookup for inline assembly.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits