Skip to content

Commit 7c7fb94

Browse files
authored
Revert "Reapply "[Analyzer][CFG] Correctly handle rebuilt default arg and default init expression" (#127338)" (#128205)
This reverts commit d235b72.
1 parent 115672f commit 7c7fb94

File tree

10 files changed

+61
-208
lines changed

10 files changed

+61
-208
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,6 @@ Code Completion
284284
Static Analyzer
285285
---------------
286286

287-
- Clang currently support extending lifetime of object bound to
288-
reference members of aggregates in CFG and ExprEngine, that are
289-
created from default member initializer.
290-
291287
New features
292288
^^^^^^^^^^^^
293289

clang/lib/AST/ParentMap.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "clang/AST/ParentMap.h"
1414
#include "clang/AST/Decl.h"
1515
#include "clang/AST/Expr.h"
16-
#include "clang/AST/ExprCXX.h"
1716
#include "clang/AST/StmtObjC.h"
1817
#include "llvm/ADT/DenseMap.h"
1918

@@ -104,22 +103,6 @@ static void BuildParentMap(MapTy& M, Stmt* S,
104103
BuildParentMap(M, SubStmt, OVMode);
105104
}
106105
break;
107-
case Stmt::CXXDefaultArgExprClass:
108-
if (auto *Arg = dyn_cast<CXXDefaultArgExpr>(S)) {
109-
if (Arg->hasRewrittenInit()) {
110-
M[Arg->getExpr()] = S;
111-
BuildParentMap(M, Arg->getExpr(), OVMode);
112-
}
113-
}
114-
break;
115-
case Stmt::CXXDefaultInitExprClass:
116-
if (auto *Init = dyn_cast<CXXDefaultInitExpr>(S)) {
117-
if (Init->hasRewrittenInit()) {
118-
M[Init->getExpr()] = S;
119-
BuildParentMap(M, Init->getExpr(), OVMode);
120-
}
121-
}
122-
break;
123106
default:
124107
for (Stmt *SubStmt : S->children()) {
125108
if (SubStmt) {

clang/lib/Analysis/CFG.cpp

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,6 @@ class CFGBuilder {
556556

557557
private:
558558
// Visitors to walk an AST and construct the CFG.
559-
CFGBlock *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Default,
560-
AddStmtChoice asc);
561-
CFGBlock *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Default,
562-
AddStmtChoice asc);
563559
CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
564560
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
565561
CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
@@ -2267,10 +2263,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
22672263
asc, ExternallyDestructed);
22682264

22692265
case Stmt::CXXDefaultArgExprClass:
2270-
return VisitCXXDefaultArgExpr(cast<CXXDefaultArgExpr>(S), asc);
2271-
22722266
case Stmt::CXXDefaultInitExprClass:
2273-
return VisitCXXDefaultInitExpr(cast<CXXDefaultInitExpr>(S), asc);
2267+
// FIXME: The expression inside a CXXDefaultArgExpr is owned by the
2268+
// called function's declaration, not by the caller. If we simply add
2269+
// this expression to the CFG, we could end up with the same Expr
2270+
// appearing multiple times (PR13385).
2271+
//
2272+
// It's likewise possible for multiple CXXDefaultInitExprs for the same
2273+
// expression to be used in the same function (through aggregate
2274+
// initialization).
2275+
return VisitStmt(S, asc);
22742276

22752277
case Stmt::CXXBindTemporaryExprClass:
22762278
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
@@ -2440,44 +2442,6 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
24402442
return B;
24412443
}
24422444

2443-
CFGBlock *CFGBuilder::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Arg,
2444-
AddStmtChoice asc) {
2445-
if (Arg->hasRewrittenInit()) {
2446-
if (asc.alwaysAdd(*this, Arg)) {
2447-
autoCreateBlock();
2448-
appendStmt(Block, Arg);
2449-
}
2450-
return VisitStmt(Arg->getExpr()->IgnoreParens(), asc);
2451-
}
2452-
2453-
// We can't add the default argument if it's not rewritten because the
2454-
// expression inside a CXXDefaultArgExpr is owned by the called function's
2455-
// declaration, not by the caller, we could end up with the same expression
2456-
// appearing multiple times.
2457-
return VisitStmt(Arg, asc);
2458-
}
2459-
2460-
CFGBlock *CFGBuilder::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Init,
2461-
AddStmtChoice asc) {
2462-
if (Init->hasRewrittenInit()) {
2463-
if (asc.alwaysAdd(*this, Init)) {
2464-
autoCreateBlock();
2465-
appendStmt(Block, Init);
2466-
}
2467-
2468-
// Unlike CXXDefaultArgExpr::getExpr stripped off the top level FullExpr and
2469-
// ConstantExpr, CXXDefaultInitExpr::getExpr does not do this, so we don't
2470-
// need to ignore ParenExprs, because the top level will not be a ParenExpr.
2471-
return VisitStmt(Init->getExpr(), asc);
2472-
}
2473-
2474-
// We can't add the default initializer if it's not rewritten because multiple
2475-
// CXXDefaultInitExprs for the same sub-expression to be used in the same
2476-
// function (through aggregate initialization). we could end up with the same
2477-
// expression appearing multiple times.
2478-
return VisitStmt(Init, asc);
2479-
}
2480-
24812445
CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
24822446
if (asc.alwaysAdd(*this, ILE)) {
24832447
autoCreateBlock();

clang/lib/Analysis/ReachableCode.cpp

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,11 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
454454
return isDeadRoot;
455455
}
456456

