Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -722,9 +722,25 @@ def AsmLabel : InheritableAttr { let Spellings = [Keyword<"asm">, Keyword<"__asm__">]; - let Args = [StringArgument<"Label">]; + let Args = [ + // Label specifies the mangled name for the decl. + StringArgument<"Label">, + + // LiteralLabel specifies whether Label is literal, i.e. spelled + // exactly as it must be in the final mangle, or not, in which case + // it may be subject to global prefixing. + // + // TODO: Make it possible to specify this in source. + BoolArgument<"LiteralLabel"> + ]; let SemaHandler = 0; - let Documentation = [Undocumented]; + let Documentation = [AsmLabelDocs]; + let AdditionalMembers = +[{ +bool equivalent(AsmLabelAttr *Other) const { + return getLabel() == Other->getLabel() && getLiteralLabel() == Other->getLiteralLabel(); +} +}]; } def Availability : InheritableAttr { Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -2558,6 +2558,26 @@ }]; } +def AsmLabelDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +This attribute can be added to a function or variable to specify its mangled name. + +For example (assuming, for convenience, that a "_" is usually prepended to C symbol names for the target): + +.. code-block:: c + + int var1 asm("altvar") = 1; // "altvar" in symbol table. + int var2 = 1; // "_var2" in symbol table. + + void func1(void) asm("altfunc"); + void func1(void) {} // "altfunc" in symbol table. + void func2(void) {} // "_func2" in symbol table. + +Clang's implementation of this attribute is compatible with GCC's, `documented here `_. + }]; +} + def EnumExtensibilityDocs : Documentation { let Category = DocCatDecl; let Content = [{ Index: clang/lib/AST/Mangle.cpp =================================================================== --- clang/lib/AST/Mangle.cpp +++ clang/lib/AST/Mangle.cpp @@ -122,15 +122,21 @@ if (const AsmLabelAttr *ALA = D->getAttr()) { // If we have an asm name, then we use it as the mangling. + // If the label is literal, or if this is an alias for an LLVM intrinsic, + // the global prefix must not be prepended. + if (ALA->getLiteralLabel() || ALA->getLabel().startswith("llvm.")) { + Out << ALA->getLabel(); + return; + } + // Adding the prefix can cause problems when one file has a "foo" and // another has a "\01foo". That is known to happen on ELF with the // tricks normally used for producing aliases (PR9177). Fortunately the // llvm mangler on ELF is a nop, so we can just avoid adding the \01 - // marker. We also avoid adding the marker if this is an alias for an - // LLVM intrinsic. + // marker. char GlobalPrefix = getASTContext().getTargetInfo().getDataLayout().getGlobalPrefix(); - if (GlobalPrefix && !ALA->getLabel().startswith("llvm.")) + if (GlobalPrefix) Out << '\01'; // LLVM IR Marker for __asm("foo") Out << ALA->getLabel(); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -2766,7 +2766,7 @@ if (AsmLabelAttr *NewA = New->getAttr()) { if (AsmLabelAttr *OldA = Old->getAttr()) { - if (OldA->getLabel() != NewA->getLabel()) { + if (!OldA->equivalent(NewA)) { // This redeclaration changes __asm__ label. Diag(New->getLocation(), diag::err_different_asm_label); Diag(OldA->getLocation(), diag::note_previous_declaration); @@ -6983,8 +6983,8 @@ } } - NewVD->addAttr(::new (Context) - AsmLabelAttr(Context, SE->getStrTokenLoc(0), Label)); + NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getStrTokenLoc(0), + Label, /*LiteralLabel=*/false)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); @@ -8882,8 +8882,9 @@ if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); - NewFD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getStrTokenLoc(0), - SE->getString())); + NewFD->addAttr(::new (Context) + AsmLabelAttr(Context, SE->getStrTokenLoc(0), + SE->getString(), /*LiteralLabel=*/false)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); @@ -17555,8 +17556,8 @@ LookupOrdinaryName); AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc), AttributeCommonInfo::AS_Pragma); - AsmLabelAttr *Attr = - AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), Info); + AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit( + Context, AliasName->getName(), /*LiteralLabel=*/false, Info); // If a declaration that: // 1) declares a function or a variable Index: clang/unittests/AST/DeclTest.cpp =================================================================== --- clang/unittests/AST/DeclTest.cpp +++ clang/unittests/AST/DeclTest.cpp @@ -10,12 +10,16 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" +#include "clang/AST/Mangle.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/LLVM.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" using namespace clang::ast_matchers; using namespace clang::tooling; +using namespace clang; TEST(Decl, CleansUpAPValues) { MatchFinder Finder; @@ -56,3 +60,49 @@ "constexpr _Complex __uint128_t c = 0xffffffffffffffff;", Args)); } + +TEST(Decl, AsmLabelAttr) { + // Create two method decls: `f` and `g`. + StringRef Code = R"( + struct S { + void f() {} + void g() {} + }; + )"; + auto AST = + tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"}); + ASTContext &Ctx = AST->getASTContext(); + DiagnosticsEngine &Diags = AST->getDiagnostics(); + SourceManager &SM = AST->getSourceManager(); + FileID MainFileID = SM.getMainFileID(); + + // Find the method decls within the AST. + SmallVector Decls; + AST->findFileRegionDecls(MainFileID, Code.find('{'), 0, Decls); + ASSERT_TRUE(Decls.size() == 1); + CXXRecordDecl *DeclS = cast(Decls[0]); + NamedDecl *DeclF = *DeclS->method_begin(); + NamedDecl *DeclG = *(++DeclS->method_begin()); + + // Attach asm labels to the decls: one literal, and one subject to global + // prefixing. + DeclF->addAttr(::new (Ctx) AsmLabelAttr(Ctx, SourceLocation(), "foo", + /*LiteralLabel=*/true)); + DeclG->addAttr(::new (Ctx) AsmLabelAttr(Ctx, SourceLocation(), "goo", + /*LiteralLabel=*/false)); + + // Mangle the decl names. + std::string MangleF, MangleG; + MangleContext *MC = ItaniumMangleContext::create(Ctx, Diags); + { + llvm::raw_string_ostream OS(MangleF); + MC->mangleName(DeclF, OS); + } + { + llvm::raw_string_ostream OS(MangleG); + MC->mangleName(DeclG, OS); + } + + ASSERT_TRUE(0 == MangleF.compare("foo")); + ASSERT_TRUE(0 == MangleG.compare("\x01goo")); +} Index: lldb/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/source/Symbol/ClangASTContext.cpp +++ lldb/source/Symbol/ClangASTContext.cpp @@ -8300,8 +8300,8 @@ cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(*getASTContext())); if (mangled_name != nullptr) { - cxx_method_decl->addAttr( - clang::AsmLabelAttr::CreateImplicit(*getASTContext(), mangled_name)); + cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( + *getASTContext(), mangled_name, /*literal=*/true)); } // Populate the method decl with parameter decls