From cab7dad9eb1d986874a8224b6167f413aec55b14 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Fri, 13 Sep 2013 09:03:14 +0000 Subject: [PATCH] [-cxx-abi microsoft] Mangle declarations inside extern "C" Summary: This is a first step to getting extern "C" working properly inside clang. There are a number of quirks but mangling declarations inside such a function are a good first step. Reviewers: timurrrr, pcc, cdavis5x CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1655 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190671 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/MicrosoftMangle.cpp | 109 ++++++++++++++++++++++++---------- test/CodeGenCXX/mangle-ms.cpp | 10 ++++ 2 files changed, 86 insertions(+), 33 deletions(-) diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index b60aad1371..e082759cb9 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -29,6 +29,40 @@ using namespace clang; namespace { +/// \brief Retrieve the declaration context that should be used when mangling +/// the given declaration. +static const DeclContext *getEffectiveDeclContext(const Decl *D) { + // The ABI assumes that lambda closure types that occur within + // default arguments live in the context of the function. However, due to + // the way in which Clang parses and creates function declarations, this is + // not the case: the lambda closure type ends up living in the context + // where the function itself resides, because the function declaration itself + // had not yet been created. Fix the context here. + if (const CXXRecordDecl *RD = dyn_cast(D)) { + if (RD->isLambda()) + if (ParmVarDecl *ContextParam = + dyn_cast_or_null(RD->getLambdaContextDecl())) + return ContextParam->getDeclContext(); + } + + // Perform the same check for block literals. + if (const BlockDecl *BD = dyn_cast(D)) { + if (ParmVarDecl *ContextParam = + dyn_cast_or_null(BD->getBlockManglingContextDecl())) + return ContextParam->getDeclContext(); + } + + const DeclContext *DC = D->getDeclContext(); + if (const CapturedDecl *CD = dyn_cast(DC)) + return getEffectiveDeclContext(CD); + + return DC; +} + +static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { + return getEffectiveDeclContext(cast(DC)); +} + static const FunctionDecl *getStructor(const FunctionDecl *fn) { if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) return ftd->getTemplatedDecl(); @@ -180,17 +214,6 @@ private: } -static bool isInCLinkageSpecification(const Decl *D) { - D = D->getCanonicalDecl(); - for (const DeclContext *DC = D->getDeclContext(); - !DC->isTranslationUnit(); DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) - return Linkage->getLanguage() == LinkageSpecDecl::lang_c; - } - - return false; -} - bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { // In C, functions with no attributes never need to be mangled. Fastpath them. if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) @@ -201,28 +224,46 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (D->hasAttr()) return true; - // Clang's "overloadable" attribute extension to C/C++ implies name mangling - // (always) as does passing a C++ member function and a function - // whose name is not a simple identifier. - const FunctionDecl *FD = dyn_cast(D); - if (FD && (FD->hasAttr() || isa(FD) || - !FD->getDeclName().isIdentifier())) - return true; + if (const FunctionDecl *FD = dyn_cast(D)) { + LanguageLinkage L = FD->getLanguageLinkage(); + // Overloadable functions need mangling. + if (FD->hasAttr()) + return true; + + // "main" is not mangled. + if (FD->isMain()) + return false; + + // C++ functions and those whose names are not a simple identifier need + // mangling. + if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage) + return true; + + // C functions are not mangled. + if (L == CLanguageLinkage) + return false; + } // Otherwise, no mangling is done outside C++ mode. if (!getASTContext().getLangOpts().CPlusPlus) return false; - // Variables at global scope with internal linkage are not mangled. - if (!FD) { - const DeclContext *DC = D->getDeclContext(); - if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage) + if (const VarDecl *VD = dyn_cast(D)) { + // C variables are not mangled. + if (VD->isExternC()) return false; - } - // C functions and "main" are not mangled. - if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) - return false; + // Variables at global scope with non-internal linkage are not mangled. + const DeclContext *DC = getEffectiveDeclContext(D); + // Check for extern variable declared locally. + if (DC->isFunctionOrMethod() && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = getEffectiveParentContext(DC); + + if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage && + !isa(D)) + return false; + } return true; } @@ -269,10 +310,6 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // first, since it is most likely to be the declaration in a header file. FD = FD->getFirstDeclaration(); - // Don't mangle in the type if this isn't a decl we should typically mangle. - if (!Context.shouldMangleDeclName(FD)) - return; - // We should never ever see a FunctionNoProtoType at this point. // We don't even know how to mangle their types anyway :). TypeSourceInfo *TSI = FD->getTypeSourceInfo(); @@ -288,10 +325,16 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { InStructor = true; } - // First, the function class. - mangleFunctionClass(FD); + // extern "C" functions can hold entities that must be mangled. + // As it stands, these functions still need to get expressed in the full + // external name. They have their class and type omitted, replaced with '9'. + if (Context.shouldMangleDeclName(FD)) { + // First, the function class. + mangleFunctionClass(FD); - mangleFunctionType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD, InStructor, InInstMethod); + } else + Out << '9'; } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index c820b7a254..e7450d8fb0 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -245,3 +245,13 @@ namespace PR13182 { return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0]; } } + +extern "C" inline void extern_c_func() { + static int local; +// CHECK-DAG: @"\01?local@?1??extern_c_func@@9@4HA" +// X64-DAG: @"\01?local@?1??extern_c_func@@9@4HA" +} + +void call_extern_c_func() { + extern_c_func(); +} -- 2.40.0