aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/NestedNameSpecifier.h8
-rw-r--r--lib/AST/NestedNameSpecifier.cpp12
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp6
-rw-r--r--test/SemaTemplate/member-access-expr.cpp48
4 files changed, 72 insertions, 2 deletions
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 0c31dbbf1a..5c76064ae1 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -113,6 +113,14 @@ public:
NestedNameSpecifier *Prefix,
bool Template, Type *T);
+ /// \brief Builds a specifier that consists of just an identifier.
+ ///
+ /// The nested-name-specifier is assumed to be dependent, but has no
+ /// prefix because the prefix is implied by something outside of the
+ /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
+ /// type.
+ static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II);
+
/// \brief Returns the nested name specifier representing the global
/// scope.
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 0376f9db6b..0c24c89b29 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -75,7 +75,17 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
Mockup.Specifier = T;
return FindOrInsert(Context, Mockup);
}
-
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) {
+ assert(II && "Identifier cannot be NULL");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(0);
+ Mockup.Prefix.setInt(Identifier);
+ Mockup.Specifier = II;
+ return FindOrInsert(Context, Mockup);
+}
+
NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
if (!Context.GlobalNestedNameSpecifier)
Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 251ffea925..352e553edb 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -357,7 +357,8 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// unqualified name lookup in the given scope.
// FIXME: When we're instantiating a template, do we actually have to
- // look in the scope of the template? Seems fishy...
+ // look in the scope of the template? Both EDG and GCC do it; GCC
+ // requires the lookup to be successful, EDG doesn't.
Found = LookupName(S, &II, LookupNestedNameSpecifierName);
ObjectTypeSearchedInScope = true;
}
@@ -366,6 +367,9 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// base object type or prior nested-name-specifier, so this
// nested-name-specifier refers to an unknown specialization. Just build
// a dependent nested-name-specifier.
+ if (!Prefix)
+ return NestedNameSpecifier::Create(Context, &II);
+
return NestedNameSpecifier::Create(Context, Prefix, &II);
} else {
// Perform unqualified name lookup in the current scope.
diff --git a/test/SemaTemplate/member-access-expr.cpp b/test/SemaTemplate/member-access-expr.cpp
new file mode 100644
index 0000000000..f41dc2120a
--- /dev/null
+++ b/test/SemaTemplate/member-access-expr.cpp
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// XFAIL
+template<typename T>
+void call_f0(T x) {
+ x.Base::f0();
+}
+
+struct Base {
+ void f0();
+};
+
+struct X0 : Base {
+ typedef Base CrazyBase;
+};
+
+void test_f0(X0 x0) {
+ call_f0(x0);
+}
+
+template<typename TheBase, typename T>
+void call_f0_through_typedef(T x) {
+ typedef TheBase Base2;
+ x.Base2::f0();
+}
+
+void test_f0_through_typedef(X0 x0) {
+ call_f0_through_typedef<Base>(x0);
+}
+
+template<typename TheBase, typename T>
+void call_f0_through_typedef2(T x) {
+ typedef TheBase CrazyBase; // expected-note{{current scope}}
+ x.CrazyBase::f0(); // expected-error{{ambiguous}}
+}
+
+struct OtherBase { };
+
+struct X1 : Base, OtherBase {
+ typedef OtherBase CrazyBase; // expected-note{{object type}}
+};
+
+void test_f0_through_typedef2(X0 x0, X1 x1) {
+ call_f0_through_typedef2<Base>(x0);
+ call_f0_through_typedef2<OtherBase>(x1);
+ call_f0_through_typedef2<Base>(x1); // expected-note{{here}}
+}
+
+