зеркало из https://github.com/microsoft/clang-1.git
Adding support for #pragma include_alias in MS compatibility mode. This implements PR 10705.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151949 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7ec419aa8f
Коммит
4c55c54db8
|
@ -292,6 +292,19 @@ def warn_has_warning_invalid_option :
|
|||
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<
|
||||
|
|
|
@ -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 @@ class HeaderSearch {
|
|||
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 @@ public:
|
|||
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;
|
||||
|
|
|
@ -1262,6 +1262,7 @@ public:
|
|||
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
|
||||
|
|
|
@ -1274,6 +1274,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
|
|||
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 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
|
|||
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;
|
||||
|
|
|
@ -663,6 +663,112 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ struct PragmaCommentHandler : public PragmaHandler {
|
|||
}
|
||||
};
|
||||
|
||||
/// 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 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
|||
// MS extensions.
|
||||
if (Features.MicrosoftExt) {
|
||||
AddPragmaHandler(new PragmaCommentHandler());
|
||||
AddPragmaHandler(new PragmaIncludeAliasHandler());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,3 +38,46 @@ void f()
|
|||
// 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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче