> Includes regression test for problem noted by @hans.
> is reverts commit 973de71.
>
> Differential Revision: https://reviews.llvm.org/D106898
Feature implemented as-is is fairly expensive and hasn't been used by
libc++. A potential reimplementation is possible if libc++ become
interested in this feature again.
Differential Revision: https://reviews.llvm.org/D123885
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <set>
#include <string>
namespace clang {
//===----------------------------------------------------------------------===//
#include "clang-pseudo/Token.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/Lexer.h"
"#pragma system_header ignored in main file">,
InGroup<DiagGroup<"pragma-system-header-outside-header">>;
-def err_pragma_include_instead_not_sysheader : Error<
- "'#pragma clang include_instead' cannot be used outside of system headers">;
-def err_pragma_include_instead_system_reserved : Error<
- "header '%0' is an implementation detail; #include %select{'%2'|either '%2' "
- "or '%3'|one of %2}1 instead">;
-
def err_illegal_use_of_flt_eval_macro : Error<
"'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing "
"'#pragma clang fp eval_method'">;
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileEntry.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
/// of the framework.
StringRef Framework;
- /// List of aliases that this header is known as.
- /// Most headers should only have at most one alias, but a handful
- /// have two.
- llvm::SetVector<llvm::SmallString<32>,
- llvm::SmallVector<llvm::SmallString<32>, 2>,
- llvm::SmallSet<llvm::SmallString<32>, 2>>
- Aliases;
-
HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
getFileInfo(File).DirInfo = SrcMgr::C_System;
}
- void AddFileAlias(const FileEntry *File, StringRef Alias) {
- getFileInfo(File).Aliases.insert(Alias);
- }
-
/// Mark the specified file as part of a module.
void MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
#ifndef LLVM_CLANG_LEX_LEXER_H
#define LLVM_CLANG_LEX_LEXER_H
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/PreprocessorLexer.h"
/// Read a universal character name.
///
/// \param StartPtr The position in the source buffer after the initial '\'.
- /// If the UCN is syntactically well-formed (but not
+ /// If the UCN is syntactically well-formed (but not
/// necessarily valid), this parameter will be updated to
/// point to the character after the UCN.
/// \param SlashLoc The position in the source buffer of the '\'.
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
/// This either returns the EOF token and returns true, or
/// pops a level off the include stack and returns false, at which point the
/// client should call lex again.
- bool HandleEndOfFile(Token &Result, SourceLocation Loc,
- bool isEndOfMacro = false);
+ bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false);
/// Callback invoked when the current TokenLexer hits the end of its
/// token stream.
// Pragmas.
void HandlePragmaDirective(PragmaIntroducer Introducer);
- void ResolvePragmaIncludeInstead(SourceLocation Location) const;
public:
void HandlePragmaOnce(Token &OnceTok);
void HandlePragmaMark(Token &MarkTok);
void HandlePragmaPoison();
void HandlePragmaSystemHeader(Token &SysHeaderTok);
- void HandlePragmaIncludeInstead(Token &Tok);
void HandlePragmaDependency(Token &DependencyTok);
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
+#include "clang/Basic/FileEntry.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
#include <cassert>
namespace clang {
/// we are currently in.
SmallVector<PPConditionalInfo, 4> ConditionalStack;
- struct IncludeInfo {
- const FileEntry *File;
- SourceLocation Location;
- };
- // A complete history of all the files included by the current file.
- llvm::StringMap<IncludeInfo> IncludeHistory;
-
PreprocessorLexer() : FID() {}
PreprocessorLexer(Preprocessor *pp, FileID fid);
virtual ~PreprocessorLexer() = default;
ConditionalStack.clear();
ConditionalStack.append(CL.begin(), CL.end());
}
-
- void addInclude(StringRef Filename, const FileEntry &File,
- SourceLocation Location) {
- IncludeHistory.insert({Filename, {&File, Location}});
- }
-
- const llvm::StringMap<IncludeInfo> &getIncludeHistory() const {
- return IncludeHistory;
- }
};
} // namespace clang
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
ConditionalStack.pop_back();
}
- SourceLocation EndLoc = getSourceLocation(BufferEnd);
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
DiagnosticsEngine &Diags = PP->getDiagnostics();
+ SourceLocation EndLoc = getSourceLocation(BufferEnd);
unsigned DiagID;
if (LangOpts.CPlusPlus11) {
BufferPtr = CurPtr;
// Finally, let the preprocessor handle this.
- return PP->HandleEndOfFile(Result, EndLoc, isPragmaLexer());
+ return PP->HandleEndOfFile(Result, isPragmaLexer());
}
/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from
IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
- // Record the header's filename for later use.
- if (File)
- CurLexer->addInclude(OriginalFilename, File->getFileEntry(), FilenameLoc);
-
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
if (File && isPCHThroughHeader(&File->getFileEntry()))
SkippingUntilPCHThroughHeader = false;
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
}
}
-void Preprocessor::ResolvePragmaIncludeInstead(
- const SourceLocation Location) const {
- assert(Location.isValid());
- if (CurLexer == nullptr)
- return;
-
- if (SourceMgr.isInSystemHeader(Location))
- return;
-
- for (const auto &Include : CurLexer->getIncludeHistory()) {
- StringRef Filename = Include.getKey();
- const PreprocessorLexer::IncludeInfo &Info = Include.getValue();
- ArrayRef<SmallString<32>> Aliases =
- HeaderInfo.getFileInfo(Info.File).Aliases.getArrayRef();
-
- if (Aliases.empty())
- continue;
-
- switch (Aliases.size()) {
- case 1:
- Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
- << Filename << 0 << Aliases[0];
- continue;
- case 2:
- Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
- << Filename << 1 << Aliases[0] << Aliases[1];
- continue;
- default: {
- Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
- << Filename << 2 << ("{'" + llvm::join(Aliases, "', '") + "'}");
- }
- }
- }
-}
-
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
/// the include stack and keeps going.
-bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc,
- bool isEndOfMacro) {
+bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
assert(!CurTokenLexer &&
"Ending a file when currently in a macro!");
}
}
- if (EndLoc.isValid())
- ResolvePragmaIncludeInstead(EndLoc);
-
// Complain about reaching a true EOF within arc_cf_code_audited.
// We don't want to complain about reaching the end of a macro
// instantiation or a _Pragma.
TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer);
// Handle this like a #include file being popped off the stack.
- return HandleEndOfFile(Result, {}, true);
+ return HandleEndOfFile(Result, true);
}
/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the
#include "clang/Lex/Pragma.h"
#include "clang/Basic/CLWarnings.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Lex/TokenLexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Timer.h"
SrcMgr::C_System);
}
-static llvm::Optional<Token> LexHeader(Preprocessor &PP,
- Optional<FileEntryRef> &File,
- bool SuppressIncludeNotFoundError) {
+/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
+void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
Token FilenameTok;
- if (PP.LexHeaderName(FilenameTok, /*AllowConcatenation*/ false))
- return llvm::None;
+ if (LexHeaderName(FilenameTok, /*AllowConcatenation*/false))
+ return;
// If the next token wasn't a header-name, diagnose the error.
if (FilenameTok.isNot(tok::header_name)) {
- PP.Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
- return llvm::None;
+ Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+ return;
}
// Reserve a buffer to get the spelling.
SmallString<128> FilenameBuffer;
bool Invalid = false;
- StringRef Filename = PP.getSpelling(FilenameTok, FilenameBuffer, &Invalid);
+ StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
if (Invalid)
- return llvm::None;
+ return;
bool isAngled =
- PP.GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
+ GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
if (Filename.empty())
- return llvm::None;
+ return;
// Search include directories for this file.
- File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr);
+ Optional<FileEntryRef> File =
+ LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
- PP.Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
- return llvm::None;
- }
-
- return FilenameTok;
-}
-
-/// HandlePragmaIncludeInstead - Handle \#pragma clang include_instead(header).
-void Preprocessor::HandlePragmaIncludeInstead(Token &Tok) {
- // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
- PreprocessorLexer *TheLexer = getCurrentFileLexer();
-
- if (!SourceMgr.isInSystemHeader(Tok.getLocation())) {
- Diag(Tok, diag::err_pragma_include_instead_not_sysheader);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
- Lex(Tok);
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected) << "(";
- return;
- }
-
- Optional<FileEntryRef> File;
- llvm::Optional<Token> FilenameTok =
- LexHeader(*this, File, SuppressIncludeNotFoundError);
- if (!FilenameTok)
- return;
-
- Lex(Tok);
- if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected) << ")";
- return;
- }
-
- SmallString<128> FilenameBuffer;
- StringRef Filename = getSpelling(*FilenameTok, FilenameBuffer);
- HeaderInfo.AddFileAlias(TheLexer->getFileEntry(), Filename);
-}
-
-/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
-void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
- Optional<FileEntryRef> File;
- llvm::Optional<Token> FilenameTok =
- LexHeader(*this, File, SuppressIncludeNotFoundError);
- if (!FilenameTok)
- return;
-
const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry();
// If this file is older than the file it depends on, emit a diagnostic.
// Remove the trailing ' ' if present.
if (!Message.empty())
Message.erase(Message.end()-1);
- Diag(*FilenameTok, diag::pp_out_of_date_dependency) << Message;
+ Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message;
}
}
}
};
-/// PragmaIncludeInsteadHandler - "\#pragma clang include_instead(header)" marks
-/// the current file as non-includable if the including header is not a system
-/// header.
-struct PragmaIncludeInsteadHandler : public PragmaHandler {
- PragmaIncludeInsteadHandler() : PragmaHandler("include_instead") {}
-
- void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
- Token &IIToken) override {
- PP.HandlePragmaIncludeInstead(IIToken);
- }
-};
-
struct PragmaDependencyHandler : public PragmaHandler {
PragmaDependencyHandler() : PragmaHandler("dependency") {}
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler());
AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
- AddPragmaHandler("clang", new PragmaIncludeInsteadHandler());
AddPragmaHandler("clang", new PragmaDebugHandler());
AddPragmaHandler("clang", new PragmaDependencyHandler());
AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
+++ /dev/null
-// Enabling MS extensions should allow us to add BAR definitions.
-// RUN: %clang_cc1 -DMSEXT -fms-extensions -DBAZ="\"Inputs/pch-through1.h\"" -emit-pch -o %t1.pch
-// RUN: %clang_cc1 -DMSEXT -fms-extensions -include-pch %t1.pch -verify %s
-
-#include BAZ
-// expected-no-diagnostics
+++ /dev/null
-#pragma GCC system_header
-
-#pragma clang include_instead <include_instead/public-before.h>
-// expected-error@-1{{expected (}}
-
-#pragma clang include_instead(<include_instead/public-after.h>]
-// expected-error@-1{{expected )}}
+++ /dev/null
-#pragma GCC system_header
-#pragma clang include_instead(<include_instead/does_not_exist.h>)
-// expected-error@-1{{'include_instead/does_not_exist.h' file not found}}
+++ /dev/null
-#pragma clang include_instead(<include_instead/public1.h>)
-// expected-error@-1{{'#pragma clang include_instead' cannot be used outside of system headers}}
+++ /dev/null
-#include <include_instead/private1.h>
-
-#pragma GCC system_header
-#pragma clang include_instead(<include_instead/public-gcc-system-header-before-includes.h>)
+++ /dev/null
-#pragma GCC system_header
-#pragma clang include_instead(<include_instead/public-before.h>)
+++ /dev/null
-#pragma GCC system_header
-
-#pragma clang include_instead(<include_instead/public-before.h>)
-#pragma clang include_instead("include_instead/public-after.h")
+++ /dev/null
-#pragma GCC system_header
-
-#pragma clang include_instead(<include_instead/public-after.h>)
-#pragma clang include_instead(<include_instead/public-empty.h>)
-#pragma clang include_instead("include_instead/public-before.h")
+++ /dev/null
-#include <include_instead/private2.h>
-#pragma GCC system_header
+++ /dev/null
-#pragma GCC system_header
-
-#include <include_instead/private1.h> // no warning expected
-#include <include_instead/private2.h> // no warning expected
-#include <include_instead/private3.h> // no warning expected
+++ /dev/null
-// This file simply needs to exist.
+++ /dev/null
-// RUN: %clang_cc1 -fsyntax-only -verify -I %S/Inputs %s
-
-#include <include_instead/bad-syntax.h>
-#include <include_instead/non-system-header.h>
-
-#include <include_instead/private1.h>
-// expected-error@-1{{header '<include_instead/private1.h>' is an implementation detail; #include '<include_instead/public-before.h>' instead}}
-
-#include "include_instead/private2.h"
-// expected-error@-1{{header '"include_instead/private2.h"' is an implementation detail; #include either '<include_instead/public-before.h>' or '"include_instead/public-after.h"' instead}}
-
-#include <include_instead/private3.h>
-// expected-error@-1{{header '<include_instead/private3.h>' is an implementation detail; #include one of {'<include_instead/public-after.h>', '<include_instead/public-empty.h>', '"include_instead/public-before.h"'} instead}}
-
-#include <include_instead/public-before.h>
-#include <include_instead/public-after.h>
+++ /dev/null
-// RUN: %clang_cc1 -fsyntax-only -verify -I %S/Inputs %s
-#include <include_instead/file-not-found.h>