Skip to content

Commit 612c9ca

Browse files
Merge branch 'main' into users/nico/transfer-read-after-write-broadcast-tightening
2 parents 50589c0 + 971c49f commit 612c9ca

File tree

71 files changed

+7528
-5179
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+7528
-5179
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,13 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
424424
bool empty() const { return Files.empty(); }
425425

426426
/// Clear out this map.
427-
void clear() {
427+
void clear(bool Soft) {
428+
// Just clear the cache when in soft mode.
428429
Files.clear();
429-
FirstDiagState = CurDiagState = nullptr;
430-
CurDiagStateLoc = SourceLocation();
430+
if (!Soft) {
431+
FirstDiagState = CurDiagState = nullptr;
432+
CurDiagStateLoc = SourceLocation();
433+
}
431434
}
432435

433436
/// Produce a debugging dump of the diagnostic state.
@@ -920,6 +923,10 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
920923
/// Reset the state of the diagnostic object to its initial configuration.
921924
/// \param[in] soft - if true, doesn't reset the diagnostic mappings and state
922925
void Reset(bool soft = false);
926+
/// We keep a cache of FileIDs for diagnostics mapped by pragmas. These might
927+
/// get invalidated when diagnostics engine is shared across different
928+
/// compilations. Provide users with a way to reset that.
929+
void ResetPragmas();
923930

924931
//===--------------------------------------------------------------------===//
925932
// DiagnosticsEngine classification and reporting interfaces.

clang/lib/Basic/Diagnostic.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
119119
return true;
120120
}
121121

122+
void DiagnosticsEngine::ResetPragmas() { DiagStatesByLoc.clear(/*Soft=*/true); }
123+
122124
void DiagnosticsEngine::Reset(bool soft /*=false*/) {
123125
ErrorOccurred = false;
124126
UncompilableErrorOccurred = false;
@@ -135,7 +137,7 @@ void DiagnosticsEngine::Reset(bool soft /*=false*/) {
135137
if (!soft) {
136138
// Clear state related to #pragma diagnostic.
137139
DiagStates.clear();
138-
DiagStatesByLoc.clear();
140+
DiagStatesByLoc.clear(false);
139141
DiagStateOnPushStack.clear();
140142

141143
// Create a DiagState and DiagStatePoint representing diagnostic changes

clang/lib/Basic/SourceManager.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ void SourceManager::clearIDTables() {
344344
NextLocalOffset = 0;
345345
CurrentLoadedOffset = MaxLoadedOffset;
346346
createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1);
347+
// Diagnostics engine keeps some references to fileids, mostly for dealing
348+
// with diagnostic pragmas, make sure they're reset as well.
349+
Diag.ResetPragmas();
347350
}
348351

349352
bool SourceManager::isMainFile(const FileEntry &SourceFile) {

clang/lib/Sema/SemaLookup.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,8 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
19781978
if (D->isModulePrivate())
19791979
return false;
19801980

1981+
Module *DeclTopModule = DeclModule->getTopLevelModule();
1982+
19811983
// [module.reach]/p1
19821984
// A translation unit U is necessarily reachable from a point P if U is a
19831985
// module interface unit on which the translation unit containing P has an
@@ -1996,17 +1998,28 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
19961998
//
19971999
// Here we only check for the first condition. Since we couldn't see
19982000
// DeclModule if it isn't (transitively) imported.
1999-
if (DeclModule->getTopLevelModule()->isModuleInterfaceUnit())
2001+
if (DeclTopModule->isModuleInterfaceUnit())
20002002
return true;
20012003

2002-
// [module.reach]/p2
2004+
// [module.reach]/p1,2
2005+
// A translation unit U is necessarily reachable from a point P if U is a
2006+
// module interface unit on which the translation unit containing P has an
2007+
// interface dependency, or the translation unit containing P imports U, in
2008+
// either case prior to P
2009+
//
20032010
// Additional translation units on
20042011
// which the point within the program has an interface dependency may be
20052012
// considered reachable, but it is unspecified which are and under what
20062013
// circumstances.
2007-
//
2008-
// The decision here is to treat all additional tranditional units as
2009-
// unreachable.
2014+
Module *CurrentM = SemaRef.getCurrentModule();
2015+
2016+
// Directly imported module are necessarily reachable.
2017+
// Since we can't export import a module implementation partition unit, we
2018+
// don't need to count for Exports here.
2019+
if (CurrentM && CurrentM->getTopLevelModule()->Imports.count(DeclTopModule))
2020+
return true;
2021+
2022+
// Then we treat all module implementation partition unit as unreachable.
20102023
return false;
20112024
}
20122025

clang/lib/Sema/SemaModule.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -712,19 +712,20 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
712712
Mod->Kind == Module::ModuleKind::ModulePartitionImplementation) {
713713
Diag(ExportLoc, diag::err_export_partition_impl)
714714
<< SourceRange(ExportLoc, Path.back().getLoc());
715-
} else if (!ModuleScopes.empty() && !currentModuleIsImplementation()) {
715+
} else if (ExportLoc.isValid() &&
716+
(ModuleScopes.empty() || currentModuleIsImplementation())) {
717+
// [module.interface]p1:
718+
// An export-declaration shall inhabit a namespace scope and appear in the
719+
// purview of a module interface unit.
720+
Diag(ExportLoc, diag::err_export_not_in_module_interface);
721+
} else if (!ModuleScopes.empty()) {
716722
// Re-export the module if the imported module is exported.
717723
// Note that we don't need to add re-exported module to Imports field
718724
// since `Exports` implies the module is imported already.
719725
if (ExportLoc.isValid() || getEnclosingExportDecl(Import))
720726
getCurrentModule()->Exports.emplace_back(Mod, false);
721727
else
722728
getCurrentModule()->Imports.insert(Mod);
723-
} else if (ExportLoc.isValid()) {
724-
// [module.interface]p1:
725-
// An export-declaration shall inhabit a namespace scope and appear in the
726-
// purview of a module interface unit.
727-
Diag(ExportLoc, diag::err_export_not_in_module_interface);
728729
}
729730

730731
return Import;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11322,9 +11322,9 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S,
1132211322
SourceLocation Loc,
1132311323
iterator &Best) {
1132411324

11325-
assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) ||
11326-
DeferredCandidatesCount == 0 &&
11327-
"Unexpected deferred template candidates");
11325+
assert((shouldDeferTemplateArgumentDeduction(S.getLangOpts()) ||
11326+
DeferredCandidatesCount == 0) &&
11327+
"Unexpected deferred template candidates");
1132811328

