Skip to content

[Clang] Implement P3034R1 Module Declarations Shouldn’t be Macros #90574

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

Merged
merged 27 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1dcb4c3
[Clang] Implement P3034R1 Module Declarations Shouldn’t be Macros
yronglin Apr 30, 2024
0b472f2
Use split-file in test and improve implementation
yronglin May 3, 2024
fd75d83
Format
yronglin May 3, 2024
265189b
Do not treat no '(' following function-like macro as a macro name
yronglin May 3, 2024
1f44657
Merge branch 'main' into P3034R1
yronglin May 3, 2024
611e1d8
Add new line at the end of file
yronglin May 3, 2024
224e1d0
Move implementation to Preprocessor
yronglin May 6, 2024
8ff13ca
Remove dead code
yronglin May 6, 2024
bb4a923
Add more test
yronglin May 6, 2024
597b6a1
Fix test
yronglin May 6, 2024
b3e843b
Address review comments
yronglin May 8, 2024
ed0e90b
Address review comments
yronglin May 11, 2024
890a769
Merge branch 'main' into P3034R1
yronglin May 11, 2024
45d40a0
Skip unexpect tokens in parser
yronglin May 29, 2024
0155137
Merge branch 'main' into P3034R1
yronglin Jun 19, 2024
9690140
Introduce annot_module_name token and refactor module name lexcial an…
yronglin Jun 20, 2024
ff95c74
Merge branch 'main' into P3034R1
yronglin Jun 20, 2024
bb4c89f
Fix clang-repl lit issue
yronglin Jun 22, 2024
e22a353
Remove unused vars
yronglin Jun 23, 2024
514450f
Merge branch 'main' into P3034R1
yronglin Jul 11, 2024
fde07d7
Update clang/include/clang/Basic/IdentifierTable.h
AaronBallman Jul 12, 2024
6eb51ee
Address review comments
yronglin Jul 11, 2024
00d5aa9
Add a comment to explain changes in TokenConcatenation::AvoidConcat
yronglin Jul 13, 2024
f21af27
[Clang] Lexing the partition along with the module name
yronglin Jul 17, 2024
93a4041
Merge branch 'main' into P3034R1
yronglin Jul 17, 2024
f4adc54
Format
yronglin Jul 17, 2024
f4dc73e
[Clang] Add more comments and remove token handling in Preprocessor::Lex
yronglin Jul 18, 2024
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
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ C++2c Feature Support

- Implemented `P2963R3 Ordering of constraints involving fold expressions <https://wg21.link/P2963R3>`_.

- Implemented `P3034R1 Module Declarations Shouldn’t be Macros <https://wg21.link/P3034R1>`_.


Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,11 @@ def warn_module_conflict : Warning<
InGroup<ModuleConflict>;

// C++20 modules
def err_module_decl_cannot_be_macros : Error<
"the module name in a module%select{| partition}0 declaration cannot contain "
"an object-like macro %1">;
def err_unxepected_paren_in_module_decl : Error<
"unexpected '(' after the module name in a module%select{| partition}0 declaration">;
def err_header_import_semi_in_macro : Error<
"semicolon terminating header import declaration cannot be produced "
"by a macro">;
Expand Down
24 changes: 21 additions & 3 deletions clang/include/clang/Basic/IdentifierTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned IsModulesImport : 1;

// True if this is the 'module' contextual keyword.
LLVM_PREFERRED_TYPE(bool)
unsigned IsModulesDecl : 1;

// True if this is a mangled OpenMP variant name.
LLVM_PREFERRED_TYPE(bool)
unsigned IsMangledOpenMPVariantName : 1;
Expand All @@ -196,7 +200,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned IsFinal : 1;

// 22 bits left in a 64-bit word.
// 21 bits left in a 64-bit word.

// Managed by the language front-end.
void *FETokenInfo = nullptr;
Expand All @@ -212,8 +216,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false),
IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false),
RevertedTokenID(false), OutOfDate(false), IsModulesImport(false),
IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
IsRestrictExpansion(false), IsFinal(false) {}
IsModulesDecl(false), IsMangledOpenMPVariantName(false),
IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {}

public:
IdentifierInfo(const IdentifierInfo &) = delete;
Expand Down Expand Up @@ -520,6 +524,18 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
RecomputeNeedsHandleIdentifier();
}

