Skip to content

Commit d300a2b

Browse files
committed
[C++20][Modules] Implement P1857R3 Modules Dependency Discovery
Signed-off-by: yronglin <[email protected]>
1 parent 2cce3d1 commit d300a2b

File tree

40 files changed

+1311
-652
lines changed

40 files changed

+1311
-652
lines changed

clang/examples/AnnotateFunctions/AnnotateFunctions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class PragmaAnnotateHandler : public PragmaHandler {
6565
Token Tok;
6666
PP.LexUnexpandedToken(Tok);
6767
if (Tok.isNot(tok::eod))
68-
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
68+
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "#pragma";
6969

7070
if (HandledDecl) {
7171
DiagnosticsEngine &D = PP.getDiagnostics();

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ def err_pp_embed_device_file : Error<
466466

467467
def ext_pp_extra_tokens_at_eol : ExtWarn<
468468
"extra tokens at end of #%0 directive">, InGroup<ExtraTokens>;
469+
def ext_pp_extra_tokens_at_module_directive_eol : ExtWarn<
470+
"extra tokens at end of '%0' directive">, InGroup<ExtraTokens>;
469471

470472
def ext_pp_comma_expr : Extension<"comma operator in operand of #if">;
471473
def ext_pp_bad_vaargs_use : Extension<
@@ -496,7 +498,7 @@ def warn_cxx98_compat_variadic_macro : Warning<
496498
def ext_named_variadic_macro : Extension<
497499
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
498500
def err_embedded_directive : Error<
499-
"embedding a #%0 directive within macro arguments is not supported">;
501+
"embedding a %select{#|C++ }0%1 directive within macro arguments is not supported">;
500502
def ext_embedded_directive : Extension<
501503
"embedding a directive within macro arguments has undefined behavior">,
502504
InGroup<DiagGroup<"embedded-directive">>;
@@ -983,6 +985,18 @@ def warn_module_conflict : Warning<
983985
InGroup<ModuleConflict>;
984986

985987
// C++20 modules
988+
def err_pp_expected_module_name_or_header_name : Error<
989+
"expected module name or header name">;
990+
def err_pp_expected_semi_after_module_or_import : Error<
991+
"'%select{module|import}0' directive must end with a ';' on the same line">;
992+
def err_module_decl_in_header : Error<
993+
"module declaration must not come from an #include directive">;
994+
def err_pp_cond_span_module_decl : Error<
995+
"preprocessor conditionals shall not span a module declaration">;
996+
def err_pp_module_expected_ident : Error<
997+
"expected a module name after '%select{module|import}0'">;
998+
def err_pp_unsupported_module_partition : Error<
999+
"module partitions are only supported for C++20 onwards">;
9861000
def err_header_import_semi_in_macro : Error<
9871001
"semicolon terminating header import declaration cannot be produced "
9881002
"by a macro">;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,8 +1760,8 @@ def ext_bit_int : Extension<
17601760
} // end of Parse Issue category.
17611761

17621762
let CategoryName = "Modules Issue" in {
1763-
def err_unexpected_module_decl : Error<
1764-
"module declaration can only appear at the top level">;
1763+
def err_unexpected_module_import_decl : Error<
1764+
"%select{module|import}0 declaration can only appear at the top level">;
17651765
def err_module_expected_ident : Error<
17661766
"expected a module name after '%select{module|import}0'">;
17671767
def err_attribute_not_module_attr : Error<
@@ -1782,8 +1782,6 @@ def err_module_fragment_exported : Error<
17821782
def err_private_module_fragment_expected_semi : Error<
17831783
"expected ';' after private module fragment declaration">;
17841784
def err_missing_before_module_end : Error<"expected %0 at end of module">;
1785-
def err_unsupported_module_partition : Error<
1786-
"module partitions are only supported for C++20 onwards">;
17871785
def err_import_not_allowed_here : Error<
17881786
"imports must immediately follow the module declaration">;
17891787
def err_partition_import_outside_module : Error<

clang/include/clang/Basic/IdentifierTable.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
179179
LLVM_PREFERRED_TYPE(bool)
180180
unsigned IsModulesImport : 1;
181181

182+
// True if this is the 'module' contextual keyword.
183+
LLVM_PREFERRED_TYPE(bool)
184+
unsigned IsModulesDecl : 1;
185+
182186
// True if this is a mangled OpenMP variant name.
183187
LLVM_PREFERRED_TYPE(bool)
184188
unsigned IsMangledOpenMPVariantName : 1;
@@ -215,8 +219,9 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
215219
IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false),
216220
IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false),
217221
RevertedTokenID(false), OutOfDate(false), IsModulesImport(false),
218-
IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
219-
IsRestrictExpansion(false), IsFinal(false), IsKeywordInCpp(false) {}
222+
IsModulesDecl(false), IsMangledOpenMPVariantName(false),
223+
IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false),
224+
IsKeywordInCpp(false) {}
220225

