/// 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);
/// 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.
AssociatedClassSet &AssociatedClasses);
void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization);
+ bool ConsiderLinkage, bool AllowInlineNamespace);
void DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
/// 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()) {
}
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.
}
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) {
/// 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();
}
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;
}
// 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.
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
+ D.getCXXScopeSpec().isNotEmpty() ||
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
// 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,
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.
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) {
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}}
+}