/// Determine whether this is the contextual keyword \c module.
bool isModulesDeclaration() const { return IsModulesDecl; }

/// Set whether this identifier is the contextual keyword \c module.
void setModulesDeclaration(bool I) {
IsModulesDecl = I;
if (I)
NeedsHandleIdentifier = true;
else
RecomputeNeedsHandleIdentifier();
}

/// Determine whether this is the mangled name of an OpenMP variant.
bool isMangledOpenMPVariantName() const { return IsMangledOpenMPVariantName; }

Expand Down Expand Up @@ -740,6 +756,8 @@ class IdentifierTable {
// If this is the 'import' contextual keyword, mark it as such.
if (Name == "import")
II->setModulesImport(true);
else if (Name == "module")
II->setModulesDeclaration(true);

return *II;
}
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,9 @@ ANNOTATION(module_include)
ANNOTATION(module_begin)
ANNOTATION(module_end)

// Annotations for C++, Clang and Objective-C named modules.
ANNOTATION(module_name)

// Annotation for a header_name token that has been looked up and transformed
// into the name of a header unit.
ANNOTATION(header_unit)
Expand Down
83 changes: 78 additions & 5 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,10 +615,6 @@ class Preprocessor {

ModuleDeclSeq ModuleDeclState;

/// Whether the module import expects an identifier next. Otherwise,
/// it expects a '.' or ';'.
bool ModuleImportExpectsIdentifier = false;

/// The identifier and source location of the currently-active
/// \#pragma clang arc_cf_code_audited begin.
std::pair<IdentifierInfo *, SourceLocation> PragmaARCCFCodeAuditedInfo;
Expand Down Expand Up @@ -1744,11 +1740,14 @@ class Preprocessor {
/// Lex a token, forming a header-name token if possible.
bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);

/// Lex a module name or a partition name.
bool LexModuleName(Token &Result, bool IsImport);

/// Lex the parameters for an #embed directive, returns nullopt on error.
std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
bool ForHasEmbed);

bool LexAfterModuleImport(Token &Result);
bool LexAfterModuleDecl(Token &Result);
void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);

void makeModuleVisible(Module *M, SourceLocation Loc);
Expand Down Expand Up @@ -3039,6 +3038,9 @@ class Preprocessor {
static bool CLK_LexAfterModuleImport(Preprocessor &P, Token &Result) {
return P.LexAfterModuleImport(Result);
}
static bool CLK_LexAfterModuleDecl(Preprocessor &P, Token &Result) {
return P.LexAfterModuleDecl(Result);
}
};

/// Abstract base class that describes a handler that will receive
Expand Down Expand Up @@ -3071,6 +3073,77 @@ struct EmbedAnnotationData {
/// Registry of pragma handlers added by plugins
using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;

/// Represents module or partition name token sequance.
///
/// module-name:
/// module-name-qualifier[opt] identifier
///
/// partition-name: [C++20]
/// : module-name-qualifier[opt] identifier
///
/// module-name-qualifier
/// module-name-qualifier[opt] identifier .
///
/// This class can only be created by the preprocessor and guarantees that the
/// two source array being contiguous in memory and only contains 3 kind of
/// tokens (identifier, '.' and ':'). And only available when the preprocessor
/// returns annot_module_name token.
///
/// For exmaple:
///
/// export module m.n:c.d
///
/// The module name array has 3 tokens ['m', '.', 'n'].
/// The partition name array has 4 tokens [':', 'c', '.', 'd'].
///
/// When import a partition in a named module fragment (Eg. import :part1;),
/// the module name array will be empty, and the partition name array has 2
/// tokens.
///
/// When we meet a private-module-fragment (Eg. module :private;), preprocessor
/// will not return a annot_module_name token, but will return 2 separate tokens
/// [':', 'kw_private'].

class ModuleNameInfo {
friend class Preprocessor;
ArrayRef<Token> ModuleName;
ArrayRef<Token> PartitionName;

ModuleNameInfo(ArrayRef<Token> AnnotToks, std::optional<unsigned> ColonIndex);

public:
/// Return the contiguous token array.
ArrayRef<Token> getTokens() const {
if (ModuleName.empty())
return PartitionName;
if (PartitionName.empty())
return ModuleName;
return ArrayRef(ModuleName.begin(), PartitionName.end());
}
bool hasModuleName() const { return !ModuleName.empty(); }
bool hasPartitionName() const { return !PartitionName.empty(); }
ArrayRef<Token> getModuleName() const { return ModuleName; }
ArrayRef<Token> getPartitionName() const { return PartitionName; }
Token getColonToken() const {
assert(hasPartitionName() && "Do not have a partition name");
return getPartitionName().front();
}

/// Under the standard C++ Modules, the dot is just part of the module name,
/// and not a real hierarchy separator. Flatten such module names now.
std::string getFlatName() const;

/// Build a module id path from the contiguous token array, both include
/// module name and partition name.
void getModuleIdPath(
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path) const;

/// Build a module id path from \param ModuleName.
static void getModuleIdPath(
ArrayRef<Token> ModuleName,
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path);
};

} // namespace clang

