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

Reply via email to