diff options
-rw-r--r-- | include/clang/AST/NestedNameSpecifier.h | 8 | ||||
-rw-r--r-- | lib/AST/NestedNameSpecifier.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 6 | ||||
-rw-r--r-- | test/SemaTemplate/member-access-expr.cpp | 48 |
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}} +} + + |