1132911329
bool TwoPhaseResolution =
1133011330
DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled;

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,48 @@ namespace clang {
221221
Record.AddDeclRef(F.second);
222222
}
223223

224+
template <typename T> bool shouldSkipWritingSpecializations(T *Spec) {
225+
// Now we will only avoid writing specializations if we're generating
226+
// reduced BMI.
227+
if (!GeneratingReducedBMI)
228+
return false;
229+
230+
assert((isa<FunctionDecl, ClassTemplateSpecializationDecl,
231+
VarTemplateSpecializationDecl>(Spec)));
232+
233+
ArrayRef<TemplateArgument> Args;
234+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
235+
Args = CTSD->getTemplateArgs().asArray();
236+
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
237+
Args = VTSD->getTemplateArgs().asArray();
238+
else
239+
Args = cast<FunctionDecl>(Spec)
240+
->getTemplateSpecializationArgs()
241+
->asArray();
242+
243+
// If there is any template argument is TULocal, we can avoid writing the
244+
// specialization since the consumers of reduced BMI won't get the
245+
// specialization anyway.
246+
for (const TemplateArgument &TA : Args) {
247+
switch (TA.getKind()) {
248+
case TemplateArgument::Type: {
249+
Linkage L = TA.getAsType()->getLinkage();
250+
if (!isExternallyVisible(L))
251+
return true;
252+
break;
253+
}
254+
case TemplateArgument::Declaration:
255+
if (!TA.getAsDecl()->isExternallyVisible())
256+
return true;
257+
break;
258+
default:
259+
break;
260+
}
261+
}
262+
263+
return false;
264+
}
265+
224266
/// Add to the record the first template specialization from each module
225267
/// file that provides a declaration of D. We store the DeclId and an
226268
/// ODRHash of the template arguments of D which should provide enough
@@ -235,6 +277,9 @@ namespace clang {
235277
CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts);
236278

