[cfe-commits] r151949 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/HeaderSearch.h include/clang/Lex/Preprocessor.h lib/Lex/PPDirectives.cpp lib/Lex/Pragma.cpp test/Preprocessor/pragma_microsoft.c

Aaron Ballman aaron at aaronballman.com
Fri Mar 2 14:51:54 PST 2012


Author: aaronballman
Date: Fri Mar  2 16:51:54 2012
New Revision: 151949

URL: http://llvm.org/viewvc/llvm-project?rev=151949&view=rev
Log:
Adding support for #pragma include_alias in MS compatibility mode.  This implements PR 10705.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Lex/Pragma.cpp
    cfe/trunk/test/Preprocessor/pragma_microsoft.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Mar  2 16:51:54 2012
@@ -292,6 +292,19 @@
    ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
    InGroup<MalformedWarningCheck>;
 
+def warn_pragma_include_alias_mismatch_angle :
+   ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted "
+   "include \"%1\"">, InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_mismatch_quote :
+   ExtWarn<"double-quoted include \"%0\" cannot be aliased to angle-bracketed "
+   "include <%1>">, InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_expected :
+   ExtWarn<"pragma include_alias expected '%0'">,
+   InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_expected_filename :
+   ExtWarn<"pragma include_alias expected include filename">,
+   InGroup<UnknownPragmas>;
+
 def err__Pragma_malformed : Error<
   "_Pragma takes a parenthesized string literal">;
 def err_pragma_comment_malformed : Error<

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Fri Mar  2 16:51:54 2012
@@ -19,6 +19,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/ADT/OwningPtr.h"
 #include <vector>
 
 namespace clang {
@@ -154,6 +155,13 @@
   llvm::StringMap<const DirectoryEntry *, llvm::BumpPtrAllocator>
     FrameworkMap;
 
+  /// IncludeAliases - maps include file names (including the quotes or
+  /// angle brackets) to other include file names.  This is used to support the
+  /// include_alias pragma for Microsoft compatibility.
+  typedef llvm::StringMap<std::string, llvm::BumpPtrAllocator>
+    IncludeAliasMap;
+  OwningPtr<IncludeAliasMap> IncludeAliases;
+
   /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing
   /// headermaps.  This vector owns the headermap.
   std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
@@ -217,6 +225,34 @@
     SystemDirIdx++;
   }
 
+  /// HasIncludeAliasMap - Checks whether the map exists or not
+  bool HasIncludeAliasMap() const {
+    return IncludeAliases;
+  }
+
+  /// AddIncludeAlias - Map the source include name to the dest include name.
+  /// The Source should include the angle brackets or quotes, the dest 
+  /// should not.  This allows for distinction between <> and "" headers.
+  void AddIncludeAlias(StringRef Source, StringRef Dest) {
+    if (!IncludeAliases)
+      IncludeAliases.reset(new IncludeAliasMap);
+    (*IncludeAliases)[Source] = Dest;
+  }
+
+  /// MapHeaderToIncludeAlias - Maps one header file name to a different header
+  /// file name, for use with the include_alias pragma.  Note that the source
+  /// file name should include the angle brackets or quotes.  Returns StringRef
+  /// as null if the header cannot be mapped.
+  StringRef MapHeaderToIncludeAlias(StringRef Source) {
+    assert(IncludeAliases && "Trying to map headers when there's no map");
+
+    // Do any filename replacements before anything else
+    IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source);
+    if (Iter != IncludeAliases->end())
+      return Iter->second;
+    return StringRef();
+  }
+
   /// \brief Set the path to the module cache.
   void setModuleCachePath(StringRef CachePath) {
     ModuleCachePath = CachePath;

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Mar  2 16:51:54 2012
@@ -1262,6 +1262,7 @@
   void HandlePragmaMessage(Token &MessageTok);
   void HandlePragmaPushMacro(Token &Tok);
   void HandlePragmaPopMacro(Token &Tok);
+  void HandlePragmaIncludeAlias(Token &Tok);
   IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
 
   // Return true and store the first token only if any CommentHandler

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Mar  2 16:51:54 2012
@@ -1274,6 +1274,7 @@
     return;
   }
 
