if (R.empty()) {
// In Microsoft mode, if we are inside a template class member function
// whose parent class has dependent base classes, and we can't resolve
- // an identifier, then assume the identifier is a member of a dependent
- // base class. The goal is to postpone name lookup to instantiation time
- // to be able to search into the type dependent base classes.
+ // an unqualified identifier, then assume the identifier is a member of a
+ // dependent base class. The goal is to postpone name lookup to
+ // instantiation time to be able to search into the type dependent base
+ // classes.
// FIXME: If we want 100% compatibility with MSVC, we will have delay all
// unqualified name lookup. Any name lookup during template parsing means
// clang might find something that MSVC doesn't. For now, we only handle
// the common case of members of a dependent base class.
- if (getLangOpts().MSVCCompat) {
+ if (SS.isEmpty() && getLangOpts().MSVCCompat) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) {
- assert(SS.isEmpty() && "qualifiers should be already handled");
QualType ThisType = MD->getThisType(Context);
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
template struct D<A>;
}
+
+namespace PR19233 {
+template <class T>
+struct A : T {
+ void foo() {
+ ::undef(); // expected-error {{no member named 'undef' in the global namespace}}
+ }
+ void bar() {
+ ::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}}
+ }
+ void baz() {
+ B::qux(); // expected-error {{use of undeclared identifier 'B'}}
+ }
+};
+
+struct B { void qux(); };
+struct C : B { };
+template struct A<C>; // No error! B is a base of A<C>, and qux is available.
+
+struct D { };
+template struct A<D>; // expected-note {{in instantiation of member function 'PR19233::A<PR19233::D>::baz' requested here}}
+
+}