[cfe-commits] r127162 - in /cfe/trunk: include/clang/Sema/IdentifierResolver.h include/clang/Sema/Sema.h lib/Sema/IdentifierResolver.cpp lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
Douglas Gregor
dgregor at apple.com
Mon Mar 7 08:54:27 PST 2011
Author: dgregor
Date: Mon Mar 7 10:54:27 2011
New Revision: 127162
URL: http://llvm.org/viewvc/llvm-project?rev=127162&view=rev
Log:
Support explicit template specialization and instantiation for members
of a C++0x inline namespace within enclosing namespaces, as noted in
C++0x [namespace.def]p8.
Fixes <rdar://problem/9006349>, a libc++ failure where Clang was
rejected an explicit specialization of std::swap (since libc++ puts it
into an inline, versioned namespace std::__1).
Added:
cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp (with props)
Modified:
cfe/trunk/include/clang/Sema/IdentifierResolver.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/IdentifierResolver.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
Modified: cfe/trunk/include/clang/Sema/IdentifierResolver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/IdentifierResolver.h?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/IdentifierResolver.h (original)
+++ cfe/trunk/include/clang/Sema/IdentifierResolver.h Mon Mar 7 10:54:27 2011
@@ -146,8 +146,13 @@
/// 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);
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Mar 7 10:54:27 2011
@@ -1058,7 +1058,12 @@
/// 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.
Modified: cfe/trunk/lib/Sema/IdentifierResolver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/IdentifierResolver.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/IdentifierResolver.cpp (original)
+++ cfe/trunk/lib/Sema/IdentifierResolver.cpp Mon Mar 7 10:54:27 2011
@@ -104,7 +104,8 @@
/// 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 @@
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.
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar 7 10:54:27 2011
@@ -496,8 +496,10 @@
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 @@
/// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
// 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 @@
// 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 @@
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.
Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp Mon Mar 7 10:54:27 2011
@@ -95,3 +95,24 @@
};
} }
+
+// 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 };
+}
Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp Mon Mar 7 10:54:27 2011
@@ -237,3 +237,66 @@
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;
Added: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp?rev=127162&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp Mon Mar 7 10:54:27 2011
@@ -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&);
Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list