summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/IdentifierResolver.h7
-rw-r--r--include/clang/Sema/Sema.h7
-rw-r--r--lib/Sema/IdentifierResolver.cpp8
-rw-r--r--lib/Sema/SemaDecl.cpp29
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp21
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp63
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp65
7 files changed, 186 insertions, 14 deletions
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 7e9d338293..770f146e6a 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -146,8 +146,13 @@ public:
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
+ ///
+ /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+ /// whether the declaration is in scope for the purposes of explicit template
+ /// instantiation or specialization. The default is false.
bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context,
- Scope *S = 0) const;
+ Scope *S = 0,
+ bool ExplicitInstantiationOrSpecialization = false) const;
/// AddDecl - Link the decl to its shadowed decl chain.
void AddDecl(NamedDecl *D);
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index d5444257a6..70ec778289 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1058,7 +1058,12 @@ public:
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
- bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0);
+ ///
+ /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+ /// whether the declaration is in scope for the purposes of explicit template
+ /// instantiation or specialization. The default is false.
+ bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0,
+ bool ExplicitInstantiationOrSpecialization = false);
/// Finds the scope corresponding to the given decl context, if it
/// happens to be an enclosing scope. Otherwise return NULL.
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 3f16ed7723..10856225ad 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -104,7 +104,8 @@ IdentifierResolver::~IdentifierResolver() {
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
- ASTContext &Context, Scope *S) const {
+ ASTContext &Context, Scope *S,
+ bool ExplicitInstantiationOrSpecialization) const {
Ctx = Ctx->getRedeclContext();
if (Ctx->isFunctionOrMethod()) {
@@ -135,7 +136,10 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
return false;
}
- return D->getDeclContext()->getRedeclContext()->Equals(Ctx);
+ DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
+ return ExplicitInstantiationOrSpecialization
+ ? Ctx->InEnclosingNamespaceSetOf(DCtx)
+ : Ctx->Equals(DCtx);
}
/// AddDecl - Link the decl to its shadowed decl chain.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 20e9be023a..0e114eaa86 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -496,8 +496,10 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
IdResolver.AddDecl(D);
}
-bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
- return IdResolver.isDeclInScope(D, Ctx, Context, S);
+bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
+ bool ExplicitInstantiationOrSpecialization) {
+ return IdResolver.isDeclInScope(D, Ctx, Context, S,
+ ExplicitInstantiationOrSpecialization);
}
Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
@@ -519,12 +521,13 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// as determined by isDeclInScope.
static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage) {
+ bool ConsiderLinkage,
+ bool ExplicitInstantiationOrSpecialization) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (SemaRef.isDeclInScope(D, Ctx, S))
+ if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
continue;
if (ConsiderLinkage &&
@@ -2886,7 +2889,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false);
+ FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+ /*ExplicitInstantiationOrSpecialization=*/false);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypeDefDecl(NewTD, Previous);
@@ -3167,7 +3171,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+ isExplicitSpecialization);
if (!getLangOptions().CPlusPlus)
CheckVariableDeclaration(NewVD, Previous, Redeclaration);
@@ -3624,7 +3629,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Set the lexical context.
NewFD->setLexicalDeclContext(CurContext);
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ /*ExplicitInstantiationOrSpecialization=*/false);
} else {
isFriend = D.getDeclSpec().isFriendSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -3884,7 +3890,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ isExplicitSpecialization ||
+ isFunctionTemplateSpecialization);
if (isFriend) {
// For now, claim that the objects have no previous declaration.
@@ -6268,7 +6276,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S)) {
+ isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
@@ -6412,7 +6420,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Invalid = true;
// Otherwise, only diagnose if the declaration is in scope.
- } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S,
+ isExplicitSpecialization)) {
// do nothing
// Diagnose implicit declarations introduced by elaborated types.
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
index b9ad6e1c06..7c4a21c35a 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
@@ -95,3 +95,24 @@ namespace redecl { inline namespace n1 {
};
} }
+
+// Normal redeclarations (not for explicit instantiations or
+// specializations) are distinct in an inline namespace vs. not in an
+// inline namespace.
+namespace redecl2 {
+ inline namespace n1 {
+ void f(int) { }
+ struct X1 { };
+ template<typename T> void f(T) { }
+ template<typename T> struct X2 { };
+ int i = 71;
+ enum E { e };
+ }
+
+ void f(int) { }
+ struct X1 { };
+ template<typename T> void f(T) { }
+ template<typename T> struct X2 { };
+ int i = 71;
+ enum E { e };
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
index ed600e4ad9..4a17ceca7c 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
@@ -237,3 +237,66 @@ void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
xvp.ft1(vp, i);
xvp.ft1(vp, u);
}
+
+namespace has_inline_namespaces {
+ inline namespace inner {
+ template<class T> void f(T&);
+
+ template<class T>
+ struct X0 {
+ struct MemberClass;
+
+ void mem_func();
+
+ template<typename U>
+ struct MemberClassTemplate;
+
+ template<typename U>
+ void mem_func_template(U&);
+
+ static int value;
+ };
+ }
+
+ struct X1;
+ struct X2;
+
+ // An explicit specialization whose declarator-id is not qualified
+ // shall be declared in the nearest enclosing namespace of the
+ // template, or, if the namespace is inline (7.3.1), any namespace
+ // from its enclosing namespace set.
+ template<> void f(X1&);
+ template<> void f<X2>(X2&);
+
+ template<> struct X0<X1> { };
+
+ template<> struct X0<X2>::MemberClass { };
+
+ template<> void X0<X2>::mem_func();
+
+ template<> template<typename T> struct X0<X2>::MemberClassTemplate { };
+
+ template<> template<typename T> void X0<X2>::mem_func_template(T&) { }
+
+ template<> int X0<X2>::value = 12;
+}
+
+struct X3;
+struct X4;
+
+template<> void has_inline_namespaces::f(X3&);
+template<> void has_inline_namespaces::f<X4>(X4&);
+
+template<> struct has_inline_namespaces::X0<X3> { };
+
+template<> struct has_inline_namespaces::X0<X4>::MemberClass { };
+
+template<> void has_inline_namespaces::X0<X4>::mem_func();
+
+template<> template<typename T>
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate { };
+
+template<> template<typename T>
+void has_inline_namespaces::X0<X4>::mem_func_template(T&) { }
+
+template<> int has_inline_namespaces::X0<X4>::value = 13;
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
new file mode 100644
index 0000000000..fdb922abcf
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++0x -verify %s
+
+// If the name declared in the explicit instantiation is an
+// unqualified name, the explicit instantiation shall appear in the
+// namespace where its template is declared or, if that namespace is
+// inline (7.3.1), any namespace from its enclosing namespace set.
+
+namespace has_inline_namespaces {
+ inline namespace inner {
+ template<class T> void f(T&) {}
+
+ template<class T>
+ struct X0 {
+ struct MemberClass {};
+
+ void mem_func() {}
+
+ template<typename U>
+ struct MemberClassTemplate {};
+
+ template<typename U>
+ void mem_func_template(U&) {}
+
+ static int value;
+ };
+ }
+
+ template<typename T> int X0<T>::value = 17;
+
+ struct X1 {};
+ struct X2 {};
+
+ template void f(X1&);
+ template void f<X2>(X2&);
+
+ template struct X0<X1>;
+
+ template struct X0<X2>::MemberClass;
+
+ template void X0<X2>::mem_func();
+
+ template struct X0<X2>::MemberClassTemplate<X1>;
+
+ template void X0<X2>::mem_func_template(X1&);
+
+ template int X0<X2>::value;
+}
+
+struct X3;
+struct X4;
+
+template void has_inline_namespaces::f(X3&);
+template void has_inline_namespaces::f<X4>(X4&);
+
+template struct has_inline_namespaces::X0<X3>;
+
+template struct has_inline_namespaces::X0<X4>::MemberClass;
+
+template void has_inline_namespaces::X0<X4>::mem_func();
+
+template
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate<X3>;
+
+template
+void has_inline_namespaces::X0<X4>::mem_func_template(X3&);