diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index df85dfe8eb..8fdf779acd 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -300,7 +300,9 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + /// \returns true if an error occurred, false otherwise. + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + return false; } /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index b9b17d24d1..e11ca0ce6b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1123,7 +1123,9 @@ private: void EnterDeclaratorScope() { assert(!EnteredScope && "Already entered the scope!"); assert(SS.isSet() && "C++ scope was not set!"); - P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS); + if (P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS)) + SS.setScopeRep(0); + if (!SS.isInvalid()) EnteredScope = true; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 18b56c5bfb..0bb72568b1 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2151,7 +2151,7 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 60661f147e..8f536da777 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -519,10 +519,18 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. -void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { +bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - if (DeclContext *DC = computeDeclContext(SS, true)) + if (DeclContext *DC = computeDeclContext(SS, true)) { + // Before we enter a declarator's context, we need to make sure that + // it is a complete declaration context. + if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) + return true; + EnterDeclaratorContext(S, DC); + } + + return false; } /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp new file mode 100644 index 0000000000..197dae5a15 --- /dev/null +++ b/test/SemaTemplate/explicit-specialization-member.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template +struct X0 { + typedef T* type; + + void f0(T); + void f1(type); +}; + +template<> void X0::f0(char); +template<> void X0::f1(type);