457-
// Check if the given `DeadStmt` is one of target statements or is a sub-stmt of
458-
// them. `Block` is the CFGBlock containing the `DeadStmt`.
459-
template <class... Ts>
460-
static bool isDeadStmtInOneOf(const Stmt *DeadStmt, const CFGBlock *Block) {
457+
// Check if the given `DeadStmt` is a coroutine statement and is a substmt of
458+
// the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`.
459+
static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block) {
461460
// The coroutine statement, co_return, co_await, or co_yield.
462-
const Stmt *TargetStmt = nullptr;
461+
const Stmt *CoroStmt = nullptr;
463462
// Find the first coroutine statement after the DeadStmt in the block.
464463
bool AfterDeadStmt = false;
465464
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E;
@@ -468,27 +467,32 @@ static bool isDeadStmtInOneOf(const Stmt *DeadStmt, const CFGBlock *Block) {
468467
const Stmt *S = CS->getStmt();
469468
if (S == DeadStmt)
470469
AfterDeadStmt = true;
471-
if (AfterDeadStmt && llvm::isa<Ts...>(S)) {
472-
TargetStmt = S;
470+
if (AfterDeadStmt &&
471+
// For simplicity, we only check simple coroutine statements.
472+
(llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
473+
CoroStmt = S;
473474
break;
474475
}
475476
}
476-
if (!TargetStmt)
477+
if (!CoroStmt)
477478
return false;
478479
struct Checker : DynamicRecursiveASTVisitor {
479480
const Stmt *DeadStmt;
480-
bool IsSubStmtOfTargetStmt = false;
481-
Checker(const Stmt *S) : DeadStmt(S) { ShouldVisitImplicitCode = true; }
481+
bool CoroutineSubStmt = false;
482+
Checker(const Stmt *S) : DeadStmt(S) {
483+
// Statements captured in the CFG can be implicit.
484+
ShouldVisitImplicitCode = true;
485+
}
482486

483487
bool VisitStmt(Stmt *S) override {
484488
if (S == DeadStmt)
485-
IsSubStmtOfTargetStmt = true;
489+
CoroutineSubStmt = true;
486490
return true;
487491
}
488492
};
489493
Checker checker(DeadStmt);
490-
checker.TraverseStmt(const_cast<Stmt *>(TargetStmt));
491-
return checker.IsSubStmtOfTargetStmt;
494+
checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
495+
return checker.CoroutineSubStmt;
492496
}
493497

494498
static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
@@ -499,12 +503,7 @@ static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
499503
// Coroutine statements are never considered dead statements, because removing
500504
// them may change the function semantic if it is the only coroutine statement
501505
// of the coroutine.
502-
//
503-
// If the dead stmt is a sub-stmt of CXXDefaultInitExpr and CXXDefaultArgExpr,
504-
// we would rather expect to find CXXDefaultInitExpr and CXXDefaultArgExpr as
505-
// a valid dead stmt.
506-
return !isDeadStmtInOneOf<CoreturnStmt, CoroutineSuspendExpr,
507-
CXXDefaultArgExpr, CXXDefaultInitExpr>(S, Block);
506+
return !isInCoroutineStmt(S, Block);
508507
}
509508

510509
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5571,10 +5571,8 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
55715571
/*SkipImmediateInvocations=*/NestedDefaultChecking))
55725572
return ExprError();
55735573

5574-
Expr *RewrittenExpr = (Init == Param->getDefaultArg() ? nullptr : Init);
55755574
return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param,
5576-
RewrittenExpr,
5577-
InitializationContext->Context);
5575+
Init, InitializationContext->Context);
55785576
}
55795577

55805578
static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx,
@@ -5692,11 +5690,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
56925690
return ExprError();
56935691
}
56945692
Init = Res.get();
5695-
Expr *RewrittenInit =
5696-
(Init == Field->getInClassInitializer() ? nullptr : Init);
5693+
56975694
return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc,
56985695
Field, InitializationContext->Context,
5699-
RewrittenInit);
5696+
Init);
57005697
}
57015698