#endif // LLVM_CLANG_LEX_PREPROCESSOR_H
3 changes: 3 additions & 0 deletions clang/include/clang/Lex/Token.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ class Token {
assert(isAnnotation() && "Used AnnotVal on non-annotation token");
return PtrData;
}
template <class T> T getAnnotationValueAs() const {
return static_cast<T>(getAnnotationValue());
}
void setAnnotationValue(void *val) {
assert(isAnnotation() && "Used AnnotVal on non-annotation token");
PtrData = val;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3876,7 +3876,7 @@ class Parser : public CodeCompletionHandler {
}

bool ParseModuleName(
SourceLocation UseLoc,
SourceLocation UseLoc, ArrayRef<Token> ModuleName,
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
bool IsImport);

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,9 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
if (LangOpts.IEEE128)
AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);

// Add the 'import' contextual keyword.
// Add the 'import' and 'module' contextual keyword.
get("import").setModulesImport(true);
get("module").setModulesDeclaration(true);
}

/// Checks if the specified token kind represents a keyword in the
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/Frontend/PrintPreprocessedOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -758,9 +758,10 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok,
// These tokens are not expanded to anything and don't need whitespace before
// them.
if (Tok.is(tok::eof) ||
(Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) &&
!Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) &&
!Tok.is(tok::annot_repl_input_end) && !Tok.is(tok::annot_embed)))
(Tok.isAnnotation() && Tok.isNot(tok::annot_header_unit) &&
Tok.isNot(tok::annot_module_begin) && Tok.isNot(tok::annot_module_end) &&
Tok.isNot(tok::annot_module_name) &&
Tok.isNot(tok::annot_repl_input_end) && Tok.isNot(tok::annot_embed)))
return;

// EmittedDirectiveOnThisLine takes priority over RequireSameLine.
Expand Down Expand Up @@ -951,6 +952,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PP.Lex(Tok);
IsStartOfLine = true;
continue;
} else if (Tok.is(tok::annot_module_name)) {
auto *Info = static_cast<ModuleNameInfo *>(Tok.getAnnotationValue());
*Callbacks->OS << Info->getFlatName();
PP.Lex(Tok);
continue;
} else if (Tok.is(tok::annot_header_unit)) {
// This is a header-name that has been (effectively) converted into a
// module-name.
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Lex/PPLexerChange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
CurPPLexer = TheLexer;
CurDirLookup = CurDir;
CurLexerSubmodule = nullptr;
if (CurLexerCallback != CLK_LexAfterModuleImport)
if (CurLexerCallback != CLK_LexAfterModuleImport &&
CurLexerCallback != CLK_LexAfterModuleDecl)
CurLexerCallback = TheLexer->isDependencyDirectivesLexer()
? CLK_DependencyDirectivesLexer
: CLK_Lexer;
Expand Down Expand Up @@ -161,8 +162,7 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
PushIncludeMacroStack();
CurDirLookup = nullptr;
CurTokenLexer = std::move(TokLexer);
if (CurLexerCallback != CLK_LexAfterModuleImport)
CurLexerCallback = CLK_TokenLexer;
CurLexerCallback = CLK_TokenLexer;
}

/// EnterTokenStream - Add a "macro" context to the top of the include stack,
Expand Down Expand Up @@ -216,7 +216,8 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
PushIncludeMacroStack();
CurDirLookup = nullptr;
CurTokenLexer = std::move(TokLexer);
if (CurLexerCallback != CLK_LexAfterModuleImport)
if (CurLexerCallback != CLK_LexAfterModuleImport &&
CurLexerCallback != CLK_LexAfterModuleDecl)
CurLexerCallback = CLK_TokenLexer;
}

Expand Down
Loading