r196464 - Per [dcl.meaning]p1, a name in an inline namespace can be redeclared using a
Richard Smith
richard-llvm at metafoo.co.uk
Wed Dec 4 20:30:04 PST 2013
Author: rsmith
Date: Wed Dec 4 22:30:04 2013
New Revision: 196464
URL: http://llvm.org/viewvc/llvm-project?rev=196464&view=rev
Log:
Per [dcl.meaning]p1, a name in an inline namespace can be redeclared using a
name from the enclosing namespace set if the name is specified as a
qualified-id.
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/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1-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=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/IdentifierResolver.h (original)
+++ cfe/trunk/include/clang/Sema/IdentifierResolver.h Wed Dec 4 22:30:04 2013
@@ -150,11 +150,14 @@ public:
/// 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.
+ /// \param AllowInlineNamespace If \c true, we are checking whether a prior
+ /// declaration is in scope in a declaration that requires a prior
+ /// declaration (because it is either explicitly qualified or is a
+ /// template instantiation or specialization). In this case, a
+ /// declaration is in scope if it's in the inline namespace set of the
+ /// context.
bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0,
- bool ExplicitInstantiationOrSpecialization = false) const;
+ bool AllowInlineNamespace = 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=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Dec 4 22:30:04 2013
@@ -1823,11 +1823,11 @@ public:
/// 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.
+ /// \param AllowInlineNamespace If \c true, allow the declaration to be in the
+ /// enclosing namespace set of the context, rather than contained
+ /// directly within it.
bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = 0,
- bool ExplicitInstantiationOrSpecialization = false);
+ bool AllowInlineNamespace = false);
/// Finds the scope corresponding to the given decl context, if it
/// happens to be an enclosing scope. Otherwise return NULL.
@@ -2528,8 +2528,7 @@ public:
AssociatedClassSet &AssociatedClasses);
void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization);
+ bool ConsiderLinkage, bool AllowInlineNamespace);
void DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
Modified: cfe/trunk/lib/Sema/IdentifierResolver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/IdentifierResolver.cpp?rev=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/IdentifierResolver.cpp (original)
+++ cfe/trunk/lib/Sema/IdentifierResolver.cpp Wed Dec 4 22:30:04 2013
@@ -95,7 +95,7 @@ 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, Scope *S,
- bool ExplicitInstantiationOrSpecialization) const {
+ bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
@@ -131,9 +131,8 @@ bool IdentifierResolver::isDeclInScope(D
}
DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
- return ExplicitInstantiationOrSpecialization
- ? Ctx->InEnclosingNamespaceSetOf(DCtx)
- : Ctx->Equals(DCtx);
+ return AllowInlineNamespace ? 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=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Dec 4 22:30:04 2013
@@ -1086,9 +1086,8 @@ void Sema::pushExternalDeclIntoScope(Nam
}
bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S,
- bool ExplicitInstantiationOrSpecialization) {
- return IdResolver.isDeclInScope(D, Ctx, S,
- ExplicitInstantiationOrSpecialization);
+ bool AllowInlineNamespace) {
+ return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace);
}
Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
@@ -1108,21 +1107,19 @@ static bool isOutOfScopePreviousDeclarat
/// Filters out lookup results that don't fall within the given scope
/// as determined by isDeclInScope.
-void Sema::FilterLookupForScope(LookupResult &R,
- DeclContext *Ctx, Scope *S,
+void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization) {
+ bool AllowInlineNamespace) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
+ if (isDeclInScope(D, Ctx, S, AllowInlineNamespace))
continue;
- if (ConsiderLinkage &&
- isOutOfScopePreviousDeclaration(D, Ctx, Context))
+ if (ConsiderLinkage && isOutOfScopePreviousDeclaration(D, Ctx, Context))
continue;
-
+
F.erase();
}
@@ -4671,8 +4668,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, Dec
LookupResult &Previous, bool &Redeclaration) {
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
- /*ExplicitInstantiationOrSpecialization=*/false);
+ FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false,
+ /*AllowInlineNamespace*/false);
filterNonConflictingPreviousDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
@@ -5400,15 +5397,16 @@ Sema::ActOnVariableDeclarator(Scope *S,
}
// Diagnose shadowed variables before filtering for scope.
- if (!D.getCXXScopeSpec().isSet())
+ if (D.getCXXScopeSpec().isEmpty())
CheckShadow(S, NewVD, Previous);
// 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(
- Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
- IsExplicitSpecialization || IsVariableTemplateSpecialization);
+ FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
+ D.getCXXScopeSpec().isNotEmpty() ||
+ IsExplicitSpecialization ||
+ IsVariableTemplateSpecialization);
// Check whether the previous declaration is in the same block scope. This
// affects whether we merge types with it, per C++11 [dcl.array]p3.
@@ -6886,6 +6884,7 @@ Sema::ActOnFunctionDeclarator(Scope *S,
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
+ D.getCXXScopeSpec().isNotEmpty() ||
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -10683,7 +10682,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
// 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, isExplicitSpecialization)) {
+ isDeclInScope(PrevDecl, SearchDC, S,
+ SS.isNotEmpty() || isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
@@ -10844,8 +10844,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
Invalid = true;
// Otherwise, only diagnose if the declaration is in scope.
- } else if (!isDeclInScope(PrevDecl, SearchDC, S,
- isExplicitSpecialization)) {
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S,
+ SS.isNotEmpty() || isExplicitSpecialization)) {
// do nothing
// Diagnose implicit declarations introduced by elaborated types.
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Dec 4 22:30:04 2013
@@ -968,7 +968,8 @@ Sema::CheckClassTemplate(Scope *S, unsig
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
}
}
- } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
+ } else if (PrevDecl &&
+ !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid()))
PrevDecl = PrevClassTemplate = 0;
if (PrevClassTemplate) {
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp?rev=196464&r1=196463&r2=196464&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp Wed Dec 4 22:30:04 2013
@@ -22,3 +22,82 @@ int decltype(tfoo<T>())::i; // expected-
template<typename T>
void decltype(tfoo<T>())::func() { // expected-error{{nested name specifier 'decltype(tfoo<T>())::' for declaration does not refer into a class, class template or class template partial specialization}}
}
+
+// An init-declarator named with a qualified-id can refer to an element of the
+// inline namespace set of the named namespace.
+namespace inline_namespaces {
+ namespace N {
+ inline namespace M {
+ void f(); // expected-note {{possible target}}
+ void g();
+ extern int m, n;
+ struct S; struct T;
+ enum E : int; enum F : int;
+ template<typename T> void ft(); // expected-note {{here}}
+ template<typename T> void gt(); // expected-note {{here}}
+ template<typename T> extern int mt; // expected-note {{here}} expected-warning {{extension}}
+ template<typename T> extern int nt; // expected-note {{here}} expected-warning {{extension}}
+ template<typename T> struct U; // expected-note {{here}}
+ template<typename T> struct V; // expected-note {{here}}
+ }
+
+ // When named by unqualified-id, we do *not* look in the inline namespace
+ // set.
+ void f() {} // expected-note {{possible target}}
+ int m;
+ struct S {};
+ enum E : int {};
+
+ static_assert(&f != &M::f, ""); // expected-error {{reference to overloaded function could not be resolved}}
+ static_assert(&m != &M::m, "");
+ typedef S X; // expected-note {{previous}}
+ typedef M::S X; // expected-error {{different type}}
+ typedef E Y; // expected-note {{previous}}
+ typedef M::E Y; // expected-error {{different type}}
+
+ // When named by (unqualified) template-id, we do look in the inline
+ // namespace set. See [namespace.def]p8, [temp.explicit]p3,
+ // [temp.expl.spec]p2.
+ //
+ // This is not explicitly specified for partial specializations, but
+ // that is just a language defect.
+ template<> void ft<int>() {}
+ template void ft<char>(); // expected-error {{undefined}}
+
+ template<typename T> int mt<T*>; // expected-warning {{extension}}
+ template<> int mt<int>; // expected-warning {{extension}}
+ template int mt<int*>;
+ template int mt<char>; // expected-error {{undefined}}
+
+ template<typename T> struct U<T*> {};
+ template<> struct U<int> {};
+ template struct U<int*>;
+ template struct U<char>; // expected-error {{undefined}}
+ }
+
+ // When named by qualified-id, we *do* look in the inline namespace set.
+ void N::g() {}
+ int N::n;
+ struct N::T {};
+ enum N::F : int {};
+
+ static_assert(&N::g == &N::M::g, "");
+ static_assert(&N::n == &N::M::n, "");
+ typedef N::T X;
+ typedef N::M::T X;
+ typedef N::F Y;
+ typedef N::M::F Y;
+
+ template<> void N::gt<int>() {}
+ template void N::gt<char>(); // expected-error {{undefined}}
+
+ template<typename T> int N::nt<T*>; // expected-warning {{extension}}
+ template<> int N::nt<int>; // expected-warning {{extension}}
+ template int N::nt<int*>;
+ template int N::nt<char>; // expected-error {{undefined}}
+
+ template<typename T> struct N::V<T*> {};
+ template<> struct N::V<int> {};
+ template struct N::V<int*>;
+ template struct N::V<char>; // expected-error {{undefined}}
+}
More information about the cfe-commits
mailing list