57025699
// DR1351:

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,45 +1990,33 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
19901990
ExplodedNodeSet Tmp;
19911991
StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
19921992

1993-
bool HasRebuiltInit = false;
1994-
const Expr *ArgE = nullptr;
1995-
if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S)) {
1993+
const Expr *ArgE;
1994+
if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S))
19961995
ArgE = DefE->getExpr();
1997-
HasRebuiltInit = DefE->hasRewrittenInit();
1998-
} else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S)) {
1996+
else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S))
19991997
ArgE = DefE->getExpr();
2000-
HasRebuiltInit = DefE->hasRewrittenInit();
2001-
} else
1998+
else
20021999
llvm_unreachable("unknown constant wrapper kind");
20032000

2004-
if (HasRebuiltInit) {
2005-
for (auto *N : PreVisit) {
2006-
ProgramStateRef state = N->getState();
2007-
const LocationContext *LCtx = N->getLocationContext();
2008-
state = state->BindExpr(S, LCtx, state->getSVal(ArgE, LCtx));
2009-
Bldr2.generateNode(S, N, state);
2010-
}
2011-
} else {
2012-
// If it's not rewritten, the contents of these expressions are not
2013-
// actually part of the current function, so we fall back to constant
2014-
// evaluation.
2015-
bool IsTemporary = false;
2016-
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
2017-
ArgE = MTE->getSubExpr();
2018-
IsTemporary = true;
2019-
}
2020-
2021-
std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
2022-
const LocationContext *LCtx = Pred->getLocationContext();
2023-
for (auto *I : PreVisit) {
2024-
ProgramStateRef State = I->getState();
2025-
State = State->BindExpr(S, LCtx, ConstantVal.value_or(UnknownVal()));
2026-
if (IsTemporary)
2027-
State = createTemporaryRegionIfNeeded(State, LCtx, cast<Expr>(S),
2028-
cast<Expr>(S));
2001+
bool IsTemporary = false;
2002+
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
2003+
ArgE = MTE->getSubExpr();
2004+
IsTemporary = true;
2005+
}
20292006

2030-
Bldr2.generateNode(S, I, State);
2031-
}
2007+
std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
2008+
if (!ConstantVal)
2009+
ConstantVal = UnknownVal();
2010+
2011+
const LocationContext *LCtx = Pred->getLocationContext();
2012+
for (const auto I : PreVisit) {
2013+
ProgramStateRef State = I->getState();
2014+
State = State->BindExpr(S, LCtx, *ConstantVal);
2015+
if (IsTemporary)
2016+
State = createTemporaryRegionIfNeeded(State, LCtx,
2017+
cast<Expr>(S),
2018+
cast<Expr>(S));
2019+
Bldr2.generateNode(S, I, State);
20322020
}
20332021

20342022
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);

clang/test/AST/ast-dump-recovery.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ union U {
507507
// CHECK-NEXT: `-DeclStmt {{.*}}
508508
// CHECK-NEXT: `-VarDecl {{.*}} g 'U':'GH112560::U' listinit
509509
// CHECK-NEXT: `-InitListExpr {{.*}} 'U':'GH112560::U' contains-errors field Field {{.*}} 'f' 'int'
510-
// CHECK-NEXT: `-CXXDefaultInitExpr {{.*}} 'int' contains-errors
510+
// CHECK-NEXT: `-CXXDefaultInitExpr {{.*}} 'int' contains-errors has rewritten init
511511
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
512512
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
513513
void foo() {

clang/test/Analysis/lifetime-extended-regions.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,11 @@ void aggregateWithReferences() {
121121
clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
122122
clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}
123123

124-
// The lifetime of object bound to reference members of aggregates,
125-
// that are created from default member initializer was extended.
124+
// FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
125+
// that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
126+
// The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
126127
RefAggregate defaultInitExtended{i};
127-
clang_analyzer_dump(defaultInitExtended.ry); // expected-warning-re {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
128+
clang_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }}
128129
}
129130

130131
void lambda() {

clang/test/SemaCXX/cxx2c-placeholder-vars.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,16 @@ void f() {
274274
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct A definition
275275
// CHECK: CXXConstructorDecl {{.*}} implicit used constexpr A 'void () noexcept'
276276
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
277-
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int'
277+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
278278
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
279279
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
280-
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int'
280+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
281281
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
282282
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} 'a' 'int'
283-
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int'
283+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
284284
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
285285
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
286-
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int'
286+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
287287
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
288288
// CHECK-NEXT: CompoundStmt {{.*}}
289289

0 commit comments

Comments
 (0)