forked from OSchip/llvm-project
[clang-cl, PCH] Support for /Yc and /Yu without filename and #pragma hdrstop
With clang-cl, when the user specifies /Yc or /Yu without a filename the compiler uses a #pragma hdrstop in the main source file to determine the end of the PCH. If a header is specified with /Yc or /Yu #pragma hdrstop has no effect. The optional #pragma hdrstop filename argument is not yet supported. Differential Revision: https://reviews.llvm.org/D51391 llvm-svn: 341963
This commit is contained in:
parent
12fd6bd4ad
commit
58df1affed
|
@ -87,6 +87,11 @@ Attribute Changes in Clang
|
|||
Windows Support
|
||||
---------------
|
||||
|
||||
- clang-cl now supports the use of the precompiled header options /Yc and /Yu
|
||||
without the filename argument. When these options are used without the
|
||||
filename, a `#pragma hdrstop` inside the source marks the end of the
|
||||
precompiled code.
|
||||
|
||||
- ...
|
||||
|
||||
|
||||
|
|
|
@ -151,9 +151,6 @@ def warn_drv_unknown_argument_clang_cl_with_suggestion : Warning<
|
|||
"unknown argument ignored in clang-cl '%0' (did you mean '%1'?)">,
|
||||
InGroup<UnknownArgument>;
|
||||
|
||||
def warn_drv_ycyu_no_arg_clang_cl : Warning<
|
||||
"support for '%0' without a filename not implemented yet; flag ignored">,
|
||||
InGroup<ClangClPch>;
|
||||
def warn_drv_ycyu_different_arg_clang_cl : Warning<
|
||||
"support for '/Yc' and '/Yu' with different filenames not implemented yet; flags ignored">,
|
||||
InGroup<ClangClPch>;
|
||||
|
|
|
@ -412,9 +412,16 @@ def err_pp_through_header_not_found : Error<
|
|||
def err_pp_through_header_not_seen : Error<
|
||||
"#include of '%0' not seen while attempting to "
|
||||
"%select{create|use}1 precompiled header">, DefaultFatal;
|
||||
def err_pp_pragma_hdrstop_not_seen : Error<
|
||||
"#pragma hdrstop not seen while attempting to use precompiled header">,
|
||||
DefaultFatal;
|
||||
def warn_pp_macro_def_mismatch_with_pch : Warning<
|
||||
"definition of macro %0 does not match definition in precompiled header">,
|
||||
InGroup<ClangClPch>;
|
||||
def warn_pp_hdrstop_filename_ignored : Warning<
|
||||
"#pragma hdrstop filename not supported, "
|
||||
"/Fp can be used to specify precompiled header filename">,
|
||||
InGroup<ClangClPch>;
|
||||
def err_pp_file_not_found_not_fatal : Error<
|
||||
"'%0' file not found with <angled> include; use \"quotes\" instead">;
|
||||
def err_pp_error_opening_file : Error<
|
||||
|
|
|
@ -604,6 +604,10 @@ def foverride_record_layout_EQ : Joined<["-"], "foverride-record-layout=">,
|
|||
def pch_through_header_EQ : Joined<["-"], "pch-through-header=">,
|
||||
HelpText<"Stop PCH generation after including this file. When using a PCH, "
|
||||
"skip tokens until after this file is included.">;
|
||||
def pch_through_hdrstop_create : Flag<["-"], "pch-through-hdrstop-create">,
|
||||
HelpText<"When creating a PCH, stop PCH generation after #pragma hdrstop.">;
|
||||
def pch_through_hdrstop_use : Flag<["-"], "pch-through-hdrstop-use">,
|
||||
HelpText<"When using a PCH, skip tokens until after a #pragma hdrstop.">;
|
||||
def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">,
|
||||
HelpText<"Disable inclusion of timestamp in precompiled headers">;
|
||||
def building_pch_with_obj : Flag<["-"], "building-pch-with-obj">,
|
||||
|
|
|
@ -726,6 +726,9 @@ private:
|
|||
/// The file ID for the PCH through header.
|
||||
FileID PCHThroughHeaderFileID;
|
||||
|
||||
/// Whether tokens are being skipped until a #pragma hdrstop is seen.
|
||||
bool SkippingUntilPragmaHdrStop = false;
|
||||
|
||||
/// Whether tokens are being skipped until the through header is seen.
|
||||
bool SkippingUntilPCHThroughHeader = false;
|
||||
|
||||
|
@ -1168,11 +1171,19 @@ public:
|
|||
/// True if using a PCH with a through header.
|
||||
bool usingPCHWithThroughHeader();
|
||||
|
||||
/// Skip tokens until after the #include of the through header.
|
||||
void SkipTokensUntilPCHThroughHeader();
|
||||
/// True if creating a PCH with a #pragma hdrstop.
|
||||
bool creatingPCHWithPragmaHdrStop();
|
||||
|
||||
/// Process directives while skipping until the through header is found.
|
||||
void HandleSkippedThroughHeaderDirective(Token &Result,
|
||||
/// True if using a PCH with a #pragma hdrstop.
|
||||
bool usingPCHWithPragmaHdrStop();
|
||||
|
||||
/// Skip tokens until after the #include of the through header or
|
||||
/// until after a #pragma hdrstop.
|
||||
void SkipTokensWhileUsingPCH();
|
||||
|
||||
/// Process directives while skipping until the through header or
|
||||
/// #pragma hdrstop is found.
|
||||
void HandleSkippedDirectiveWhileUsingPCH(Token &Result,
|
||||
SourceLocation HashLoc);
|
||||
|
||||
/// Enter the specified FileID as the main source file,
|
||||
|
@ -2203,6 +2214,7 @@ public:
|
|||
void HandlePragmaPopMacro(Token &Tok);
|
||||
void HandlePragmaIncludeAlias(Token &Tok);
|
||||
void HandlePragmaModuleBuild(Token &Tok);
|
||||
void HandlePragmaHdrstop(Token &Tok);
|
||||
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
|
||||
|
||||
// Return true and store the first token only if any CommentHandler
|
||||
|
|
|
@ -54,6 +54,16 @@ public:
|
|||
/// definitions and expansions.
|
||||
bool DetailedRecord = false;
|
||||
|
||||
/// When true, we are creating or using a PCH where a #pragma hdrstop is
|
||||
/// expected to indicate the beginning or end of the PCH.
|
||||
bool PCHWithHdrStop = false;
|
||||
|
||||
/// When true, we are creating a PCH or creating the PCH object while
|
||||
/// expecting a #pragma hdrstop to separate the two. Allow for a
|
||||
/// missing #pragma hdrstop, which generates a PCH for the whole file,
|
||||
/// and creates an empty PCH object.
|
||||
bool PCHWithHdrStopCreate = false;
|
||||
|
||||
/// If non-empty, the filename used in an #include directive in the primary
|
||||
/// source file (or command-line preinclude) that is used to implement
|
||||
/// MSVC-style precompiled headers. When creating a PCH, after the #include
|
||||
|
|
|
@ -2982,22 +2982,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
|
|||
}
|
||||
}
|
||||
|
||||
// Diagnose unsupported forms of /Yc /Yu. Ignore /Yc/Yu for now if:
|
||||
// * no filename after it
|
||||
// * both /Yc and /Yu passed but with different filenames
|
||||
// * corresponding file not also passed as /FI
|
||||
// Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames.
|
||||
Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc);
|
||||
Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu);
|
||||
if (YcArg && YcArg->getValue()[0] == '\0') {
|
||||
Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YcArg->getSpelling();
|
||||
Args.eraseArg(options::OPT__SLASH_Yc);
|
||||
YcArg = nullptr;
|
||||
}
|
||||
if (YuArg && YuArg->getValue()[0] == '\0') {
|
||||
Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YuArg->getSpelling();
|
||||
Args.eraseArg(options::OPT__SLASH_Yu);
|
||||
YuArg = nullptr;
|
||||
}
|
||||
if (YcArg && YuArg && strcmp(YcArg->getValue(), YuArg->getValue()) != 0) {
|
||||
Diag(clang::diag::warn_drv_ycyu_different_arg_clang_cl);
|
||||
Args.eraseArg(options::OPT__SLASH_Yc);
|
||||
|
@ -4279,11 +4266,11 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const {
|
|||
// extension of .pch is assumed. "
|
||||
if (!llvm::sys::path::has_extension(Output))
|
||||
Output += ".pch";
|
||||
} else if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc)) {
|
||||
Output = YcArg->getValue();
|
||||
llvm::sys::path::replace_extension(Output, ".pch");
|
||||
} else {
|
||||
Output = BaseName;
|
||||
if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc))
|
||||
Output = YcArg->getValue();
|
||||
if (Output.empty())
|
||||
Output = BaseName;
|
||||
llvm::sys::path::replace_extension(Output, ".pch");
|
||||
}
|
||||
return Output.str();
|
||||
|
|
|
@ -1105,10 +1105,19 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
|
|||
StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue();
|
||||
if (!isa<PrecompileJobAction>(JA)) {
|
||||
CmdArgs.push_back("-include-pch");
|
||||
CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(C, ThroughHeader)));
|
||||
CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(
|
||||
C, !ThroughHeader.empty()
|
||||
? ThroughHeader
|
||||
: llvm::sys::path::filename(Inputs[0].getBaseInput()))));
|
||||
}
|
||||
|
||||
if (ThroughHeader.empty()) {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
Twine("-pch-through-hdrstop-") + (YcArg ? "create" : "use")));
|
||||
} else {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader));
|
||||
}
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2862,6 +2862,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
|||
frontend::ActionKind Action) {
|
||||
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
|
||||
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
|
||||
Opts.PCHWithHdrStop = Args.hasArg(OPT_pch_through_hdrstop_create) ||
|
||||
Args.hasArg(OPT_pch_through_hdrstop_use);
|
||||
Opts.PCHWithHdrStopCreate = Args.hasArg(OPT_pch_through_hdrstop_create);
|
||||
Opts.PCHThroughHeader = Args.getLastArgValue(OPT_pch_through_header_EQ);
|
||||
if (const Arg *A = Args.getLastArg(OPT_token_cache))
|
||||
Opts.TokenCache = A->getValue();
|
||||
|
|
|
@ -887,18 +887,29 @@ private:
|
|||
bool save;
|
||||
};
|
||||
|
||||
/// Process a directive while looking for the through header.
|
||||
/// Only #include (to check if it is the through header) and #define (to warn
|
||||
/// about macros that don't match the PCH) are handled. All other directives
|
||||
/// are completely discarded.
|
||||
void Preprocessor::HandleSkippedThroughHeaderDirective(Token &Result,
|
||||
/// Process a directive while looking for the through header or a #pragma
|
||||
/// hdrstop. The following directives are handled:
|
||||
/// #include (to check if it is the through header)
|
||||
/// #define (to warn about macros that don't match the PCH)
|
||||
/// #pragma (to check for pragma hdrstop).
|
||||
/// All other directives are completely discarded.
|
||||
void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result,
|
||||
SourceLocation HashLoc) {
|
||||
if (const IdentifierInfo *II = Result.getIdentifierInfo()) {
|
||||
if (II->getPPKeywordID() == tok::pp_include)
|
||||
return HandleIncludeDirective(HashLoc, Result);
|
||||
if (II->getPPKeywordID() == tok::pp_define)
|
||||
if (II->getPPKeywordID() == tok::pp_define) {
|
||||
return HandleDefineDirective(Result,
|
||||
/*ImmediatelyAfterHeaderGuard=*/false);
|
||||
}
|
||||
if (SkippingUntilPCHThroughHeader &&
|
||||
II->getPPKeywordID() == tok::pp_include) {
|
||||
return HandleIncludeDirective(HashLoc, Result);
|
||||
}
|
||||
if (SkippingUntilPragmaHdrStop && II->getPPKeywordID() == tok::pp_pragma) {
|
||||
Token P = LookAhead(0);
|
||||
auto *II = P.getIdentifierInfo();
|
||||
if (II && II->getName() == "hdrstop")
|
||||
return HandlePragmaDirective(HashLoc, PIK_HashPragma);
|
||||
}
|
||||
}
|
||||
DiscardUntilEndOfDirective();
|
||||
}
|
||||
|
@ -964,8 +975,8 @@ void Preprocessor::HandleDirective(Token &Result) {
|
|||
// and reset to previous state when returning from this function.
|
||||
ResetMacroExpansionHelper helper(this);
|
||||
|
||||
if (SkippingUntilPCHThroughHeader)
|
||||
return HandleSkippedThroughHeaderDirective(Result, SavedHash.getLocation());
|
||||
if (SkippingUntilPCHThroughHeader || SkippingUntilPragmaHdrStop)
|
||||
return HandleSkippedDirectiveWhileUsingPCH(Result, SavedHash.getLocation());
|
||||
|
||||
switch (Result.getKind()) {
|
||||
case tok::eod:
|
||||
|
|
|
@ -876,6 +876,37 @@ void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
|
|||
StringRef(Start, End - Start));
|
||||
}
|
||||
|
||||
void Preprocessor::HandlePragmaHdrstop(Token &Tok) {
|
||||
Lex(Tok);
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
Diag(Tok.getLocation(), diag::warn_pp_hdrstop_filename_ignored);
|
||||
|
||||
std::string FileName;
|
||||
if (!LexStringLiteral(Tok, FileName, "pragma hdrstop", false))
|
||||
return;
|
||||
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
Diag(Tok, diag::err_expected) << tok::r_paren;
|
||||
return;
|
||||
}
|
||||
Lex(Tok);
|
||||
}
|
||||
if (Tok.isNot(tok::eod))
|
||||
Diag(Tok.getLocation(), diag::ext_pp_extra_tokens_at_eol)
|
||||
<< "pragma hdrstop";
|
||||
|
||||
if (creatingPCHWithPragmaHdrStop() &&
|
||||
SourceMgr.isInMainFile(Tok.getLocation())) {
|
||||
assert(CurLexer && "no lexer for #pragma hdrstop processing");
|
||||
Token &Result = Tok;
|
||||
Result.startToken();
|
||||
CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
|
||||
CurLexer->cutOffLexing();
|
||||
}
|
||||
if (usingPCHWithPragmaHdrStop())
|
||||
SkippingUntilPragmaHdrStop = false;
|
||||
}
|
||||
|
||||
/// 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".
|
||||
|
@ -1220,6 +1251,15 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// "\#pragma hdrstop [<header-name-string>]"
|
||||
struct PragmaHdrstopHandler : public PragmaHandler {
|
||||
PragmaHdrstopHandler() : PragmaHandler("hdrstop") {}
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &DepToken) override {
|
||||
PP.HandlePragmaHdrstop(DepToken);
|
||||
}
|
||||
};
|
||||
|
||||
/// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's
|
||||
/// diagnostics, so we don't really implement this pragma. We parse it and
|
||||
/// ignore it to avoid -Wunknown-pragma warnings.
|
||||
|
@ -1799,6 +1839,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
|||
if (LangOpts.MicrosoftExt) {
|
||||
AddPragmaHandler(new PragmaWarningHandler());
|
||||
AddPragmaHandler(new PragmaIncludeAliasHandler());
|
||||
AddPragmaHandler(new PragmaHdrstopHandler());
|
||||
}
|
||||
|
||||
// Pragmas added by plugins
|
||||
|
|
|
@ -149,6 +149,10 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
|
|||
Ident_AbnormalTermination = nullptr;
|
||||
}
|
||||
|
||||
// If using a PCH where a #pragma hdrstop is expected, start skipping tokens.
|
||||
if (usingPCHWithPragmaHdrStop())
|
||||
SkippingUntilPragmaHdrStop = true;
|
||||
|
||||
// If using a PCH with a through header, start skipping tokens.
|
||||
if (!this->PPOpts->PCHThroughHeader.empty() &&
|
||||
!this->PPOpts->ImplicitPCHInclude.empty())
|
||||
|
@ -576,8 +580,9 @@ void Preprocessor::EnterMainSourceFile() {
|
|||
}
|
||||
|
||||
// Skip tokens from the Predefines and if needed the main file.
|
||||
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader)
|
||||
SkipTokensUntilPCHThroughHeader();
|
||||
if ((usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) ||
|
||||
(usingPCHWithPragmaHdrStop() && SkippingUntilPragmaHdrStop))
|
||||
SkipTokensWhileUsingPCH();
|
||||
}
|
||||
|
||||
void Preprocessor::setPCHThroughHeaderFileID(FileID FID) {
|
||||
|
@ -602,12 +607,23 @@ bool Preprocessor::usingPCHWithThroughHeader() {
|
|||
PCHThroughHeaderFileID.isValid();
|
||||
}
|
||||
|
||||
/// Skip tokens until after the #include of the through header.
|
||||
/// Tokens in the predefines file and the main file may be skipped. If the end
|
||||
/// of the predefines file is reached, skipping continues into the main file.
|
||||
/// If the end of the main file is reached, it's a fatal error.
|
||||
void Preprocessor::SkipTokensUntilPCHThroughHeader() {
|
||||
bool Preprocessor::creatingPCHWithPragmaHdrStop() {
|
||||
return TUKind == TU_Prefix && PPOpts->PCHWithHdrStop;
|
||||
}
|
||||
|
||||
bool Preprocessor::usingPCHWithPragmaHdrStop() {
|
||||
return TUKind != TU_Prefix && PPOpts->PCHWithHdrStop;
|
||||
}
|
||||
|
||||
/// Skip tokens until after the #include of the through header or
|
||||
/// until after a #pragma hdrstop is seen. Tokens in the predefines file
|
||||
/// and the main file may be skipped. If the end of the predefines file
|
||||
/// is reached, skipping continues into the main file. If the end of the
|
||||
/// main file is reached, it's a fatal error.
|
||||
void Preprocessor::SkipTokensWhileUsingPCH() {
|
||||
bool ReachedMainFileEOF = false;
|
||||
bool UsingPCHThroughHeader = SkippingUntilPCHThroughHeader;
|
||||
bool UsingPragmaHdrStop = SkippingUntilPragmaHdrStop;
|
||||
Token Tok;
|
||||
while (true) {
|
||||
bool InPredefines = (CurLexer->getFileID() == getPredefinesFileID());
|
||||
|
@ -616,12 +632,18 @@ void Preprocessor::SkipTokensUntilPCHThroughHeader() {
|
|||
ReachedMainFileEOF = true;
|
||||
break;
|
||||
}
|
||||
if (!SkippingUntilPCHThroughHeader)
|
||||
if (UsingPCHThroughHeader && !SkippingUntilPCHThroughHeader)
|
||||
break;
|
||||
if (UsingPragmaHdrStop && !SkippingUntilPragmaHdrStop)
|
||||
break;
|
||||
}
|
||||
if (ReachedMainFileEOF)
|
||||
Diag(SourceLocation(), diag::err_pp_through_header_not_seen)
|
||||
<< PPOpts->PCHThroughHeader << 1;
|
||||
if (ReachedMainFileEOF) {
|
||||
if (UsingPCHThroughHeader)
|
||||
Diag(SourceLocation(), diag::err_pp_through_header_not_seen)
|
||||
<< PPOpts->PCHThroughHeader << 1;
|
||||
else if (!PPOpts->PCHWithHdrStopCreate)
|
||||
Diag(SourceLocation(), diag::err_pp_pragma_hdrstop_not_seen);
|
||||
}
|
||||
}
|
||||
|
||||
void Preprocessor::replayPreambleConditionalStack() {
|
||||
|
|
|
@ -141,26 +141,26 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
|
|||
CleanupParser(ParseOP.get());
|
||||
|
||||
S.getPreprocessor().EnterMainSourceFile();
|
||||
if (!S.getPreprocessor().getCurrentLexer()) {
|
||||
// If a PCH through header is specified that does not have an include in
|
||||
// the source, there won't be any tokens or a Lexer.
|
||||
return;
|
||||
}
|
||||
|
||||
P.Initialize();
|
||||
|
||||
Parser::DeclGroupPtrTy ADecl;
|
||||
ExternalASTSource *External = S.getASTContext().getExternalSource();
|
||||
if (External)
|
||||
External->StartTranslationUnit(Consumer);
|
||||
|
||||
for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
|
||||
AtEOF = P.ParseTopLevelDecl(ADecl)) {
|
||||
// If we got a null return and something *was* parsed, ignore it. This
|
||||
// is due to a top-level semicolon, an action override, or a parse error
|
||||
// skipping something.
|
||||
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
|
||||
return;
|
||||
// If a PCH through header is specified that does not have an include in
|
||||
// the source, or a PCH is being created with #pragma hdrstop with nothing
|
||||
// after the pragma, there won't be any tokens or a Lexer.
|
||||
bool HaveLexer = S.getPreprocessor().getCurrentLexer();
|
||||
|
||||
if (HaveLexer) {
|
||||
P.Initialize();
|
||||
Parser::DeclGroupPtrTy ADecl;
|
||||
for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
|
||||
AtEOF = P.ParseTopLevelDecl(ADecl)) {
|
||||
// If we got a null return and something *was* parsed, ignore it. This
|
||||
// is due to a top-level semicolon, an action override, or a parse error
|
||||
// skipping something.
|
||||
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Process any TopLevelDecls generated by #pragma weak.
|
||||
|
@ -179,7 +179,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
|
|||
std::swap(OldCollectStats, S.CollectStats);
|
||||
if (PrintStats) {
|
||||
llvm::errs() << "\nSTATISTICS:\n";
|
||||
P.getActions().PrintStats();
|
||||
if (HaveLexer) P.getActions().PrintStats();
|
||||
S.getASTContext().PrintStats();
|
||||
Decl::PrintStats();
|
||||
Stmt::PrintStats();
|
||||
|
|
|
@ -264,6 +264,71 @@
|
|||
// CHECK-YU-SLASH: -include
|
||||
// CHECK-YU-SLASH: ".{{[/\\]+}}pchfile.h"
|
||||
|
||||
// /Yc without an argument creates a PCH from the code before #pragma hdrstop.
|
||||
// /Yu without an argument uses a PCH and starts compiling after the
|
||||
// #pragma hdrstop.
|
||||
// RUN: %clang_cl -Werror /Yc /Fpycnoarg.pch /c -### -- %s 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-YC-NOARG %s
|
||||
// 1. Create .pch file
|
||||
// CHECK-YC-NOARG: cc1
|
||||
// CHECK-YC-NOARG: -emit-pch
|
||||
// CHECK-YC-NOARG: -pch-through-hdrstop-create
|
||||
// CHECK-YC-NOARG: -o
|
||||
// CHECK-YC-NOARG: ycnoarg.pch
|
||||
// CHECK-YC-NOARG: -x
|
||||
// CHECK-YC-NOARG: "c++-header"
|
||||
// CHECK-YC-NOARG: cl-pch.cpp
|
||||
// 2. Use .pch file: Includes ycnoarg.pch
|
||||
// CHECK-YC-NOARG: cc1
|
||||
// CHECK-YC-NOARG: -emit-obj
|
||||
// CHECK-YC-NOARG: -include-pch
|
||||
// CHECK-YC-NOARG: ycnoarg.pch
|
||||
// CHECK-YC-NOARG: -pch-through-hdrstop-create
|
||||
// CHECK-YC-NOARG: -o
|
||||
// CHECK-YC-NOARG: cl-pch.obj
|
||||
// CHECK-YC-NOARG: -x
|
||||
// CHECK-YC-NOARG: "c++"
|
||||
// CHECK-YC-NOARG: cl-pch.cpp
|
||||
|
||||
// RUN: %clang_cl -Werror /Yu /Fpycnoarg.pch /c -### -- %s 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-YU-NOARG %s
|
||||
// Use .pch file, but don't build it.
|
||||
// CHECK-YU-NOARG-NOT: -emit-pch
|
||||
// CHECK-YU-NOARG: cc1
|
||||
// CHECK-YU-NOARG: -emit-obj
|
||||
// CHECK-YU-NOARG: -include-pch
|
||||
// CHECK-YU-NOARG: ycnoarg.pch
|
||||
// CHECK-YU-NOARG: -pch-through-hdrstop-use
|
||||
// CHECK-YU-NOARG: -o
|
||||
// CHECK-YU-NOARG: cl-pch.obj
|
||||
// CHECK-YU-NOARG: -x
|
||||
// CHECK-YU-NOARG: "c++"
|
||||
// CHECK-YU-NOARG: cl-pch.cpp
|
||||
|
||||
// /Yc with no argument and no /FP
|
||||
// RUN: %clang_cl -Werror /Yc /c -### -- %s 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-YC-NOARG-NOFP %s
|
||||
// 1. Create .pch file
|
||||
// CHECK-YC-NOARG-NOFP: cc1
|
||||
// CHECK-YC-NOARG-NOFP: -emit-pch
|
||||
// CHECK-YC-NOARG-NOFP: -pch-through-hdrstop-create
|
||||
// CHECK-YC-NOARG-NOFP: -o
|
||||
// CHECK-YC-NOARG-NOFP: cl-pch.pch
|
||||
// CHECK-YC-NOARG-NOFP: -x
|
||||
// CHECK-YC-NOARG-NOFP: "c++-header"
|
||||
// CHECK-YC-NOARG-NOFP: cl-pch.cpp
|
||||
// 2. Use .pch file: Includes cl-pch.pch
|
||||
// CHECK-YC-NOARG-NOFP: cc1
|
||||
// CHECK-YC-NOARG-NOFP: -emit-obj
|
||||
// CHECK-YC-NOARG-NOFP: -include-pch
|
||||
// CHECK-YC-NOARG-NOFP: cl-pch.pch
|
||||
// CHECK-YC-NOARG-NOFP: -pch-through-hdrstop-create
|
||||
// CHECK-YC-NOARG-NOFP: -o
|
||||
// CHECK-YC-NOARG-NOFP: cl-pch.obj
|
||||
// CHECK-YC-NOARG-NOFP: -x
|
||||
// CHECK-YC-NOARG-NOFP: "c++"
|
||||
// CHECK-YC-NOARG-NOFP: cl-pch.cpp
|
||||
|
||||
// cl.exe warns on multiple /Yc, /Yu, /Fp arguments, but clang-cl silently just
|
||||
// uses the last one. This is true for e.g. /Fo too, so not warning on this
|
||||
// is self-consistent with clang-cl's flag handling.
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include "Inputs/pch-through1.h"
|
||||
static int bar() { return 42; }
|
||||
#include "Inputs/pch-through2.h"
|
||||
int pch();
|
||||
#pragma hdrstop
|
||||
|
||||
//expected-no-diagnostics
|
||||
//CHECK-NOT: FunctionDecl{{.*}}other
|
||||
//CHECK: FunctionDecl{{.*}}main
|
||||
int main()
|
||||
{
|
||||
return pch() - 42*42 + bar() - 42 + through1(0) + through2(33);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "Inputs/pch-through1.h"
|
||||
static int bar() { return 42; }
|
||||
#include "Inputs/pch-through2.h"
|
||||
int pch();
|
||||
#pragma hdrstop
|
||||
|
||||
//expected-no-diagnostics
|
||||
int main()
|
||||
{
|
||||
return pch() + through1(0) + through2(-1) + bar() - 42;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Create PCH with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -I %S -emit-pch -pch-through-hdrstop-create \
|
||||
// RUN: -fms-extensions -o %t.pch -x c++-header %s
|
||||
|
||||
// Use PCH with no #pragma hdrstop
|
||||
// RUN: not %clang_cc1 -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-use -fms-extensions -o %t.obj -x c++ %s 2>&1 \
|
||||
// RUN: | FileCheck --check-prefix=CHECK-U %s
|
||||
|
||||
#include "Inputs/pch-through1.h"
|
||||
static int bar() { return 42; }
|
||||
#include "Inputs/pch-through2.h"
|
||||
int pch();
|
||||
//CHECK-U: hdrstop not seen while attempting to use precompiled header
|
|
@ -0,0 +1,10 @@
|
|||
// Create PCH with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-pch -pch-through-hdrstop-create \
|
||||
// RUN: -fms-extensions -o %t.pch -x c++-header %s
|
||||
|
||||
// Create PCH object with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-create -fms-extensions -o %t.obj -x c++ %s
|
||||
|
||||
//expected-warning@+1{{hdrstop filename not supported}}
|
||||
#pragma hdrstop("name.pch")
|
|
@ -0,0 +1,28 @@
|
|||
// expected-no-diagnostics
|
||||
// Create PCH with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-pch -pch-through-hdrstop-create \
|
||||
// RUN: -fms-extensions -o %t.pch -x c++-header %s
|
||||
|
||||
// Create PCH object with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-create -fms-extensions -o %t.obj -x c++ %s
|
||||
|
||||
// Use PCH with #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-use -fms-extensions -o %t.obj \
|
||||
// RUN: -x c++ %S/Inputs/pch-hdrstop-use.cpp
|
||||
|
||||
// Ensure the PCH stops at the hdrstop
|
||||
// RUN: %clang_cc1 -ast-dump -I %S -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-use -fms-extensions -o %t.obj \
|
||||
// RUN: -x c++ %S/Inputs/pch-hdrstop-use.cpp 2>&1 \
|
||||
// RUN: | FileCheck %S/Inputs/pch-hdrstop-use.cpp
|
||||
|
||||
#include "Inputs/pch-through1.h"
|
||||
static int bar() { return 42; }
|
||||
#include "Inputs/pch-through2.h"
|
||||
int pch();
|
||||
#pragma hdrstop
|
||||
|
||||
int pch() { return 42*42; }
|
||||
int other() { return 42; }
|
|
@ -0,0 +1,18 @@
|
|||
// expected-no-diagnostics
|
||||
// Create PCH with #pragma hdrstop processing with no #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-pch -pch-through-hdrstop-create \
|
||||
// RUN: -fms-extensions -o %t.pch -x c++-header %s
|
||||
|
||||
// Create the PCH object
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-create -fms-extensions -o %t.obj -x c++ %s
|
||||
|
||||
// The use must still have a #pragma hdrstop
|
||||
// RUN: %clang_cc1 -verify -I %S -emit-obj -include-pch %t.pch \
|
||||
// RUN: -pch-through-hdrstop-use -fms-extensions -o %t.obj \
|
||||
// RUN: -x c++ %S/Inputs/pch-no-hdrstop-use.cpp
|
||||
|
||||
#include "Inputs/pch-through1.h"
|
||||
static int bar() { return 42; }
|
||||
#include "Inputs/pch-through2.h"
|
||||
int pch();
|
Loading…
Reference in New Issue