]> granicus.if.org Git - clang/commitdiff
Adding support for MSVC #pragma detect_mismatch functionality by emitting a FAILIFMIS...
authorAaron Ballman <aaron@aaronballman.com>
Tue, 4 Jun 2013 02:07:14 +0000 (02:07 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Tue, 4 Jun 2013 02:07:14 +0000 (02:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183178 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/clang/AST/ASTConsumer.h
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Lex/PPCallbacks.h
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/CodeGen/TargetInfo.cpp
lib/CodeGen/TargetInfo.h
lib/Frontend/PrintPreprocessedOutput.cpp
lib/Parse/ParsePragma.cpp
lib/Parse/ParsePragma.h
lib/Parse/Parser.cpp
lib/Sema/SemaAttr.cpp
test/CodeGen/pragma-detect_mismatch.c [new file with mode: 0644]
test/Preprocessor/pragma_microsoft.c

index 33e9bd92a476f33492be1500d5b267601b6ce17c..9109a6741f9ac6a9f95dac6265eb1fc59b481a0f 100644 (file)
@@ -92,6 +92,12 @@ public:
   /// only exists to support Microsoft's #pragma comment(linker, "/foo").
   virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
 
+  /// \brief Handle a pragma that emits a mismatch identifier and value to the
+  /// object file for the linker to work with.  Currently, this only exists to
+  /// support Microsoft's #pragma detect_mismatch.
+  virtual void HandleDetectMismatch(llvm::StringRef Name,
+                                    llvm::StringRef Value) {}
+
   /// \brief Handle a dependent library created by a pragma in the source.
   /// Currently this only exists to support Microsoft's
   /// #pragma comment(lib, "/foo").
index 69314e93d919aaeee1d393175f7dbcd45edc5dac..74b94d341374d596d7f8e9b91560a0a9cdae2bb2 100644 (file)
@@ -789,7 +789,10 @@ def err_pragma_fp_contract_scope : Error<
 def err_pragma_comment_malformed : Error<
   "pragma comment requires parenthesized identifier and optional string">;
 def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
-
+// - #pragma detect_mismatch
+def err_pragma_detect_mismatch_malformed : Error<
+  "pragma detect_mismatch is malformed; it requires two comma-separated "
+  "string literals">;
 
 // OpenCL Section 6.8.g
 def err_not_opencl_storage_class_specifier : Error<
index db2ecd247f40b650c2ac421e573bcada19bc36ec..021cef00b30cd699f0b7caf1c8384b06fc7de707 100644 (file)
@@ -160,6 +160,13 @@ public:
                              const std::string &Str) {
   }
 
+  /// \brief Callback invoked when a \#pragma detect_mismatch directive is
+  /// read.
+  virtual void PragmaDetectMismatch(SourceLocation Loc,
+                                    const std::string &Name,
+                                    const std::string &Value) {
+  }
+
   /// \brief Callback invoked when a \#pragma clang __debug directive is read.
   /// \param Loc The location of the debug directive.
   /// \param DebugType The identifier following __debug.
@@ -352,6 +359,13 @@ public:
     Second->PragmaComment(Loc, Kind, Str);
   }
 