221226
public:
222227
IdentifierInfo(const IdentifierInfo &) = delete;
@@ -528,6 +533,18 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
528533
RecomputeNeedsHandleIdentifier();
529534
}
530535

536+
/// Determine whether this is the contextual keyword \c module.
537+
bool isModulesDeclaration() const { return IsModulesDecl; }
538+
539+
/// Set whether this identifier is the contextual keyword \c module.
540+
void setModulesDeclaration(bool I) {
541+
IsModulesDecl = I;
542+
if (I)
543+
NeedsHandleIdentifier = true;
544+
else
545+
RecomputeNeedsHandleIdentifier();
546+
}
547+
531548
/// Determine whether this is the mangled name of an OpenMP variant.
532549
bool isMangledOpenMPVariantName() const { return IsMangledOpenMPVariantName; }
533550

@@ -745,10 +762,11 @@ class IdentifierTable {
745762
// contents.
746763
II->Entry = &Entry;
747764

748-
// If this is the 'import' contextual keyword, mark it as such.
765+
// If this is the 'import' or 'module' contextual keyword, mark it as such.
749766
if (Name == "import")
750767
II->setModulesImport(true);
751-
768+
else if (Name == "module")
769+
II->setModulesDeclaration(true);
752770
return *II;
753771
}
754772

clang/include/clang/Basic/TokenKinds.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ PPKEYWORD(pragma)
133133
// C23 & C++26 #embed
134134
PPKEYWORD(embed)
135135

136+
// C++20 Module Directive
137+
PPKEYWORD(module)
138+
136139
// GNU Extensions.
137140
PPKEYWORD(import)
138141
PPKEYWORD(include_next)
@@ -1023,6 +1026,9 @@ ANNOTATION(module_include)
10231026
ANNOTATION(module_begin)
10241027
ANNOTATION(module_end)
10251028