+  StringRef OriginalFilename = Filename;
   bool isAngled =
     GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
   // If GetIncludeFilenameSpelling set the start ptr to null, there was an
@@ -1304,6 +1305,15 @@
     PragmaARCCFCodeAuditedLoc = SourceLocation();
   }
 
+  if (HeaderInfo.HasIncludeAliasMap()) {
+    // Map the filename with the brackets still attached.  If the name doesn't 
+    // map to anything, fall back on the filename we've already gotten the 
+    // spelling for.
+    StringRef NewName = HeaderInfo.MapHeaderToIncludeAlias(OriginalFilename);
+    if (!NewName.empty())
+      Filename = NewName;
+  }
+
   // Search include directories.
   const DirectoryLookup *CurDir;
   SmallString<1024> SearchPath;

Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Fri Mar  2 16:51:54 2012
@@ -663,6 +663,112 @@
   }
 }
 
+void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
+  // We will either get a quoted filename or a bracketed filename, and we 
+  // have to track which we got.  The first filename is the source name,
+  // and the second name is the mapped filename.  If the first is quoted,
+  // the second must be as well (cannot mix and match quotes and brackets).
+  SourceLocation Loc = Tok.getLocation();
+
+  // Get the open paren
+  Lex(Tok);
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok, diag::warn_pragma_include_alias_expected) << "(";
+    return;
+  }
+
+  // We expect either a quoted string literal, or a bracketed name
+  Token SourceFilenameTok;
+  CurPPLexer->LexIncludeFilename(SourceFilenameTok);
+  if (SourceFilenameTok.is(tok::eod)) {
+    // The diagnostic has already been handled
+    return;
+  }
+
+  StringRef SourceFileName;
+  SmallString<128> FileNameBuffer;
+  if (SourceFilenameTok.is(tok::string_literal) || 
+      SourceFilenameTok.is(tok::angle_string_literal)) {
+    SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer);
+  } else if (SourceFilenameTok.is(tok::less)) {
+    // This could be a path instead of just a name
+    FileNameBuffer.push_back('<');
+    SourceLocation End;
+    if (ConcatenateIncludeName(FileNameBuffer, End))
+      return; // Diagnostic already emitted
+    SourceFileName = FileNameBuffer.str();
+  } else {
+    Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
+    return;
+  }
+  FileNameBuffer.clear();
+
+  // Now we expect a comma, followed by another include name
+  Lex(Tok);
+  if (Tok.isNot(tok::comma)) {
+    Diag(Tok, diag::warn_pragma_include_alias_expected) << ",";
+    return;
+  }
+
+  Token ReplaceFilenameTok;
+  CurPPLexer->LexIncludeFilename(ReplaceFilenameTok);
+  if (ReplaceFilenameTok.is(tok::eod)) {
+    // The diagnostic has already been handled
+    return;
+  }
+
+  StringRef ReplaceFileName;
+  if (ReplaceFilenameTok.is(tok::string_literal) || 
+      ReplaceFilenameTok.is(tok::angle_string_literal)) {
+    ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer);
+  } else if (ReplaceFilenameTok.is(tok::less)) {
+    // This could be a path instead of just a name
+    FileNameBuffer.push_back('<');
+    SourceLocation End;
+    if (ConcatenateIncludeName(FileNameBuffer, End))
+      return; // Diagnostic already emitted
+    ReplaceFileName = FileNameBuffer.str();
+  } else {
+    Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
+    return;
+  }
+
+  // Finally, we expect the closing paren
+  Lex(Tok);
+  if (Tok.isNot(tok::r_paren)) {
+    Diag(Tok, diag::warn_pragma_include_alias_expected) << ")";
+    return;
+  }
+
+  // Now that we have the source and target filenames, we need to make sure
+  // they're both of the same type (angled vs non-angled)
+  StringRef OriginalSource = SourceFileName;
+
+  bool SourceIsAngled = 
+    GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(), 
+                                SourceFileName);
+  bool ReplaceIsAngled =
+    GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(),
+                                ReplaceFileName);
+  if (!SourceFileName.empty() && !ReplaceFileName.empty() &&
+      (SourceIsAngled != ReplaceIsAngled)) {
+    unsigned int DiagID;
+    if (SourceIsAngled)
+      DiagID = diag::warn_pragma_include_alias_mismatch_angle;
+    else
+      DiagID = diag::warn_pragma_include_alias_mismatch_quote;
+
+    Diag(SourceFilenameTok.getLocation(), DiagID)
+      << SourceFileName 
+      << ReplaceFileName;
+
+    return;
+  }
+
+  // Now we can let the include handler know about this mapping
+  getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
+}
+
 /// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
 /// If 'Namespace' is non-null, then it is a token required to exist on the
 /// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -943,6 +1049,15 @@
   }
 };
 
