/// NamespaceDecl - Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext {
+ bool IsInline : 1;
+
SourceLocation LBracLoc, RBracLoc;
// For extended namespace definitions:
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
- NextNamespace(0), OrigOrAnonNamespace(0, true) { }
+ IsInline(false), NextNamespace(0), OrigOrAnonNamespace(0, true) { }
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id);
- // \brief Returns true if this is an anonymous namespace declaration.
- //
- // For example:
+ /// \brief Returns true if this is an anonymous namespace declaration.
+ ///
+ /// For example:
/// \code
- // namespace {
- // ...
- // };
- // \endcode
- // q.v. C++ [namespace.unnamed]
+ /// namespace {
+ /// ...
+ /// };
+ /// \endcode
+ /// q.v. C++ [namespace.unnamed]
bool isAnonymousNamespace() const {
return !getIdentifier();
}
- /// \brief Returns true if this is a C++0x inline namespace.
+ /// \brief Returns true if this is an inline namespace declaration.
bool isInline() const {
- return false;
+ return IsInline;
+ }
+
+ /// \brief Set whether this is an inline namespace declaration.
+ void setInline(bool Inline) {
+ IsInline = Inline;
}
/// \brief Return the next extended namespace declaration or null if there
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
+def err_inline_namespace_mismatch : Error<
+ "%select{|non-}0inline namespace "
+ "cannot be reopened as %select{non-|}0inline">;
+
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def ext_enum_friend : ExtWarn<
else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord)
return cast<RecordDecl>(this)->isAnonymousStructOrUnion();
else if (DeclKind == Decl::Namespace)
- return false; // FIXME: Check for C++0x inline namespaces
+ return cast<NamespaceDecl>(this)->isInline();
return false;
}
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext,
(II ? IdentLoc : LBrace) , II);
Namespc->setLBracLoc(LBrace);
+ Namespc->setInline(InlineLoc.isValid());
Scope *DeclRegionScope = NamespcScope->getParent();
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
// This is an extended namespace definition.
+ if (Namespc->isInline() != OrigNS->isInline()) {
+ // inline-ness must match
+ Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
+ << Namespc->isInline();
+ Diag(OrigNS->getLocation(), diag::note_previous_definition);
+ Namespc->setInvalidDecl();
+ // Recover by ignoring the new namespace's inline status.
+ Namespc->setInline(OrigNS->isInline());
+ }
+
// Attach this namespace decl to the chain of extended namespace
// definitions.
OrigNS->setNextNamespace(Namespc);
assert(!PrevDecl->getNextNamespace());
Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
PrevDecl->setNextNamespace(Namespc);
+
+ if (Namespc->isInline() != PrevDecl->isInline()) {
+ // inline-ness must match
+ Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
+ << Namespc->isInline();
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ Namespc->setInvalidDecl();
+ // Recover by ignoring the new namespace's inline status.
+ Namespc->setInline(PrevDecl->isInline());
+ }
}
CurContext->addDecl(Namespc);
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+namespace NIL {} // expected-note {{previous definition}}
+inline namespace NIL {} // expected-error {{cannot be reopened as inline}}
+inline namespace IL {} // expected-note {{previous definition}}
+namespace IL {} // expected-error {{cannot be reopened as non-inline}}
+
+namespace {} // expected-note {{previous definition}}
+inline namespace {} // expected-error {{cannot be reopened as inline}}
+namespace X {
+ inline namespace {} // expected-note {{previous definition}}
+ namespace {} // expected-error {{cannot be reopened as non-inline}}
+}