diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-05-08 13:44:39 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-05-08 13:44:39 +0000 |
commit | e43f0fea153bd67e39f085d92d9e12ada915bb99 (patch) | |
tree | 6e125ab241ac35e231eb1aca174c107b03fd2347 | |
parent | 7bbd7aa7fe63f9df9e4d30355180cfcf0785973c (diff) | |
download | bcm5719-llvm-e43f0fea153bd67e39f085d92d9e12ada915bb99.tar.gz bcm5719-llvm-e43f0fea153bd67e39f085d92d9e12ada915bb99.zip |
Forward #pragma comment(lib/linker) through as flags metadata
Summary:
Most of this change is wiring the pragma all the way through from the
lexer, parser, and sema to codegen. I considered adding a Decl AST node
for this, but it seemed too heavyweight.
Mach-O already uses a metadata flag called "Linker Options" to do this
kind of auto-linking. This change follows that pattern.
LLVM knows how to forward the "Linker Options" metadata into the COFF
.drectve section where these flags belong. ELF support is not
implemented, but possible.
This is related to auto-linking, which is http://llvm.org/PR13016.
CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D723
llvm-svn: 181426
-rw-r--r-- | clang/include/clang/AST/ASTConsumer.h | 11 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 13 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 8 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 45 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/ModuleBuilder.cpp | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 32 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.h | 6 | ||||
-rw-r--r-- | clang/lib/Parse/ParsePragma.cpp | 23 | ||||
-rw-r--r-- | clang/lib/Parse/ParsePragma.h | 5 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAttr.cpp | 21 | ||||
-rw-r--r-- | clang/test/Modules/autolink.m | 2 |
14 files changed, 163 insertions, 27 deletions
diff --git a/clang/include/clang/AST/ASTConsumer.h b/clang/include/clang/AST/ASTConsumer.h index ae779436a9d..33e9bd92a47 100644 --- a/clang/include/clang/AST/ASTConsumer.h +++ b/clang/include/clang/AST/ASTConsumer.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_AST_ASTCONSUMER_H #define LLVM_CLANG_AST_ASTCONSUMER_H +#include "llvm/ADT/StringRef.h" + namespace clang { class ASTContext; class CXXRecordDecl; @@ -86,6 +88,15 @@ public: /// The default implementation passes it to HandleTopLevelDecl. virtual void HandleImplicitImportDecl(ImportDecl *D); + /// \brief Handle a pragma that appends to Linker Options. Currently this + /// only exists to support Microsoft's #pragma comment(linker, "/foo"). + virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {} + + /// \brief Handle a dependent library created by a pragma in the source. + /// Currently this only exists to support Microsoft's + /// #pragma comment(lib, "/foo"). + virtual void HandleDependentLibrary(llvm::StringRef Lib) {} + /// CompleteTentativeDefinition - Callback invoked at the end of a translation /// unit to notify the consumer that the given tentative definition should be /// completed. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 1029a90c55c..72acacf5ae6 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -419,6 +419,10 @@ private: void HandlePragmaMSStruct(); /// \brief Handle the annotation token produced for + /// #pragma comment... + void HandlePragmaMSComment(); + + /// \brief Handle the annotation token produced for /// #pragma align... void HandlePragmaAlign(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d7c80f2e4f9..f75ac93a908 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -49,6 +49,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include <deque> #include <string> +#include <vector> namespace llvm { class APSInt; @@ -6584,6 +6585,15 @@ public: PMSST_ON // #pragms ms_struct on }; + enum PragmaMSCommentKind { + PCK_Unknown, + PCK_Linker, // #pragma comment(linker, ...) + PCK_Lib, // #pragma comment(lib, ...) + PCK_Compiler, // #pragma comment(compiler, ...) + PCK_ExeStr, // #pragma comment(exestr, ...) + PCK_User // #pragma comment(user, ...) + }; + /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, @@ -6595,6 +6605,9 @@ public: /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); + /// ActOnPragmaMSStruct - Called on well formed \#pragma comment(kind, "arg"). + void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg); + /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. void ActOnPragmaUnused(const Token &Identifier, Scope *curScope, diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 679cfeb6ed3..9570076574c 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -179,6 +179,14 @@ namespace clang { Gen->HandleVTable(RD, DefinitionRequired); } + virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) { + Gen->HandleLinkerOptionPragma(Opts); + } + + virtual void HandleDependentLibrary(llvm::StringRef Opts) { + Gen->HandleDependentLibrary(Opts); + } + static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, unsigned LocCookie) { SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0b03a3c4b67..1da4e87c0a5 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -186,7 +186,8 @@ void CodeGenModule::Release() { EmitStaticExternCAliases(); EmitLLVMUsed(); - if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) { + if (CodeGenOpts.Autolink && + (Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) { EmitModuleLinkOptions(); } @@ -762,31 +763,41 @@ void CodeGenModule::EmitLLVMUsed() { GV->setSection("llvm.metadata"); } +void CodeGenModule::AppendLinkerOptions(StringRef Opts) { + llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opts); + LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); +} + +void CodeGenModule::AddDependentLib(StringRef Lib) { + llvm::SmallString<24> Opt; + getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt); + llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt); + LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); +} + /// \brief Add link options implied by the given module, including modules /// it depends on, using a postorder walk. -static void addLinkOptionsPostorder(llvm::LLVMContext &Context, +static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, SmallVectorImpl<llvm::Value *> &Metadata, llvm::SmallPtrSet<Module *, 16> &Visited) { // Import this module's parent. if (Mod->Parent && Visited.insert(Mod->Parent)) { - addLinkOptionsPostorder(Context, Mod->Parent, Metadata, Visited); + addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited); } // Import this module's dependencies. for (unsigned I = Mod->Imports.size(); I > 0; --I) { if (Visited.insert(Mod->Imports[I-1])) - addLinkOptionsPostorder(Context, Mod->Imports[I-1], Metadata, Visited); + addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited); } // Add linker options to link against the libraries/frameworks // described by this module. + llvm::LLVMContext &Context = CGM.getLLVMContext(); for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) { - // FIXME: -lfoo is Unix-centric and -framework Foo is Darwin-centric. - // We need to know more about the linker to know how to encode these - // options propertly. - - // Link against a framework. + // Link against a framework. Frameworks are currently Darwin only, so we + // don't to ask TargetCodeGenInfo for the spelling of the linker option. if (Mod->LinkLibraries[I-1].IsFramework) { llvm::Value *Args[2] = { llvm::MDString::get(Context, "-framework"), @@ -798,9 +809,10 @@ static void addLinkOptionsPostorder(llvm::LLVMContext &Context, } // Link against a library. - llvm::Value *OptString - = llvm::MDString::get(Context, - "-l" + Mod->LinkLibraries[I-1].Library); + llvm::SmallString<24> Opt; + CGM.getTargetCodeGenInfo().getDependentLibraryOption( + Mod->LinkLibraries[I-1].Library, Opt); + llvm::Value *OptString = llvm::MDString::get(Context, Opt); Metadata.push_back(llvm::MDNode::get(Context, OptString)); } } @@ -852,20 +864,23 @@ void CodeGenModule::EmitModuleLinkOptions() { } // Add link options for all of the imported modules in reverse topological - // order. + // order. We don't do anything to try to order import link flags with respect + // to linker options inserted by things like #pragma comment(). SmallVector<llvm::Value *, 16> MetadataArgs; Visited.clear(); for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(), MEnd = LinkModules.end(); M != MEnd; ++M) { if (Visited.insert(*M)) - addLinkOptionsPostorder(getLLVMContext(), *M, MetadataArgs, Visited); + addLinkOptionsPostorder(*this, *M, MetadataArgs, Visited); } std::reverse(MetadataArgs.begin(), MetadataArgs.end()); + LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end()); // Add the linker options metadata flag. getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options", - llvm::MDNode::get(getLLVMContext(), MetadataArgs)); + llvm::MDNode::get(getLLVMContext(), + LinkerOptionsMetadata)); } void CodeGenModule::EmitDeferred() { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 91138c607c3..1d6c7e98e5c 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -355,6 +355,9 @@ class CodeGenModule : public CodeGenTypeCache { /// \brief The complete set of modules that has been imported. llvm::SetVector<clang::Module *> ImportedModules; + /// \brief A vector of metadata strings. + SmallVector<llvm::Value *, 16> LinkerOptionsMetadata; + /// @name Cache for Objective-C runtime types /// @{ @@ -906,6 +909,12 @@ public: void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); + /// \brief Appends Opts to the "Linker Options" metadata value. + void AppendLinkerOptions(StringRef Opts); + + /// \brief Appends a dependent lib to the "Linker Options" metadata value. + void AddDependentLib(StringRef Lib); + llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 69e5b323045..56067a47bbd 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -115,6 +116,14 @@ namespace { Builder->EmitVTable(RD, DefinitionRequired); } + + virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) { + Builder->AppendLinkerOptions(Opts); + } + + virtual void HandleDependentLibrary(llvm::StringRef Lib) { + Builder->AddDependentLib(Lib); + } }; } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 32b27b3172a..45fc475e341 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -143,6 +143,16 @@ bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, return false; } +void +TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, + llvm::SmallString<24> &Opt) const { + // This assumes the user is passing a library name like "rt" instead of a + // filename like "librt.a/so", and that they don't care whether it's static or + // dynamic. + Opt = "-l"; + Opt += Lib; +} + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -1256,6 +1266,18 @@ public: }; +class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo { +public: + WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned RegParms) + : X86_32TargetCodeGenInfo(CGT, false, true, true, RegParms) {} + + void getDependentLibraryOption(llvm::StringRef Lib, + llvm::SmallString<24> &Opt) const { + Opt = "/DEFAULTLIB:"; + Opt += Lib; + } +}; + class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) @@ -1274,6 +1296,12 @@ public: AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16); return false; } + + void getDependentLibraryOption(llvm::StringRef Lib, + llvm::SmallString<24> &Opt) const { + Opt = "/DEFAULTLIB:"; + Opt += Lib; + } }; } @@ -5173,8 +5201,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::Win32: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, true, true, - CodeGenOpts.NumRegisterParameters)); + new WinX86_32TargetCodeGenInfo(Types, + CodeGenOpts.NumRegisterParameters)); default: return *(TheTargetCodeGenInfo = diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index bb50ce69e31..dee7fd8dd40 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -18,6 +18,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" namespace llvm { class GlobalValue; @@ -167,6 +168,11 @@ namespace clang { /// that unprototyped calls to varargs functions still succeed. virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args, const FunctionNoProtoType *fnType) const; + + /// Gets the linker options necessary to link a dependent library on this + /// platform. + virtual void getDependentLibraryOption(llvm::StringRef Lib, + llvm::SmallString<24> &Opt) const; }; } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 3d1249aa684..3c6f96ac2be 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -821,10 +821,16 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, } // Verify that this is one of the 5 whitelisted options. - // FIXME: warn that 'exestr' is deprecated. - const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && - !II->isStr("linker") && !II->isStr("user")) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + Sema::PragmaMSCommentKind Kind = + llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName()) + .Case("linker", Sema::PCK_Linker) + .Case("lib", Sema::PCK_Lib) + .Case("compiler", Sema::PCK_Compiler) + .Case("exestr", Sema::PCK_ExeStr) + .Case("user", Sema::PCK_User) + .Default(Sema::PCK_Unknown); + if (Kind == Sema::PCK_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); return; } @@ -837,11 +843,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, /*MacroExpansion=*/true)) return; + // FIXME: warn that 'exestr' is deprecated. // FIXME: If the kind is "compiler" warn if the string is present (it is // ignored). - // FIXME: 'lib' requires a comment string. - // FIXME: 'linker' requires a comment string, and has a specific list of - // things that are allowable. + // The MSDN docs say that "lib" and "linker" require a string and have a short + // whitelist of linker options they support, but in practice MSVC doesn't + // issue a diagnostic. Therefore neither does clang. if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); @@ -857,4 +864,6 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // If the pragma is lexically sound, notify any interested PPCallbacks. if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); + + Actions.ActOnPragmaMSComment(Kind, ArgumentString); } diff --git a/clang/lib/Parse/ParsePragma.h b/clang/lib/Parse/ParsePragma.h index d9560f3181d..3c6f3434ad0 100644 --- a/clang/lib/Parse/ParsePragma.h +++ b/clang/lib/Parse/ParsePragma.h @@ -116,9 +116,12 @@ public: /// PragmaCommentHandler - "\#pragma comment ...". class PragmaCommentHandler : public PragmaHandler { public: - PragmaCommentHandler() : PragmaHandler("comment") {} + PragmaCommentHandler(Sema &Actions) + : PragmaHandler("comment"), Actions(Actions) {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); +private: + Sema &Actions; }; } // end namespace clang diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 455139b881a..2117df45f3a 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -103,7 +103,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) PP.AddPragmaHandler(OpenMPHandler.get()); if (getLangOpts().MicrosoftExt) { - MSCommentHandler.reset(new PragmaCommentHandler()); + MSCommentHandler.reset(new PragmaCommentHandler(actions)); PP.AddPragmaHandler(MSCommentHandler.get()); } diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index e12bbde0d0d..bc19b382989 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" @@ -263,6 +264,26 @@ void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) { MSStructPragmaOn = (Kind == PMSST_ON); } +void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, llvm::StringRef Arg) { + // FIXME: Serialize this. + switch (Kind) { + case PCK_Unknown: + llvm_unreachable("unexpected pragma comment kind"); + case PCK_Linker: + Consumer.HandleLinkerOptionPragma(Arg); + return; + case PCK_Lib: { + Consumer.HandleDependentLibrary(Arg); + return; + } + case PCK_Compiler: + case PCK_ExeStr: + case PCK_User: + return; // We ignore all of these. + } + llvm_unreachable("invalid pragma comment kind"); +} + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, SourceLocation PragmaLoc) { diff --git a/clang/test/Modules/autolink.m b/clang/test/Modules/autolink.m index 4bf9d592a8f..2b31fe51542 100644 --- a/clang/test/Modules/autolink.m +++ b/clang/test/Modules/autolink.m @@ -35,7 +35,7 @@ int use_no_umbrella() { // CHECK: !4 = metadata !{i32 6, metadata !"Linker Options", metadata ![[AUTOLINK_OPTIONS:[0-9]+]]} // CHECK: ![[AUTOLINK_OPTIONS]] = metadata !{metadata ![[AUTOLINK_FRAMEWORK:[0-9]+]], metadata ![[AUTOLINK:[0-9]+]], metadata ![[DEPENDSONMODULE:[0-9]+]], metadata ![[MODULE:[0-9]+]], metadata ![[NOUMBRELLA:[0-9]+]]} // CHECK: ![[AUTOLINK_FRAMEWORK]] = metadata !{metadata !"-framework", metadata !"autolink_framework"} -// CHECK: ![[AUTOLINK]] = metadata !{metadata !"-lautolink"} +// CHECK: ![[AUTOLINK]] = metadata !{metadata !"{{(-l|/DEFAULTLIB:)}}autolink"} // CHECK: ![[DEPENDSONMODULE]] = metadata !{metadata !"-framework", metadata !"DependsOnModule"} // CHECK: ![[MODULE]] = metadata !{metadata !"-framework", metadata !"Module"} // CHECK: ![[NOUMBRELLA]] = metadata !{metadata !"-framework", metadata !"NoUmbrella"} |