+/// PragmaIncludeAliasHandler - "#pragma include_alias("...")".
+struct PragmaIncludeAliasHandler : public PragmaHandler {
+  PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {}
+  virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                            Token &IncludeAliasTok) {
+      PP.HandlePragmaIncludeAlias(IncludeAliasTok);
+  }
+};
+
 /// PragmaMessageHandler - "#pragma message("...")".
 struct PragmaMessageHandler : public PragmaHandler {
   PragmaMessageHandler() : PragmaHandler("message") {}
@@ -1095,5 +1210,6 @@
   // MS extensions.
   if (Features.MicrosoftExt) {
     AddPragmaHandler(new PragmaCommentHandler());
+    AddPragmaHandler(new PragmaIncludeAliasHandler());
   }
 }

Modified: cfe/trunk/test/Preprocessor/pragma_microsoft.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/pragma_microsoft.c?rev=151949&r1=151948&r2=151949&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/pragma_microsoft.c (original)
+++ cfe/trunk/test/Preprocessor/pragma_microsoft.c Fri Mar  2 16:51:54 2012
@@ -38,3 +38,46 @@
   // this warning should go away.
   MACRO_WITH__PRAGMA // expected-warning {{expression result unused}}
 }
+
+
+// This should include macro_arg_directive even though the include
+// is looking for test.h  This allows us to assign to "n"
+#pragma include_alias("test.h", "macro_arg_directive.h" )
+#include "test.h"
+void test( void ) {
+  n = 12;
+}
+
+#pragma include_alias(<bar.h>, "bar.h") // expected-warning {{angle-bracketed include <bar.h> cannot be aliased to double-quoted include "bar.h"}}
+#pragma include_alias("foo.h", <bar.h>) // expected-warning {{double-quoted include "foo.h" cannot be aliased to angle-bracketed include <bar.h>}}
+#pragma include_alias("test.h") // expected-warning {{pragma include_alias expected ','}}
+
+// Make sure that the names match exactly for a replacement, including path information.  If
+// this were to fail, we would get a file not found error
+#pragma include_alias(".\pp-record.h", "does_not_exist.h")
+#include "pp-record.h"
+
+#pragma include_alias(12) // expected-warning {{pragma include_alias expected include filename}}
+
+// It's expected that we can map "bar" and <bar> separately
+#define test
+// We can't actually look up stdio.h because we're using cc1 without header paths, but this will ensure
+// that we get the right bar.h, because the "bar.h" will undef test for us, where <bar.h> won't
+#pragma include_alias(<bar.h>, <stdio.h>)
+#pragma include_alias("bar.h", "pr2086.h")  // This should #undef test
+
+#include "bar.h"
+#if defined(test)
+// This should not warn because test should not be defined
+#pragma include_alias("test.h")
+#endif
+
+// Test to make sure there are no use-after-free problems
+#define B "pp-record.h"
+#pragma include_alias("quux.h", B)
+void g() {}
+#include "quux.h"
+
+// Make sure that empty includes don't work
+#pragma include_alias("", "foo.h")  // expected-error {{empty filename}}
+#pragma include_alias(<foo.h>, <>)  // expected-error {{empty filename}}





More information about the cfe-commits mailing list