Skip to content

Commit d26dd58

Browse files
committed
[StmtProfile] Don't profile the body of lambda expressions
Close #87609 We tried to profile the body of the lambda expressions in https://reviews.llvm.org/D153957. But as the original comments show, it is indeed dangerous. After we tried to skip calculating the ODR hash values recently, we have fall into this trap twice. So in this patch, I choose to not profile the body of the lambda expression. The signature of the lambda is still profiled.
1 parent dbaa189 commit d26dd58

File tree

10 files changed

+81
-28
lines changed

10 files changed

+81
-28
lines changed

clang/include/clang/AST/DeclBase.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -672,16 +672,6 @@ class alignas(8) Decl {
672672
/// Whether this declaration comes from explicit global module.
673673
bool isFromExplicitGlobalModule() const;
674674

675-
/// Check if we should skip checking ODRHash for declaration \param D.
676-
///
677-
/// The existing ODRHash mechanism seems to be not stable enough and
678-
/// the false positive ODR violation reports are annoying and we rarely see
679-
/// true ODR violation reports. Also we learned that MSVC disabled ODR checks
680-
/// for declarations in GMF. So we try to disable ODR checks in the GMF to
681-
/// get better user experiences before we make the ODR violation checks stable
682-
/// enough.
683-
bool shouldSkipCheckingODR() const;
684-
685675
/// Return true if this declaration has an attribute which acts as
686676
/// definition of the entity, such as 'alias' or 'ifunc'.
687677
bool hasDefiningAttr() const;

clang/include/clang/Serialization/ASTReader.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,12 @@ class BitsUnpacker {
24572457
uint32_t Value;
24582458
uint32_t CurrentBitsIndex = ~0;
24592459
};
2460+
2461+
inline bool shouldSkipCheckingODR(const Decl *D) {
2462+
return D->getASTContext().getLangOpts().SkipODRCheckInGMF &&
2463+
D->isFromExplicitGlobalModule();
2464+
}
2465+
24602466
} // namespace clang
24612467

24622468
#endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4534,7 +4534,7 @@ unsigned FunctionDecl::getODRHash() {
45344534
}
45354535

45364536
class ODRHash Hash;
4537-
Hash.AddFunctionDecl(this, /*SkipBody=*/shouldSkipCheckingODR());
4537+
Hash.AddFunctionDecl(this);
45384538
setHasODRHash(true);
45394539
ODRHash = Hash.CalculateHash();
45404540
return ODRHash;

clang/lib/AST/DeclBase.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,11 +1106,6 @@ bool Decl::isFromExplicitGlobalModule() const {
11061106
return getOwningModule() && getOwningModule()->isExplicitGlobalModule();
11071107
}
11081108

1109-
bool Decl::shouldSkipCheckingODR() const {
1110-
return getASTContext().getLangOpts().SkipODRCheckInGMF &&
1111-
isFromExplicitGlobalModule();
1112-
}
1113-
11141109
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
11151110
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
11161111

clang/lib/AST/StmtProfile.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,13 +2071,31 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
20712071
}
20722072

20732073
CXXRecordDecl *Lambda = S->getLambdaClass();
2074-
ID.AddInteger(Lambda->getODRHash());
2075-
20762074
for (const auto &Capture : Lambda->captures()) {
20772075
ID.AddInteger(Capture.getCaptureKind());
20782076
if (Capture.capturesVariable())
20792077
VisitDecl(Capture.getCapturedVar());
20802078
}
2079+
2080+
// Profiling the body of the lambda may be dangerous during deserialization.
2081+
// So we'd like only to profile the signature here.
2082+
ODRHash Hasher;
2083+
// FIXME: We can't get the operator call easily by
2084+
// `CXXRecordDecl::getLambdaCallOperator()` if we're in deserialization.
2085+
// So we have to do something raw here.
2086+
for (auto *SubDecl : Lambda->decls()) {
2087+
FunctionDecl *Call = nullptr;
2088+
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(SubDecl))
2089+
Call = FTD->getTemplatedDecl();
2090+
else if (auto *FD = dyn_cast<FunctionDecl>(SubDecl))
2091+
Call = FD;
2092+
2093+
if (!Call)
2094+
continue;
2095+
2096+
Hasher.AddFunctionDecl(Call, /*SkipBody=*/true);
2097+
}
2098+
ID.AddInteger(Hasher.CalculateHash());
20812099
}
20822100

20832101
void