+  virtual void PragmaDetectMismatch(SourceLocation Loc,
+                                    const std::string &Name,
+                                    const std::string &Value) {
+    First->PragmaDetectMismatch(Loc, Name, Value);
+    Second->PragmaDetectMismatch(Loc, Name, Value);
+  }
+
   virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
                              PragmaMessageKind Kind, StringRef Str) {
     First->PragmaMessage(Loc, Namespace, Kind, Str);
index de45268e0482e69953c4e7024b58d79a942ecb26..d3563bcf3e31c101c4b90a696c3deb5bf1c8a01e 100644 (file)
@@ -150,6 +150,7 @@ class Parser : public CodeCompletionHandler {
   OwningPtr<CommentHandler> CommentSemaHandler;
   OwningPtr<PragmaHandler> OpenMPHandler;
   OwningPtr<PragmaHandler> MSCommentHandler;
+  OwningPtr<PragmaHandler> MSDetectMismatchHandler;
 
   /// Whether the '>' token acts as an operator or not. This will be
   /// true except when we are parsing an expression within a C++
index 22490171c8b2794df135a7969094972256dd0326..d5873864902c16ca0edb0eccb52621d95a246e66 100644 (file)
@@ -6658,6 +6658,9 @@ public:
   /// ActOnPragmaMSStruct - Called on well formed \#pragma comment(kind, "arg").
   void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg);
 
+  /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
+  void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
+
   /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
   void ActOnPragmaUnused(const Token &Identifier,
                          Scope *curScope,
index 9570076574cb01829ab7cfd9db27fb7859a74ad8..804af31c31d4838858975dc9dc45d3b04fd04e5c 100644 (file)
@@ -183,6 +183,11 @@ namespace clang {
       Gen->HandleLinkerOptionPragma(Opts);
     }
 
+    virtual void HandleDetectMismatch(llvm::StringRef Name,
+                                      llvm::StringRef Value) {
+      Gen->HandleDetectMismatch(Name, Value);
+    }
+
     virtual void HandleDependentLibrary(llvm::StringRef Opts) {
       Gen->HandleDependentLibrary(Opts);
     }
index 7ad08e0e0a72a6d20a53df7cdf64fee739369f9d..3675e849aa78e2c40268bd0b3bfee9e23100af1f 100644 (file)
@@ -773,6 +773,13 @@ void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
   LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
 }
 
+void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) {
+  llvm::SmallString<32> Opt;
+  getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt);
+  llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
+  LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
+}
+
 void CodeGenModule::AddDependentLib(StringRef Lib) {
   llvm::SmallString<24> Opt;
   getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt);
index e4e29a8d6b680bf3964859e46f1c1fafa5a12c0c..bc8731669695e11f78c17d2a1be8949ef0507428 100644 (file)
@@ -912,6 +912,9 @@ public:
   /// \brief Appends Opts to the "Linker Options" metadata value.
   void AppendLinkerOptions(StringRef Opts);
 
+  /// \bried Appends a detect mismatch command to the linker options.
+  void AddDetectMismatch(StringRef Name, StringRef Value);
+
   /// \brief Appends a dependent lib to the "Linker Options" metadata value.
   void AddDependentLib(StringRef Lib);
 
index 56067a47bbdc6f55f14c826fa6512902cf9cf4ac..763aa12aab1222b6ad9fb4cbdd0f3297ca1d596a 100644 (file)
@@ -121,6 +121,11 @@ namespace {
       Builder->AppendLinkerOptions(Opts);
     }
 
+    virtual void HandleDetectMismatch(llvm::StringRef Name,
+                                      llvm::StringRef Value) {
+      Builder->AddDetectMismatch(Name, Value);
+    }
+
     virtual void HandleDependentLibrary(llvm::StringRef Lib) {
       Builder->AddDependentLib(Lib);
     }
index 4fa0c3bbdfcd982a399e7710d9135d771312994f..6e5084a149251430cac9209e65aa8a7e67dffa1b 100644 (file)
@@ -1287,6 +1287,12 @@ public:
     Opt = "/DEFAULTLIB:";
     Opt += qualifyWindowsLibrary(Lib);
   }
+
+  void getDetectMismatchOption(llvm::StringRef Name,
+                               llvm::StringRef Value,
+                               llvm::SmallString<32> &Opt) const {
+    Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";\r
+  }
 };
 
 class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -1313,6 +1319,12 @@ public:
     Opt = "/DEFAULTLIB:";
     Opt += qualifyWindowsLibrary(Lib);
   }
+
+  void getDetectMismatchOption(llvm::StringRef Name,
+                               llvm::StringRef Value,
+                               llvm::SmallString<32> &Opt) const {
+    Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";\r
+  }
 };
 
 }
index dee7fd8dd4034b4f2d58face69a9fdb694a42b02..b0ddebc1a0383cc79b8ed76a0cfb092f62a7b682 100644 (file)
@@ -173,6 +173,12 @@ namespace clang {
     /// platform.
     virtual void getDependentLibraryOption(llvm::StringRef Lib,
                                            llvm::SmallString<24> &Opt) const;
+
+    /// Gets the linker options necessary to detect object file mismatches on
+    /// this platform.
+    virtual void getDetectMismatchOption(llvm::StringRef Name,
+                                         llvm::StringRef Value,
+                                         llvm::SmallString<32> &Opt) const {}
   };
 }
 
index 9fd36494358052de85df235d0618f0f56287a430..83b2a271ec360e63542ad2578c1758bf8f68ecaa 100644 (file)
@@ -140,6 +140,9 @@ public:
   virtual void PragmaCaptured(SourceLocation Loc, StringRef Str);
   virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
                              const std::string &Str);