1029+
// Annotations for C++, Clang and Objective-C named modules.
1030+
ANNOTATION(module_name)
1031+
10261032
// Annotation for a header_name token that has been looked up and transformed
10271033
// into the name of a header unit.
10281034
ANNOTATION(header_unit)

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ class CompilerInstance : public ModuleLoader {
863863
/// load it.
864864
ModuleLoadResult findOrCompileModuleAndReadAST(StringRef ModuleName,
865865
SourceLocation ImportLoc,
866-
SourceLocation ModuleNameLoc,
866+
SourceRange ModuleNameRange,
867867
bool IsInclusionDirective);
868868

869869
/// Creates a \c CompilerInstance for compiling a module.

clang/include/clang/Lex/CodeCompletionHandler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
#ifndef LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H
1414
#define LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H
1515

16+
#include "clang/Basic/IdentifierTable.h"
17+
#include "clang/Basic/SourceLocation.h"
1618
#include "llvm/ADT/StringRef.h"
1719

1820
namespace clang {
1921

2022
class IdentifierInfo;
2123
class MacroInfo;
24+
using ModuleIdPath = ArrayRef<IdentifierLoc>;
2225

2326
/// Callback handler that receives notifications when performing code
2427
/// completion within the preprocessor.
@@ -70,6 +73,11 @@ class CodeCompletionHandler {
7073
/// file where we expect natural language, e.g., a comment, string, or
7174
/// \#error directive.
7275
virtual void CodeCompleteNaturalLanguage() { }
76+
77+
/// Callback invoked when performing code completion inside the module name
78+
/// part of an import directive.
79+
virtual void CodeCompleteModuleImport(SourceLocation ImportLoc,
80+
ModuleIdPath Path) {}
7381
};
7482

7583
}

clang/include/clang/Lex/Preprocessor.h

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "llvm/Support/Allocator.h"
4949
#include "llvm/Support/Casting.h"
5050
#include "llvm/Support/Registry.h"
51+
#include "llvm/Support/TrailingObjects.h"
5152
#include <cassert>
5253
#include <cstddef>
5354
#include <cstdint>
@@ -82,6 +83,7 @@ class PreprocessorLexer;
8283
class PreprocessorOptions;
8384
class ScratchBuffer;
8485
class TargetInfo;
86+
class ModuleNameLoc;
8587

8688
namespace Builtin {
8789
class Context;
@@ -332,8 +334,9 @@ class Preprocessor {
332334
/// lexed, if any.
333335
SourceLocation ModuleImportLoc;
334336

335-
/// The import path for named module that we're currently processing.
336-
SmallVector<IdentifierLoc, 2> NamedModuleImportPath;
337+
/// The source location of the \c module contextual keyword we just
338+
/// lexed, if any.
339+
SourceLocation ModuleDeclLoc;
337340

338341
llvm::DenseMap<FileID, SmallVector<const char *>> CheckPoints;
339342
unsigned CheckPointCounter = 0;
@@ -344,6 +347,21 @@ class Preprocessor {
344347
/// Whether the last token we lexed was an '@'.
345348
bool LastTokenWasAt = false;
346349

350+
/// Whether we're importing a standard C++20 named Modules.
351+
bool ImportingCXXNamedModules = false;
352+
353+
/// Whether we're declaring a standard C++20 named Modules.
354+
bool DeclaringCXXNamedModules = false;
355+
356+
struct ExportContextualKeywordInfo {
357+
Token ExportTok;
358+
bool TokAtPhysicalStartOfLine;
359+
};
360+
361+
/// Whether the last token we lexed was an 'export' keyword.
362+
std::optional<ExportContextualKeywordInfo> LastTokenWasExportKeyword =
363+
std::nullopt;
364+
347365
/// A position within a C++20 import-seq.
348366
class StdCXXImportSeq {
349367
public:
@@ -547,12 +565,7 @@ class Preprocessor {
547565
reset();
548566
}
549567

550-
void handleIdentifier(IdentifierInfo *Identifier) {
551-
if (isModuleCandidate() && Identifier)
552-
Name += Identifier->getName().str();
553-
else if (!isNamedModule())
554-
reset();
555-
}
568+
void handleModuleName(ModuleNameLoc *Path);
556569

557570
void handleColon() {
558571
if (isModuleCandidate())
@@ -561,13 +574,6 @@ class Preprocessor {
561574
reset();
562575
}
563576

564-
void handlePeriod() {
565-
if (isModuleCandidate())
566-
Name += ".";
567-
else if (!isNamedModule())
568-
reset();
569-
}
570-
571577
void handleSemi() {
572578
if (!Name.empty() && isModuleCandidate()) {
573579
if (State == InterfaceCandidate)
@@ -622,10 +628,6 @@ class Preprocessor {
622628

623629
ModuleDeclSeq ModuleDeclState;
624630

625-
/// Whether the module import expects an identifier next. Otherwise,
626-
/// it expects a '.' or ';'.
627-
bool ModuleImportExpectsIdentifier = false;
628-
629631
/// The identifier and source location of the currently-active
630632
/// \#pragma clang arc_cf_code_audited begin.
631633
IdentifierLoc PragmaARCCFCodeAuditedInfo;
@@ -1759,6 +1761,19 @@ class Preprocessor {
17591761
/// Lex the parameters for an #embed directive, returns nullopt on error.
17601762
std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
17611763
bool ForHasEmbed);
1764+
bool LexModuleNameContinue(Token &Tok, SourceLocation UseLoc,
1765+
SmallVectorImpl<IdentifierLoc> &Path,
1766+
bool AllowMacroExpansion = true);
1767+
void HandleCXXImportDirective(Token Import);
1768+
void HandleCXXModuleDirective(Token Module);
1769+
1770+
/// Callback invoked when the lexer sees one of export, import or module token
1771+
/// at the start of a line.
1772+
///
1773+
/// This consumes the import, module directive, modifies the
1774+
/// lexer/preprocessor state, and advances the lexer(s) so that the next token
1775+
/// read is the correct one.
1776+
bool HandleModuleContextualKeyword(Token &Result, bool TokAtPhysicalStartOfLine);
17621777

17631778
bool LexAfterModuleImport(Token &Result);
17641779
void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);
@@ -2344,7 +2359,7 @@ class Preprocessor {
23442359
///
23452360
/// \return The location of the end of the directive (the terminating
23462361
/// newline).
2347-
SourceLocation CheckEndOfDirective(const char *DirType,
2362+
SourceLocation CheckEndOfDirective(StringRef DirType,
23482363
bool EnableMacros = false);
23492364

23502365
/// Read and discard all tokens remaining on the current line until
@@ -2426,11 +2441,12 @@ class Preprocessor {
24262441
}
24272442

24282443
/// If we're importing a standard C++20 Named Modules.
2429-
bool isInImportingCXXNamedModules() const {
2430-
// NamedModuleImportPath will be non-empty only if we're importing
2431-
// Standard C++ named modules.
2432-
return !NamedModuleImportPath.empty() && getLangOpts().CPlusPlusModules &&
2433-
!IsAtImport;
2444+
bool isImportingCXXNamedModules() const {
2445+
return getLangOpts().CPlusPlusModules && ImportingCXXNamedModules;
2446+
}
2447+
2448+
bool isDeclaringCXXNamedModules() const {
2449+
return getLangOpts().CPlusPlusModules && DeclaringCXXNamedModules;
24342450
}
24352451

24362452
/// Allocate a new MacroInfo object with the provided SourceLocation.
@@ -3084,6 +3100,53 @@ struct EmbedAnnotationData {
30843100
StringRef FileName;
30853101
};
30863102

3103+
/// Represents module name annotation data.
3104+
///
3105+
/// module-name:
3106+
/// module-name-qualifier[opt] identifier
3107+
///
3108+
/// partition-name: [C++20]
3109+
/// : module-name-qualifier[opt] identifier
3110+
///
3111+
/// module-name-qualifier
3112+
/// module-name-qualifier[opt] identifier .
3113+
class ModuleNameLoc final
3114+
: llvm::TrailingObjects<ModuleNameLoc, IdentifierLoc> {
3115+
friend TrailingObjects;
3116+
unsigned NumIdentifierLocs;
3117+
3118+
unsigned numTrailingObjects(OverloadToken<IdentifierLoc>) const {
3119+
return getNumIdentifierLocs();
3120+
}
3121+
3122+
ModuleNameLoc(ModuleIdPath Path) : NumIdentifierLocs(Path.size()) {
3123+
(void)llvm::copy(Path, getTrailingObjects<IdentifierLoc>());
3124+
}
3125+
3126+
public:
3127+
static std::string stringFromModuleIdPath(ModuleIdPath Path);
3128+
static ModuleNameLoc *Create(Preprocessor &PP, ModuleIdPath Path);
3129+
static Token CreateAnnotToken(Preprocessor &PP, ModuleIdPath Path);
3130+
unsigned getNumIdentifierLocs() const { return NumIdentifierLocs; }
3131+
ModuleIdPath getModuleIdPath() const {
3132+
return {getTrailingObjects<IdentifierLoc>(), getNumIdentifierLocs()};
3133+
}
3134+
3135+
SourceLocation getBeginLoc() const {
3136+
return getModuleIdPath().front().getLoc();
3137+
}
3138+
SourceLocation getEndLoc() const {
3139+
auto &Last = getModuleIdPath().back();
3140+
return Last.getLoc().getLocWithOffset(
3141+
Last.getIdentifierInfo()->getLength());
3142+
}
3143+
SourceRange getRange() const { return {getBeginLoc(), getEndLoc()}; }
3144+
3145+
std::string str() const;
3146+
void print(llvm::raw_ostream &OS) const;
3147+
void dump() const { print(llvm::errs()); }
3148+
};
3149+
30873150
/// Registry of pragma handlers added by plugins
30883151
using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
30893152

clang/include/clang/Lex/Token.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ class Token {
231231
PtrData = const_cast<char*>(Ptr);
232232
}
233233

234+
template <class T> T getAnnotationValueAs() const {
235+
return static_cast<T>(getAnnotationValue());
236+
}
234237
void *getAnnotationValue() const {
235238
assert(isAnnotation() && "Used AnnotVal on non-annotation token");
236239
return PtrData;
@@ -289,6 +292,10 @@ class Token {
289292
/// Return the ObjC keyword kind.
290293
tok::ObjCKeywordKind getObjCKeywordID() const;
291294

295+
/// Return true if we have an C++20 Modules contextual keyword(export, import
296+
/// or module).
297+
bool isModuleContextualKeyword(bool AllowExport = true) const;
298+
292299
bool isSimpleTypeSpecifier(const LangOptions &LangOpts) const;
293300

294301
/// Return true if this token has trigraphs or escaped newlines in it.

clang/include/clang/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,8 @@ class Parser : public CodeCompletionHandler {
10791079
unsigned ArgumentIndex) override;
10801080
void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled) override;
10811081
void CodeCompleteNaturalLanguage() override;
1082+
void CodeCompleteModuleImport(SourceLocation ImportLoc,
1083+
ModuleIdPath Path) override;
10821084

10831085
///@}
10841086

0 commit comments

Comments
 (0)