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
@@ -3860,6 +3860,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
@@ -3414,6 +3414,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,31 +129,54 @@
 }
 
 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.
+  NotFoundWithUnknownBase,
+  /// \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 NotFoundWithUnknownBase 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;
+  IdNameLookupResult FoundDecl = IdNameLookupResult::NotFound;
+  for (NamedDecl *ND : RD->lookup(&II)) {
+    if (!CheckKind(ND))
+      return IdNameLookupResult::FoundNotSpecifiedKind;
+    FoundDecl = IdNameLookupResult::FoundSpecifiedKind;
+  }
+  if (FoundDecl != IdNameLookupResult::NotFound)
+    return FoundDecl;
+
   for (const auto &Base : RD->bases()) {
     const CXXRecordDecl *BaseRD = nullptr;
-    if (auto *BaseTT = Base.getType()->getAs<TagType>())
+    auto BaseTy = S.getASTContext().getCanonicalType(Base.getType());
+    if (const TagType *BaseTT = BaseTy->getAs<TagType>())
       BaseRD = BaseTT->getAsCXXRecordDecl();
-    else if (auto *TST = Base.getType()->getAs<TemplateSpecializationType>()) {
+    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())
@@ -166,61 +189,107 @@
       if (!BasePrimaryTemplate)
         continue;
       BaseRD = BasePrimaryTemplate;
+    } else if (SupposeExistInBaseParm &&
+               BaseTy->getAs<TemplateTypeParmType>() &&
+               FoundDecl == IdNameLookupResult::NotFound) {
+      FoundDecl = IdNameLookupResult::NotFoundWithUnknownBase;
     }
-    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;
-        }
-      }
+    if (!BaseRD)
+      continue;
+    switch (lookupIdNameInDependentClass(S, II, NameLoc, BaseRD,
+                                         SupposeExistInBaseParm, CheckKind)) {
+    case IdNameLookupResult::FoundNotSpecifiedKind:
+      return IdNameLookupResult::FoundNotSpecifiedKind;
+    case IdNameLookupResult::FoundSpecifiedKind:
+      FoundDecl = IdNameLookupResult::FoundSpecifiedKind;
+      break;
+    case IdNameLookupResult::NotFoundWithUnknownBase:
+      if (FoundDecl == IdNameLookupResult::NotFound)
+        FoundDecl = IdNameLookupResult::NotFoundWithUnknownBase;
+      break;
+    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 llvm::function_ref<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::NotFoundWithUnknownBase) {
+    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 +334,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 +389,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 +826,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

Reply via email to