237279
for (const auto &F : Firsts) {
280+
if (shouldSkipWritingSpecializations(F.second))
281+
continue;
282+
238283
if (isa<ClassTemplatePartialSpecializationDecl,
239284
VarTemplatePartialSpecializationDecl>(F.second))
240285
PartialSpecsInMap.push_back(F.second);

clang/test/Modules/pr119947.cppm

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t -emit-llvm -o -
7+
8+
9+
//--- a.cppm
10+
export module a;
11+
12+
struct a_inner {
13+
~a_inner() {
14+
}
15+
void f(auto) {
16+
}
17+
};
18+
19+
export template<typename T>
20+
struct a {
21+
a() {
22+
struct local {};
23+
inner.f(local());
24+
}
25+
private:
26+
a_inner inner;
27+
};
28+
29+
30+
namespace {
31+
32+
struct s {
33+
};
34+
35+
} // namespace
36+
37+
void f() {
38+
a<s> x;
39+
}
40+
41+
//--- use.cpp
42+
import a;
43+
44+
namespace {
45+
46+
struct s {
47+
};
48+
49+
} // namespace
50+
51+
void g() {
52+
a<s> x;
53+
}
54+

clang/test/Modules/pr143788.cppm

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/P.cppm -emit-module-interface -o %t/P.pcm
7+
// RUN: %clang_cc1 -std=c++20 %t/I.cpp -fmodule-file=M:P=%t/P.pcm -fmodule-file=M=%t/M.pcm -fsyntax-only -verify
8+
9+
//--- H.hpp
10+
struct S{};
11+
12+
//--- M.cppm
13+
export module M;
14+
15+
16+
//--- P.cppm
17+
module;
18+
#include "H.hpp"
19+
module M:P;
20+
21+
using T = S;
22+
23+
//--- I.cpp
24+
// expected-no-diagnostics
25+
module M;
26+
import :P;
27+
28+
T f() { return {}; }

clang/unittests/Frontend/CompilerInstanceTest.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
#include "clang/Frontend/CompilerInstance.h"
1010
#include "clang/Basic/FileManager.h"
1111
#include "clang/Frontend/CompilerInvocation.h"
12+
#include "clang/Frontend/FrontendActions.h"
1213
#include "clang/Frontend/TextDiagnosticPrinter.h"
14+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
1315
#include "llvm/Support/FileSystem.h"
1416
#include "llvm/Support/Format.h"
17+
#include "llvm/Support/MemoryBuffer.h"
1518
#include "llvm/Support/ToolOutputFile.h"
1619
#include "llvm/Support/VirtualFileSystem.h"
1720
#include "gtest/gtest.h"
@@ -97,4 +100,52 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
97100
ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n");
98101
}
99102

103+
TEST(CompilerInstance, MultipleInputsCleansFileIDs) {
104+
auto VFS = makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
105+
VFS->addFile("a.cc", /*ModificationTime=*/{},
106+
MemoryBuffer::getMemBuffer(R"cpp(
107+
#include "a.h"
108+
)cpp"));
109+
// Paddings of `void foo();` in the sources below are "important". We're
110+
// testing against source locations from previous compilations colliding.
111+
// Hence the `unused` variable in `b.h` needs to be within `#pragma clang
112+
// diagnostic` block from `a.h`.
113+
VFS->addFile("a.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp(
114+
#include "b.h"
115+
#pragma clang diagnostic push
116+
#pragma clang diagnostic warning "-Wunused"
117+
void foo();
118+
#pragma clang diagnostic pop
119+
)cpp"));
120+
VFS->addFile("b.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp(
121+
void foo(); void foo(); void foo(); void foo();
122+
inline void foo() { int unused = 2; }
123+
)cpp"));
124+
125+
DiagnosticOptions DiagOpts;
126+
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
127+
CompilerInstance::createDiagnostics(*VFS, DiagOpts);
128+
129+
CreateInvocationOptions CIOpts;
130+
CIOpts.Diags = Diags;
131+
132+
const char *Args[] = {"clang", "-xc++", "a.cc"};
133+
std::shared_ptr<CompilerInvocation> CInvok =
134+
createInvocation(Args, std::move(CIOpts));
135+
ASSERT_TRUE(CInvok) << "could not create compiler invocation";
136+
137+
CompilerInstance Instance(std::move(CInvok));
138+
Instance.setDiagnostics(Diags.get());
139+
Instance.createFileManager(VFS);
140+
141+
// Run once for `a.cc` and then for `a.h`. This makes sure we get the same
142+
// file ID for `b.h` in the second run as `a.h` from first run.
143+
const auto &OrigInputKind = Instance.getFrontendOpts().Inputs[0].getKind();
144+
Instance.getFrontendOpts().Inputs.emplace_back("a.h", OrigInputKind);
145+
146+
SyntaxOnlyAction Act;
147+
EXPECT_TRUE(Instance.ExecuteAction(Act)) << "Failed to execute action";
148+
EXPECT_FALSE(Diags->hasErrorOccurred());
149+
EXPECT_EQ(Diags->getNumWarnings(), 0u);
150+
}
100151
} // anonymous namespace

0 commit comments

Comments
 (0)