From: John McCall Date: Thu, 1 Oct 2009 00:25:31 +0000 (+0000) Subject: Anonymous namespaces, sema + codegen. A lot of semantics are still broken, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9aeed32282fe8a775c24c01c923717ca86695685;p=clang Anonymous namespaces, sema + codegen. A lot of semantics are still broken, apparently because using directives aren't quite working correctly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83184 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 4474719f36..e77c5e41fb 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -192,6 +192,17 @@ public: virtual void Destroy(ASTContext& C); + // \brief Returns true if this is an anonymous namespace declaration. + // + // For example: + // namespace { + // ... + // }; + // q.v. C++ [namespace.unnamed] + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + NamespaceDecl *getNextNamespace() { return NextNamespace; } const NamespaceDecl *getNextNamespace() const { return NextNamespace; } void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index f05574fcce..9e88871565 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -224,6 +224,8 @@ public: return const_cast(this)->getTranslationUnitDecl(); } + bool isInAnonymousNamespace() const; + ASTContext &getASTContext() const; void setAccess(AccessSpecifier AS) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 5f639d807d..224bf877ad 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -157,6 +157,17 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { } } +bool Decl::isInAnonymousNamespace() const { + const DeclContext *DC = getDeclContext(); + do { + if (const NamespaceDecl *ND = dyn_cast(DC)) + if (ND->isAnonymousNamespace()) + return true; + } while ((DC = DC->getParent())); + + return false; +} + TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast(this)) return TUD; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index bc8cc2652d..f93c6048a7 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -247,6 +247,11 @@ void CodeGenModule::EmitAnnotations() { static CodeGenModule::GVALinkage GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, const LangOptions &Features) { + // Everything located semantically within an anonymous namespace is + // always internal. + if (FD->isInAnonymousNamespace()) + return CodeGenModule::GVA_Internal; + // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; @@ -1000,7 +1005,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setAlignment(getContext().getDeclAlignInBytes(D)); // Set the llvm linkage type as appropriate. - if (D->getStorageClass() == VarDecl::Static) + if (D->isInAnonymousNamespace()) + GV->setLinkage(llvm::Function::InternalLinkage); + else if (D->getStorageClass() == VarDecl::Static) GV->setLinkage(llvm::Function::InternalLinkage); else if (D->hasAttr()) GV->setLinkage(llvm::Function::DLLImportLinkage); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 61555ad19d..7555ae5da4 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -254,7 +254,8 @@ static bool isStdNamespace(const DeclContext *DC) { return false; const NamespaceDecl *NS = cast(DC); - return NS->getOriginalNamespace()->getIdentifier()->isStr("std"); + const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); + return II && II->isStr("std"); } static const TemplateDecl * @@ -403,6 +404,14 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { DeclarationName Name = ND->getDeclName(); switch (Name.getNameKind()) { case DeclarationName::Identifier: + if (const NamespaceDecl *NS = dyn_cast(ND)) + if (NS->isAnonymousNamespace()) { + // This is how gcc mangles these names. It's apparently + // always '1', no matter how many different anonymous + // namespaces appear in a context. + Out << "12_GLOBAL__N_1"; + break; + } mangleSourceName(Name.getAsIdentifierInfo()); break; @@ -1204,8 +1213,7 @@ static bool isCharSpecialization(QualType T, const char *Name) { bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // ::= St # ::std:: if (const NamespaceDecl *NS = dyn_cast(ND)) { - if (NS->getParent()->isTranslationUnit() && - NS->getOriginalNamespace()->getIdentifier()->isStr("std")) { + if (isStdNamespace(NS)) { Out << "St"; return true; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1966aebca2..23a6b58a9c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2397,7 +2397,38 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PushOnScopeChains(Namespc, DeclRegionScope); } else { - // FIXME: Handle anonymous namespaces + // Anonymous namespaces. + + // C++ [namespace.unnamed]p1. An unnamed-namespace-definition + // behaves as if it were replaced by + // namespace unique { /* empty body */ } + // using namespace unique; + // namespace unique { namespace-body } + // where all occurrences of 'unique' in a translation unit are + // replaced by the same identifier and this identifier differs + // from all other identifiers in the entire program. + + // We just create the namespace with an empty name and then add an + // implicit using declaration, just like the standard suggests. + // + // CodeGen enforces the "universally unique" aspect by giving all + // declarations semantically contained within an anonymous + // namespace internal linkage. + + assert(Namespc->isAnonymousNamespace()); + CurContext->addDecl(Namespc); + + UsingDirectiveDecl* UD + = UsingDirectiveDecl::Create(Context, CurContext, + /* 'using' */ LBrace, + /* 'namespace' */ SourceLocation(), + /* qualifier */ SourceRange(), + /* NNS */ NULL, + /* identifier */ SourceLocation(), + Namespc, + /* Ancestor */ CurContext); + UD->setImplicit(); + CurContext->addDecl(UD); } // Although we could have an invalid decl (i.e. the namespace name is a diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp new file mode 100644 index 0000000000..dcfd518d68 --- /dev/null +++ b/test/CodeGenCXX/anonymous-namespaces.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s + +namespace { + // CHECK: @_ZN12_GLOBAL__N_11aE = internal global i32 0 + int a = 0; + + // CHECK: define internal i32 @_ZN12_GLOBAL__N_13fooEv() + int foo() { + return 32; + } + + // CHECK: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv() + namespace A { + int foo() { + return 45; + } + } +} + +int concrete() { + return a + foo() + A::foo(); +}