+  virtual void PragmaDetectMismatch(SourceLocation Loc,
+                                    const std::string &Name,
+                                    const std::string &Value);
   virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
                              PragmaMessageKind Kind, StringRef Str);
   virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType);
@@ -382,16 +385,8 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
   setEmittedDirectiveOnThisLine();
 }
 
-void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
-                                             const IdentifierInfo *Kind,
+static void outputPrintable(llvm::raw_ostream& OS,
                                              const std::string &Str) {
-  startNewLineIfNeeded();
-  MoveToLine(Loc);
-  OS << "#pragma comment(" << Kind->getName();
-
-  if (!Str.empty()) {
-    OS << ", \"";
-
     for (unsigned i = 0, e = Str.size(); i != e; ++i) {
       unsigned char Char = Str[i];
       if (isPrintable(Char) && Char != '\\' && Char != '"')
@@ -402,6 +397,18 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
            << (char)('0'+ ((Char >> 3) & 7))
            << (char)('0'+ ((Char >> 0) & 7));
     }
+}
+
+void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
+                                             const IdentifierInfo *Kind,
+                                             const std::string &Str) {
+  startNewLineIfNeeded();
+  MoveToLine(Loc);
+  OS << "#pragma comment(" << Kind->getName();
+
+  if (!Str.empty()) {
+    OS << ", \"";
+    outputPrintable(OS, Str);
     OS << '"';
   }
 
@@ -409,6 +416,19 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
   setEmittedDirectiveOnThisLine();
 }
 
+void PrintPPOutputPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
+                                                    const std::string &Name,
+                                                    const std::string &Value) {
+  startNewLineIfNeeded();
+  MoveToLine(Loc);
+  OS << "#pragma detect_mismatch(\"" << Name << '"';
+  outputPrintable(OS, Name);
+  OS << "\", \"";
+  outputPrintable(OS, Value);
+  OS << "\")";
+  setEmittedDirectiveOnThisLine();
+}
+
 void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
                                              StringRef Namespace,
                                              PragmaMessageKind Kind,
@@ -430,16 +450,7 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
       break;
   }
 
-  for (unsigned i = 0, e = Str.size(); i != e; ++i) {
-    unsigned char Char = Str[i];
-    if (isPrintable(Char) && Char != '\\' && Char != '"')
-      OS << (char)Char;
-    else  // Output anything hard as an octal escape.
-      OS << '\\'
-         << (char)('0'+ ((Char >> 6) & 7))
-         << (char)('0'+ ((Char >> 3) & 7))
-         << (char)('0'+ ((Char >> 0) & 7));
-  }
+  outputPrintable(OS, Str);
   OS << '"';
   if (Kind == PMK_Message)
     OS << ')';
index 3c6f96ac2be3efa222e02011c035a0b4c0ef4cfa..10ad5df629e0389ea646ebe4ac27fdf18c8a82cf 100644 (file)
@@ -794,6 +794,63 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
                       /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
 }
 
+/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
+///
+/// The syntax is:
+/// \code
+///   #pragma detect_mismatch("name", "value")
+/// \endcode
+/// Where 'name' and 'value' are quoted strings.  The values are embedded in
+/// the object file and passed along to the linker.  If the linker detects a
+/// mismatch in the object file's values for the given name, a LNK2038 error
+/// is emitted.  See MSDN for more details.
+void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
+                                               PragmaIntroducerKind Introducer,
+                                               Token &Tok) {
+  SourceLocation CommentLoc = Tok.getLocation();
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::l_paren)) {
+    PP.Diag(CommentLoc, diag::err_expected_lparen);
+    return;
+  }
+
+  // Read the name to embed, which must be a string literal.
+  std::string NameString;
+  if (!PP.LexStringLiteral(Tok, NameString,
+                           "pragma detect_mismatch",
+                           /*MacroExpansion=*/true))
+    return;
+
+  // Read the comma followed by a second string literal.
+  std::string ValueString;
+  if (Tok.isNot(tok::comma)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
+    return;
+  }
+
+  if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch",
+                           /*MacroExpansion=*/true))
+    return;
+
+  if (Tok.isNot(tok::r_paren)) {
+    PP.Diag(Tok.getLocation(), diag::err_expected_rparen);
+    return;
+  }
+  PP.Lex(Tok);  // Eat the r_paren.
+
+  if (Tok.isNot(tok::eod)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
+    return;
+  }
+
+  // If the pragma is lexically sound, notify any interested PPCallbacks.
+  if (PP.getPPCallbacks())
+    PP.getPPCallbacks()->PragmaDetectMismatch(CommentLoc, NameString,
+                                              ValueString);
+
+  Actions.ActOnPragmaDetectMismatch(NameString, ValueString);
+}
+
 /// \brief Handle the microsoft \#pragma comment extension.
 ///
 /// The syntax is:
index 3c6f3434ad0e31761a6dd0970987a171c6c77d7a..b41450f4eadfc98c931dabca85db15006c311c82 100644 (file)
@@ -124,6 +124,16 @@ private:
   Sema &Actions;
 };
 
+class PragmaDetectMismatchHandler : public PragmaHandler {
+public:
+  PragmaDetectMismatchHandler(Sema &Actions)
+    : PragmaHandler("detect_mismatch"), Actions(Actions) {}
+  virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                            Token &FirstToken);
+private:
+  Sema &Actions;
+};
+
 }  // end namespace clang
 
 #endif
index 3124b96455e2e95b644703c0fa7da8ae3812b793..f19d24299aa50564e18aafdad506349661aed8fd 100644 (file)
@@ -105,6 +105,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
   if (getLangOpts().MicrosoftExt) {
     MSCommentHandler.reset(new PragmaCommentHandler(actions));
     PP.AddPragmaHandler(MSCommentHandler.get());
+    MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(actions));
+    PP.AddPragmaHandler(MSDetectMismatchHandler.get());
   }
 
   CommentSemaHandler.reset(new ActionCommentHandler(actions));
@@ -444,6 +446,8 @@ Parser::~Parser() {
   if (getLangOpts().MicrosoftExt) {
     PP.RemovePragmaHandler(MSCommentHandler.get());
     MSCommentHandler.reset();
+    PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
+    MSDetectMismatchHandler.reset();
   }
 
   PP.RemovePragmaHandler("STDC", FPContractHandler.get());
index 943054be340390488fcd4bbafc428b2d8b6fbc96..3fbb11f2fde1c294b479b248d67e0671ad57cfdc 100644 (file)
@@ -283,6 +283,12 @@ void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, llvm::StringRef Arg) {
   llvm_unreachable("invalid pragma comment kind");
 }
 
+void Sema::ActOnPragmaDetectMismatch(llvm::StringRef Name,
+                                     llvm::StringRef Value) {
+  // FIXME: Serialize this.
+  Consumer.HandleDetectMismatch(Name, Value);
+}
+
 void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
                              SourceLocation PragmaLoc) {
 
diff --git a/test/CodeGen/pragma-detect_mismatch.c b/test/CodeGen/pragma-detect_mismatch.c
new file mode 100644 (file)
index 0000000..86cc6d8
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s\r
+\r
+#pragma detect_mismatch("test", "1")\r
+\r
+#define BAR "2"\r
+#pragma detect_mismatch("test2", BAR)\r
+\r
+// CHECK: !llvm.module.flags = !{!0}\r
+// CHECK: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}\r
+// CHECK: ![[link_opts]] = metadata !{metadata ![[test:[0-9]+]], metadata ![[test2:[0-9]+]]}\r
+// CHECK: ![[test]] = metadata !{metadata !"/FAILIFMISMATCH:\22test=1\22"}\r
+// CHECK: ![[test2]] = metadata !{metadata !"/FAILIFMISMATCH:\22test2=2\22"}\r
index c0ddf74340ce37a65502f106d276691eadc68db8..26f0a1df8c137100d758eaa521dfbfb6ff66f614 100644 (file)
 
 #pragma comment(user, "foo\abar\nbaz\tsome     thing")
 
+#pragma detect_mismatch("test", "1")
+#pragma detect_mismatch()  // expected-error {{expected string literal in pragma detect_mismatch}}
+#pragma detect_mismatch("test") // expected-error {{pragma detect_mismatch is malformed; it requires two comma-separated string literals}}
+#pragma detect_mismatch("test", 1) // expected-error {{expected string literal in pragma detect_mismatch}}
+#pragma detect_mismatch("test", BAR)
 
 // __pragma