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.
The MC layer change to forward the metadata into the .drectve section is
forthcoming.
This is related to auto-linking, which is http://llvm.org/PR13016.
http://llvm-reviews.chandlerc.com/D723
Files:
include/clang/AST/ASTConsumer.h
include/clang/Basic/PragmaKinds.h
include/clang/Basic/TokenKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/CodeGen/CodeGenAction.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ModuleBuilder.cpp
lib/Lex/Lexer.cpp
lib/Lex/Pragma.cpp
lib/Parse/ParsePragma.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaAttr.cpp
test/CodeGen/pragma-comment.c
Index: include/clang/AST/ASTConsumer.h
===================================================================
--- include/clang/AST/ASTConsumer.h
+++ 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,10 @@
/// 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(lib/linker, "foo").
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
+
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be
/// completed.
Index: include/clang/Basic/PragmaKinds.h
===================================================================
--- /dev/null
+++ include/clang/Basic/PragmaKinds.h
@@ -0,0 +1,33 @@
+//===--- PragmaKinds.h - Enum values for pragmas ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides enums used across Lex, Parse, and Sema.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_PRAGMAKINDS_H
+#define LLVM_CLANG_BASIC_PRAGMAKINDS_H
+
+namespace clang {
+
+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, ...)
+};
+
+// TODO: Consider moving some of the pragma kind enums from Sema here.
+
+} // end namespace clang
+
+#endif
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -650,6 +650,11 @@
// handles them.
ANNOTATION(pragma_fp_contract)
+// Annotation for #pragma comment
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_mscomment)
+
// Annotation for #pragma OPENCL EXTENSION...
// The lexer produces these so that they only take effect when the parser
// handles them.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -399,6 +399,10 @@
void HandlePragmaMSStruct();
/// \brief Handle the annotation token produced for
+ /// #pragma comment...
+ void HandlePragmaMSComment();
+
+ /// \brief Handle the annotation token produced for
/// #pragma align...
void HandlePragmaAlign();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ 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;
@@ -6565,6 +6566,9 @@
/// 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,
Index: lib/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -179,6 +179,10 @@
Gen->HandleVTable(RD, DefinitionRequired);
}
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ Gen->HandleLinkerOptionPragma(Opts);
+ }
+
static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
unsigned LocCookie) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -186,7 +186,8 @@
EmitStaticExternCAliases();
EmitLLVMUsed();
- if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) {
+ if (CodeGenOpts.Autolink &&
+ (Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
EmitModuleLinkOptions();
}
@@ -762,6 +763,11 @@
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));
+}
+
/// \brief Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
@@ -852,7 +858,8 @@
}
// 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(),
@@ -862,10 +869,12 @@
addLinkOptionsPostorder(getLLVMContext(), *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() {
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -355,6 +355,9 @@
/// \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
/// @{
@@ -907,6 +910,9 @@
void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
+ /// \brief Appends Opts to the "Linker Options" metadata value.
+ void AppendLinkerOptions(StringRef Opts);
+
llvm::GlobalVariable::LinkageTypes
getFunctionLinkage(const FunctionDecl *FD);
Index: lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- lib/CodeGen/ModuleBuilder.cpp
+++ lib/CodeGen/ModuleBuilder.cpp
@@ -115,6 +115,10 @@
Builder->EmitVTable(RD, DefinitionRequired);
}
+
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ Builder->AppendLinkerOptions(Opts);
+ }
};
}
Index: lib/Lex/Lexer.cpp
===================================================================
--- lib/Lex/Lexer.cpp
+++ lib/Lex/Lexer.cpp
@@ -339,6 +339,16 @@
/// UCNs, etc.
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
+ std::string Result;
+ // Annotations generated by the lexer don't have spellings or lengths.
+ // Usually they're storing integer data, so dump that.
+ if (Tok.isAnnotation()) {
+ llvm::raw_string_ostream os(Result);
+ os << reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
+ os.flush();
+ return Result;
+ }
+
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
bool CharDataInvalid = false;
@@ -353,7 +363,6 @@
if (!Tok.needsCleaning())
return std::string(TokStart, TokStart + Tok.getLength());
- std::string Result;
Result.resize(Tok.getLength());
Result.resize(getSpellingSlow(Tok, TokStart, LangOpts, &*Result.begin()));
return Result;
Index: lib/Lex/Pragma.cpp
===================================================================
--- lib/Lex/Pragma.cpp
+++ lib/Lex/Pragma.cpp
@@ -14,14 +14,16 @@
#include "clang/Lex/Pragma.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/StringSwitch.h"
#include <algorithm>
using namespace clang;
@@ -517,10 +519,16 @@
}
// 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();
+ PragmaMSCommentKind Kind =
+ llvm::StringSwitch<PragmaMSCommentKind>(II->getName())
+ .Case("linker", PCK_Linker)
+ .Case("lib", PCK_Lib)
+ .Case("compiler", PCK_Compiler)
+ .Case("exestr", PCK_ExeStr)
+ .Case("user", PCK_User)
+ .Default(PCK_Unknown);
+ if (Kind == PCK_Unknown) {
Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
return;
}
@@ -533,11 +541,12 @@
/*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)) {
Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
@@ -553,6 +562,26 @@
// If the pragma is lexically sound, notify any interested PPCallbacks.
if (Callbacks)
Callbacks->PragmaComment(CommentLoc, II, ArgumentString);
+
+ Token *Toks = BP.Allocate<Token>(2);
+
+ // Inject a pragma annotation.
+ new (&Toks[0]) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_mscomment);
+ Toks[0].setLocation(CommentLoc);
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(static_cast<uintptr_t>(Kind)));
+
+ // Inject the argument token back into the stream.
+ // FIXME: Is there a better way to forward the string literal on to the
+ // parser?
+ new (&Toks[1]) Token();
+ Toks[1].startToken();
+ Toks[1].setKind(tok::string_literal);
+ CreateString(ArgumentString, Toks[1]);
+
+ EnterTokenStream(Toks, 2, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro.
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp
+++ lib/Parse/ParsePragma.cpp
@@ -70,6 +70,19 @@
ConsumeToken(); // The annotation token.
}
+void Parser::HandlePragmaMSComment() {
+ assert(Tok.is(tok::annot_pragma_mscomment));
+ PragmaMSCommentKind Kind =
+ static_cast<PragmaMSCommentKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ ConsumeToken();
+
+ assert(Tok.is(tok::string_literal));
+ StringRef Arg(Tok.getLiteralData(), Tok.getLength());
+ Actions.ActOnPragmaMSComment(Kind, Arg);
+ ConsumeStringToken();
+}
+
void Parser::HandlePragmaAlign() {
assert(Tok.is(tok::annot_pragma_align));
Sema::PragmaOptionsAlignKind Kind =
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -613,6 +613,9 @@
case tok::annot_pragma_msstruct:
HandlePragmaMSStruct();
return DeclGroupPtrTy();
+ case tok::annot_pragma_mscomment:
+ HandlePragmaMSComment();
+ return DeclGroupPtrTy();
case tok::annot_pragma_align:
HandlePragmaAlign();
return DeclGroupPtrTy();
Index: lib/Sema/SemaAttr.cpp
===================================================================
--- lib/Sema/SemaAttr.cpp
+++ 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 @@
MSStructPragmaOn = (Kind == PMSST_ON);
}
+void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, llvm::StringRef Arg) {
+ switch (Kind) {
+ case PCK_Unknown:
+ llvm_unreachable("unexpected pragma comment kind");
+ case PCK_Linker:
+ Consumer.HandleLinkerOptionPragma(Arg);
+ return;
+ case PCK_Lib: {
+ std::string Opts(Twine("/DEFAULTLIB:" + Arg).str());
+ Consumer.HandleLinkerOptionPragma(Opts);
+ 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) {
Index: test/CodeGen/pragma-comment.c
===================================================================
--- /dev/null
+++ test/CodeGen/pragma-comment.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -fms-extensions -fsyntax-only -dump-tokens 2>&1 | FileCheck -check-prefix TOK %s
+// RUN: %clang_cc1 %s -fms-extensions -emit-llvm -o - | FileCheck %s
+
+#pragma comment(lib, "msvcrt.lib")
+// CHECK-TOK: annot_pragma_mscomment
+// CHECK-TOK: string_literal 'msvcrt.lib'
+
+#define BAR "2"
+#pragma comment(linker," /bar=" BAR)
+// CHECK-TOK: annot_pragma_mscomment
+// CHECK-TOK: string_literal ' /bar=2'
+
+// CHECK: !llvm.module.flags = !{!0}
+// CHECK: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]], metadata ![[bar:[0-9]+]]}
+// CHECK: ![[msvcrt]] = metadata !{metadata !"/DEFAULTLIB:msvcrt.lib"}
+// CHECK: ![[bar]] = metadata !{metadata !" /bar=2"}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits