return false;
}
+static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
+ const IdentifierInfo &II,
+ SourceLocation NameLoc) {
+ auto *RD = dyn_cast<CXXRecordDecl>(S.CurContext);
+ if (!RD || !RD->getDescribedClassTemplate())
+ 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 = cast<CXXRecordDecl>(TD->getTemplatedDecl());
+ for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) {
+ if (FoundTypeDecl)
+ return ParsedType();
+ FoundTypeDecl = isa<TypeDecl>(ND);
+ if (!FoundTypeDecl)
+ return ParsedType();
+ }
+ }
+ 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.
///
} 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())) {
+ if (ParsedType TypeInBase =
+ recoverFromTypeInKnownDependentBase(*this, II, NameLoc))
+ return TypeInBase;
+ }
}
NamedDecl *IIDecl = nullptr;
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, !CurMethod);
+ // 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) {
+ if (ParsedType TypeInBase =
+ recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc))
+ return TypeInBase;
+ }
+
// Perform lookup for Objective-C instance variables (including automatically
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
-// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1y -fms-compatibility -fsyntax-only -verify %s
template <class T>
};
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 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}}
+};
+}
+
+namespace classify_nontype_from_base {
+// MSVC does not do lookup of non-type declarations from dependent template base
+// classes. The extra lookup only applies to types.
+template <typename T> struct A { void NameFromBase() {} };
+template <void (*F)()> struct B { };
+template <typename T> struct C : A<T> {
+ B<C::NameFromBase> a; // correct
+ B<NameFromBase> b; // expected-error {{use of undeclared identifier '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}}
+};
+}
+
+namespace type_in_inner_class_in_base {
+template <typename T>
+struct A {
+ struct B { typedef T NameFromBase; };
+};
+template <typename T>
+struct C : A<T>::B { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+}
+
+namespace type_in_inner_template_class_in_base {
+template <typename T>
+struct A {
+ template <typename U> struct B { typedef U InnerType; };
+};
+template <typename T>
+struct C : A<T>::template B<T> {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+}
+
+namespace have_nondependent_base {
+template <typename T>
+struct A {
+ // Nothing, lookup should fail.
+};
+template <typename T>
+struct B : A<T> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+struct C : A<int> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+}
+
+namespace lookup_in_function_contexts {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T>
+struct B : A<T> {
+ // expected-warning@+1 {{lookup into dependent bases}}
+ static auto lateSpecifiedFunc() -> decltype(NameFromBase()) {
+ return {};
+ }
+
+ // FIXME: MSVC accepts all of the code below that isn't C++14 only. Downgrade
+ // these errors to warnings.
+
+ static void memberFunc() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ }
+
+ static void funcLocalClass() {
+ struct X {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ } y;
+ }
+
+ void localClassMethod() {
+ struct X {
+ void bar() {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+ }
+ } x;
+ x.bar();
+ }
+
+ static void funcLambda() {
+ auto l = []() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ };
+ l();
+ }
+
+ static constexpr int constexprFunc() {
+ NameFromBase x = {}; // expected-error {{unknown type name 'NameFromBase'}}
+ // FIXME: Suppress this diagnostic, we have an initializer.
+ // expected-error@-2 {{variables defined in a constexpr function must be initialized}}
+ return sizeof(x);
+ }
+
+ static auto autoFunc() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ return x;
+ }
+};
+
+// Force us to parse the methods.
+template struct B<int>;
+}
+
+namespace function_template_deduction {
+// Overloaded function templates.
+template <int N> int f() { return N; }
+template <typename T> int f() { return sizeof(T); }
+
+// Dependent base class with type.
+template <typename T>
+struct A { typedef T NameFromBase; };
+template <typename T>
+struct B : A<T> {
+ // expected-warning@+1 {{found via unqualified lookup into dependent bases}}
+ 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}}
+ int x = f<NameFromBase>();
+};
+}