clang 20.0.0git
SemaModule.cpp
Go to the documentation of this file.
1//===--- SemaModule.cpp - Semantic Analysis for Modules -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements semantic analysis for modules (C++ modules syntax,
10// Objective-C modules syntax, and Clang header modules).
11//
12//===----------------------------------------------------------------------===//
13
19#include "llvm/ADT/StringExtras.h"
20
21using namespace clang;
22using namespace sema;
23
25 SourceLocation ImportLoc, DeclContext *DC,
26 bool FromInclude = false) {
27 SourceLocation ExternCLoc;
28
29 if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
30 switch (LSD->getLanguage()) {
31 case LinkageSpecLanguageIDs::C:
32 if (ExternCLoc.isInvalid())
33 ExternCLoc = LSD->getBeginLoc();
34 break;
35 case LinkageSpecLanguageIDs::CXX:
36 break;
37 }
38 DC = LSD->getParent();
39 }
40
41 while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC))
42 DC = DC->getParent();
43
44 if (!isa<TranslationUnitDecl>(DC)) {
45 S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M))
46 ? diag::ext_module_import_not_at_top_level_noop
47 : diag::err_module_import_not_at_top_level_fatal)
48 << M->getFullModuleName() << DC;
49 S.Diag(cast<Decl>(DC)->getBeginLoc(),
50 diag::note_module_import_not_at_top_level)
51 << DC;
52 } else if (!M->IsExternC && ExternCLoc.isValid()) {
53 S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
54 << M->getFullModuleName();
55 S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
56 }
57}
58
59// We represent the primary and partition names as 'Paths' which are sections
60// of the hierarchical access path for a clang module. However for C++20
61// the periods in a name are just another character, and we will need to
62// flatten them into a string.
63static std::string stringFromPath(ModuleIdPath Path) {
64 std::string Name;
65 if (Path.empty())
66 return Name;
67
68 for (auto &Piece : Path) {
69 if (!Name.empty())
70 Name += ".";
71 Name += Piece.first->getName();
72 }
73 return Name;
74}
75
76/// Helper function for makeTransitiveImportsVisible to decide whether
77/// the \param Imported module unit is in the same module with the \param
78/// CurrentModule.
79/// \param FoundPrimaryModuleInterface is a helper parameter to record the
80/// primary module interface unit corresponding to the module \param
81/// CurrentModule. Since currently it is expensive to decide whether two module
82/// units come from the same module by comparing the module name.
83static bool
85 Module *CurrentModule,
86 Module *&FoundPrimaryModuleInterface) {
87 if (!Imported->isNamedModule())
88 return false;
89
90 // The a partition unit we're importing must be in the same module of the
91 // current module.
92 if (Imported->isModulePartition())
93 return true;
94
95 // If we found the primary module interface during the search process, we can
96 // return quickly to avoid expensive string comparison.
97 if (FoundPrimaryModuleInterface)
98 return Imported == FoundPrimaryModuleInterface;
99
100 if (!CurrentModule)
101 return false;
102
103 // Then the imported module must be a primary module interface unit. It
104 // is only allowed to import the primary module interface unit from the same
105 // module in the implementation unit and the implementation partition unit.
106
107 // Since we'll handle implementation unit above. We can only care
108 // about the implementation partition unit here.
109 if (!CurrentModule->isModulePartitionImplementation())
110 return false;
111
112 if (Ctx.isInSameModule(Imported, CurrentModule)) {
113 assert(!FoundPrimaryModuleInterface ||
114 FoundPrimaryModuleInterface == Imported);
115 FoundPrimaryModuleInterface = Imported;
116 return true;
117 }
118
119 return false;
120}
121
122/// [module.import]p7:
123/// Additionally, when a module-import-declaration in a module unit of some
124/// module M imports another module unit U of M, it also imports all
125/// translation units imported by non-exported module-import-declarations in
126/// the module unit purview of U. These rules can in turn lead to the
127/// importation of yet more translation units.
128static void
130 Module *Imported, Module *CurrentModule,
131 SourceLocation ImportLoc,
132 bool IsImportingPrimaryModuleInterface = false) {
133 assert(Imported->isNamedModule() &&
134 "'makeTransitiveImportsVisible()' is intended for standard C++ named "
135 "modules only.");
136
138 Worklist.push_back(Imported);
139
140 Module *FoundPrimaryModuleInterface =
141 IsImportingPrimaryModuleInterface ? Imported : nullptr;
142
143 while (!Worklist.empty()) {
144 Module *Importing = Worklist.pop_back_val();
145
146 if (VisibleModules.isVisible(Importing))
147 continue;
148
149 // FIXME: The ImportLoc here is not meaningful. It may be problematic if we
150 // use the sourcelocation loaded from the visible modules.
151 VisibleModules.setVisible(Importing, ImportLoc);
152
153 if (isImportingModuleUnitFromSameModule(Ctx, Importing, CurrentModule,
154 FoundPrimaryModuleInterface))
155 for (Module *TransImported : Importing->Imports)
156 if (!VisibleModules.isVisible(TransImported))
157 Worklist.push_back(TransImported);
158 }
159}
160
163 // We start in the global module;
164 Module *GlobalModule =
165 PushGlobalModuleFragment(ModuleLoc);
166
167 // All declarations created from now on are owned by the global module.
168 auto *TU = Context.getTranslationUnitDecl();
169 // [module.global.frag]p2
170 // A global-module-fragment specifies the contents of the global module
171 // fragment for a module unit. The global module fragment can be used to
172 // provide declarations that are attached to the global module and usable
173 // within the module unit.