clang/lib/Serialization/ASTReader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9785,7 +9785,7 @@ void ASTReader::finishPendingActions() {
97859785
!NonConstDefn->isLateTemplateParsed() &&
97869786
// We only perform ODR checks for decls not in the explicit
97879787
// global module fragment.
9788-
!FD->shouldSkipCheckingODR() &&
9788+
!shouldSkipCheckingODR(FD) &&
97899789
FD->getODRHash() != NonConstDefn->getODRHash()) {
97909790
if (!isa<CXXMethodDecl>(FD)) {
97919791
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
826826
Reader.mergeDefinitionVisibility(OldDef, ED);
827827
// We don't want to check the ODR hash value for declarations from global
828828
// module fragment.
829-
if (!ED->shouldSkipCheckingODR() &&
829+
if (!shouldSkipCheckingODR(ED) &&
830830
OldDef->getODRHash() != ED->getODRHash())
831831
Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
832832
} else {
@@ -868,7 +868,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
868868
VisitRecordDeclImpl(RD);
869869
// We should only reach here if we're in C/Objective-C. There is no
870870
// global module fragment.
871-
assert(!RD->shouldSkipCheckingODR());
871+
assert(!shouldSkipCheckingODR(RD));
872872
RD->setODRHash(Record.readInt());
873873

874874
// Maintain the invariant of a redeclaration chain containing only
@@ -2155,7 +2155,7 @@ void ASTDeclReader::MergeDefinitionData(
21552155
}
21562156

21572157
// We don't want to check ODR for decls in the global module fragment.
2158-
if (MergeDD.Definition->shouldSkipCheckingODR())
2158+
if (shouldSkipCheckingODR(MergeDD.Definition))
21592159
return;
21602160

21612161
if (D->getODRHash() != MergeDD.ODRHash) {
@@ -3530,7 +3530,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
35303530
// same template specialization into the same CXXRecordDecl.
35313531
auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
35323532
if (MergedDCIt != Reader.MergedDeclContexts.end() &&
3533-
!D->shouldSkipCheckingODR() && MergedDCIt->second == D->getDeclContext())
3533+
!shouldSkipCheckingODR(D) && MergedDCIt->second == D->getDeclContext())
35343534
Reader.PendingOdrMergeChecks.push_back(D);
35353535

35363536
return FindExistingResult(Reader, D, /*Existing=*/nullptr,

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6188,7 +6188,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
61886188

61896189
BitsPacker DefinitionBits;
61906190

6191-
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
6191+
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
61926192
DefinitionBits.addBit(ShouldSkipCheckingODR);
61936193

61946194
#define FIELD(Name, Width, Merge) \

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
526526
BitsPacker EnumDeclBits;
527527
EnumDeclBits.addBits(D->getNumPositiveBits(), /*BitWidth=*/8);
528528
EnumDeclBits.addBits(D->getNumNegativeBits(), /*BitWidth=*/8);
529-
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
529+
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
530530
EnumDeclBits.addBit(ShouldSkipCheckingODR);
531531
EnumDeclBits.addBit(D->isScoped());
532532
EnumDeclBits.addBit(D->isScopedUsingClassTag());
@@ -552,7 +552,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
552552
!D->isTopLevelDeclInObjCContainer() &&
553553
!CXXRecordDecl::classofKind(D->getKind()) &&
554554
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
555-
!needsAnonymousDeclarationNumber(D) && !D->shouldSkipCheckingODR() &&
555+
!needsAnonymousDeclarationNumber(D) && !shouldSkipCheckingODR(D) &&
556556
D->getDeclName().getNameKind() == DeclarationName::Identifier)
557557
AbbrevToUse = Writer.getDeclEnumAbbrev();
558558

@@ -718,7 +718,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
718718
// FIXME: stable encoding
719719
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
720720
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
721-
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
721+
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
722722
FunctionDeclBits.addBit(ShouldSkipCheckingODR);
723723
FunctionDeclBits.addBit(D->isInlineSpecified());
724724
FunctionDeclBits.addBit(D->isInlined());
@@ -1559,7 +1559,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
15591559
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
15601560
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
15611561
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
1562-
!D->shouldSkipCheckingODR() && !D->hasExtInfo() &&
1562+
!shouldSkipCheckingODR(D) && !D->hasExtInfo() &&
15631563
!D->isExplicitlyDefaulted()) {
15641564
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
15651565
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/A.cppm -emit-module-interface -o %t/A.pcm
6+
// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/test.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
7+
8+
//--- header.h
9+
#pragma once
10+
template <class _Tp>
11+
class Optional {};
12+
13+
template <class _Tp>
14+
concept C = requires(const _Tp& __t) {
15+
[]<class _Up>(const Optional<_Up>&) {}(__t);
16+
};
17+
18+
//--- func.h
19+
#include "header.h"
20+
template <C T>
21+
void func() {}
22+
23+
//--- test_func.h
24+
#include "func.h"
25+
26+
inline void test_func() {
27+
func<Optional<int>>();
28+
}
29+
30+
//--- A.cppm
31+
module;
32+
#include "header.h"
33+
#include "test_func.h"
34+
export module A;
35+
export using ::test_func;
36+
37+
//--- test.cpp
38+
// expected-no-diagnostics
39+
import A;
40+
#include "test_func.h"
41+
42+
void test() {
43+
test_func();
44+
}

0 commit comments

Comments
 (0)