Skip to content

[clang][Preprocessor] Handle the first pp-token in EnterMainSourceFile #145244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,8 @@ class Preprocessor {
/// Whether the last token we lexed was an '@'.
bool LastTokenWasAt = false;

/// First pp-token in current translation unit.
std::optional<Token> FirstPPToken;
/// First pp-token source location in current translation unit.
SourceLocation FirstPPTokenLoc;

/// A position within a C++20 import-seq.
class StdCXXImportSeq {
Expand Down Expand Up @@ -1769,20 +1769,13 @@ class Preprocessor {
std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
bool ForHasEmbed);

/// Whether the preprocessor already seen the first pp-token in main file.
bool hasSeenMainFileFirstPPToken() const { return FirstPPToken.has_value(); }

/// Record first pp-token and check if it has a Token::FirstPPToken flag.
void HandleMainFileFirstPPToken(const Token &Tok) {
if (!hasSeenMainFileFirstPPToken() && Tok.isFirstPPToken() &&
SourceMgr.isWrittenInMainFile(Tok.getLocation()))
FirstPPToken = Tok;
/// Get the start location of the first pp-token in main file.
SourceLocation getMainFileFirstPPTokenLoc() const {
assert(FirstPPTokenLoc.isValid() &&
"Did not see the first pp-token in the main file");
return FirstPPTokenLoc;
}

Token getMainFileFirstPPToken() const {
assert(FirstPPToken && "First main file pp-token doesn't exists");
return *FirstPPToken;
}
bool LexAfterModuleImport(Token &Result);
void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);

Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Lex/TokenLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ class TokenLexer {
void Init(const Token *TokArray, unsigned NumToks, bool DisableMacroExpansion,
bool OwnsTokens, bool IsReinject);

/// If the next token lexed will pop this macro off the expansion stack,
/// return std::nullopt, otherwise return the next unexpanded token.
/// If TokenLexer::isAtEnd returns true(the next token lexed will pop this
/// macro off the expansion stack), return std::nullopt, otherwise return the
/// next unexpanded token.
std::optional<Token> peekNextPPToken() const;

/// Lex and return a token from this macro stream.
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3228,6 +3228,7 @@ std::optional<Token> Lexer::peekNextPPToken() {
bool atStartOfLine = IsAtStartOfLine;
bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
bool leadingSpace = HasLeadingSpace;
bool isFirstPPToken = IsFirstPPToken;

Token Tok;
Lex(Tok);
Expand All @@ -3238,7 +3239,7 @@ std::optional<Token> Lexer::peekNextPPToken() {
HasLeadingSpace = leadingSpace;
IsAtStartOfLine = atStartOfLine;
IsAtPhysicalStartOfLine = atPhysicalStartOfLine;

IsFirstPPToken = isFirstPPToken;
// Restore the lexer back to non-skipping mode.
LexingRawMode = false;

Expand Down Expand Up @@ -3740,10 +3741,6 @@ bool Lexer::Lex(Token &Result) {
bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine);
// (After the LexTokenInternal call, the lexer might be destroyed.)
assert((returnedToken || !isRawLex) && "Raw lex must succeed");

if (returnedToken && Result.isFirstPPToken() && PP &&
!PP->hasSeenMainFileFirstPPToken())
PP->HandleMainFileFirstPPToken(Result);
return returnedToken;
}

Expand Down Expand Up @@ -4547,8 +4544,6 @@ const char *Lexer::convertDependencyDirectiveToken(
Result.setFlag((Token::TokenFlags)DDTok.Flags);
Result.setLength(DDTok.Length);
BufferPtr = TokPtr + DDTok.Length;
if (PP && !PP->hasSeenMainFileFirstPPToken() && Result.isFirstPPToken())
PP->HandleMainFileFirstPPToken(Result);
return TokPtr;
}

Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1242,9 +1242,6 @@ void Preprocessor::HandleDirective(Token &Result) {
// pp-directive.
bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal();

if (!hasSeenMainFileFirstPPToken())
HandleMainFileFirstPPToken(Result);

// Save the '#' token in case we need to return it later.
Token SavedHash = Result;

Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Lex/PPMacroExpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// to disable the optimization in this case.
if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro();

if (!hasSeenMainFileFirstPPToken())
HandleMainFileFirstPPToken(Identifier);

// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
if (MI->isBuiltinMacro()) {
if (Callbacks)
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Lex/Preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,21 @@ void Preprocessor::EnterMainSourceFile() {
// #imported, it won't be re-entered.
if (OptionalFileEntryRef FE = SourceMgr.getFileEntryRefForID(MainFileID))
markIncluded(*FE);

// Record the first PP token in the main file. This is used to generate
// better diagnostics for C++ modules.
//
// // This is a comment.
// #define FOO int // note: add 'module;' to the start of the file
// ^ FirstPPToken // to introduce a global module fragment.
//
// export module M; // error: module declaration must occur
// // at the start of the translation unit.
if (getLangOpts().CPlusPlusModules) {
std::optional<Token> FirstPPTok = CurLexer->peekNextPPToken();
if (FirstPPTok && FirstPPTok->isFirstPPToken())
FirstPPTokenLoc = FirstPPTok->getLocation();
}
}

// Preprocess Predefines to populate the initial preprocessor state.
Expand Down
8 changes: 3 additions & 5 deletions clang/lib/Sema/SemaModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,9 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// tokens in a file (excluding the global module fragment.).
if (getLangOpts().CPlusPlusModules && !IntroducerIsFirstPPToken && !SeenGMF) {
Diag(ModuleLoc, diag::err_module_decl_not_at_start);
SourceLocation BeginLoc = PP.getMainFileFirstPPToken().getLocation();
if (BeginLoc.isValid()) {
Diag(BeginLoc, diag::note_global_module_introducer_missing)
<< FixItHint::CreateInsertion(BeginLoc, "module;\n");
}
SourceLocation BeginLoc = PP.getMainFileFirstPPTokenLoc();
Diag(BeginLoc, diag::note_global_module_introducer_missing)
<< FixItHint::CreateInsertion(BeginLoc, "module;\n");
}

// C++23 [module.unit]p1: ... The identifiers module and import shall not
Expand Down
34 changes: 19 additions & 15 deletions clang/unittests/Lex/LexerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ class LexerTest : public ::testing::Test {
}

std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
TrivialModuleLoader &ModLoader,
StringRef PreDefines = {}) {
TrivialModuleLoader &ModLoader) {
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(Source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
Expand All @@ -63,7 +62,7 @@ class LexerTest : public ::testing::Test {
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
if (!PreDefines.empty())
PP->setPredefines(PreDefines.str());
PP->setPredefines(PreDefines);
PP->Initialize(*Target);
PP->EnterMainSourceFile();
return PP;
Expand Down Expand Up @@ -111,6 +110,7 @@ class LexerTest : public ::testing::Test {
std::shared_ptr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
std::unique_ptr<Preprocessor> PP;
std::string PreDefines;
};

TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) {
Expand Down Expand Up @@ -773,6 +773,7 @@ TEST(LexerPreambleTest, PreambleBounds) {
}

TEST_F(LexerTest, CheckFirstPPToken) {
LangOpts.CPlusPlusModules = true;
{
TrivialModuleLoader ModLoader;
auto PP = CreatePP("// This is a comment\n"
Expand All @@ -781,9 +782,8 @@ TEST_F(LexerTest, CheckFirstPPToken) {
Token Tok;
PP->Lex(Tok);
EXPECT_TRUE(Tok.is(tok::kw_int));
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::kw_int));
EXPECT_TRUE(PP->getMainFileFirstPPTokenLoc().isValid());
EXPECT_EQ(PP->getMainFileFirstPPTokenLoc(), Tok.getLocation());
}
{
TrivialModuleLoader ModLoader;
Expand All @@ -794,24 +794,28 @@ TEST_F(LexerTest, CheckFirstPPToken) {
Token Tok;
PP->Lex(Tok);
EXPECT_TRUE(Tok.is(tok::kw_int));
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::hash));
EXPECT_FALSE(Lexer::getRawToken(PP->getMainFileFirstPPTokenLoc(), Tok,
PP->getSourceManager(), PP->getLangOpts(),
/*IgnoreWhiteSpace=*/false));
EXPECT_TRUE(Tok.isFirstPPToken());
EXPECT_TRUE(Tok.is(tok::hash));
}

{
PreDefines = "#define FOO int\n";
TrivialModuleLoader ModLoader;
auto PP = CreatePP("// This is a comment\n"
"FOO a;",
ModLoader, "#define FOO int\n");
ModLoader);
Token Tok;
PP->Lex(Tok);
EXPECT_TRUE(Tok.is(tok::kw_int));
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::identifier));
EXPECT_TRUE(
PP->getMainFileFirstPPToken().getIdentifierInfo()->isStr("FOO"));
EXPECT_FALSE(Lexer::getRawToken(PP->getMainFileFirstPPTokenLoc(), Tok,
PP->getSourceManager(), PP->getLangOpts(),
/*IgnoreWhiteSpace=*/false));
EXPECT_TRUE(Tok.isFirstPPToken());
EXPECT_TRUE(Tok.is(tok::raw_identifier));
EXPECT_TRUE(Tok.getRawIdentifier() == "FOO");
}
}
} // anonymous namespace