cfe-commits try 2

http://reviews.llvm.org/D4237

Files:
  lib/Sema/SemaDecl.cpp
  test/SemaTemplate/ms-lookup-template-base-classes.cpp
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -128,6 +128,51 @@
   return false;
 }
 
+static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
+                                                      CXXRecordDecl *RD,
+                                                      const IdentifierInfo &II,
+                                                      SourceLocation NameLoc) {
+  // 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)
+      continue;
+    auto *TD = TST->getTemplateName().getAsTemplateDecl();
+    if (!TD)
+      continue;
+    auto *BasePrimaryTemplate = cast<CXXRecordDecl>(TD->getTemplatedDecl());
+    for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) {
+      if (FoundTypeDecl)
+        return ParsedType();
+      FoundTypeDecl = isa<TypeDecl>(ND);
+      if (!FoundTypeDecl)
+        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));
+
+  TypeLocBuilder Builder;
+  DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
+  DepTL.setNameLoc(NameLoc);
+  DepTL.setElaboratedKeywordLoc(SourceLocation());
+  DepTL.setQualifierLoc(SS.getWithLocInContext(Context));
+  return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
 /// \brief If the identifier refers to a type name within this scope,
 /// return the declaration of that type.
 ///
@@ -209,6 +254,18 @@
   } else {
     // 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())) {
+      auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
+      if (RD && RD->getDescribedClassTemplate()) {
+        ParsedType TypeInBase =
+            recoverFromTypeInKnownDependentBase(*this, RD, II, NameLoc);
+        if (TypeInBase)
+          return TypeInBase;
+      }
+    }
   }
 
   NamedDecl *IIDecl = nullptr;
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
@@ -275,3 +275,59 @@
 };
 template struct Derived<int>;
 }
+
+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}}
+};
+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}}
+};
+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}}
+};
+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 C : A<T>, B<T> {
+  NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+static_assert(sizeof(C<int>) == 4, "");
+}
+
+namespace type_and_decl_in_base {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T> struct B { static const T NameFromBase = 42; };
+template <typename T> struct C : A<T>, B<T> {
+  NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+}
+
+namespace template_in_base {
+template <typename T> struct A {
+  template <typename U> struct NameFromBase { U x; };
+};
+template <typename T> struct B : A<T> {
+  // Correct form.
+  typename B::template NameFromBase<T> m;
+};
+template <typename T> struct C : A<T> {
+  // Incorrect form.
+  NameFromBase<T> m; // expected-error {{unknown type name 'NameFromBase'}}
+  //expected-error@-1 {{expected member name or ';' after declaration specifiers}}
+};
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to