Skip to content

Commit c138801

Browse files
committed
[Clang] Correctly handle allocations in the condition of a if constexpr
Deal with the following scenario ```cpp struct S { char* c = new char; constexpr ~S() { delete c; } }; if constexpr((S{}, true)){}; ``` There were two issues - We need to produce a full expressions _before_ evaluating the condition (otherwise automatic variables are neber destroyed) - We need to preserve the evaluation context of the condition while doing the semantics analysis for it (lest it is evaluated in a non constant evaluated context) Fixes #120197 Fixes #134820
1 parent a75587d commit c138801

File tree

6 files changed

+58
-18
lines changed

6 files changed

+58
-18
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,7 @@ Bug Fixes to C++ Support
896896
- Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835)
897897
- Fixed an access checking bug when substituting into concepts (#GH115838)
898898
- Fix a bug where private access specifier of overloaded function not respected. (#GH107629)
899+
- Correctly handle allocations in the condition of a ``if constexpr``.(#GH120197) (#GH134820)
899900

900901
Bug Fixes to AST Handling
901902
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7723,12 +7723,12 @@ class Sema final : public SemaBase {
77237723

77247724
class ConditionResult {
77257725
Decl *ConditionVar;
7726-
FullExprArg Condition;
7726+
ExprResult Condition;
77277727
bool Invalid;
77287728
std::optional<bool> KnownValue;
77297729

77307730
friend class Sema;
7731-
ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition,
7731+
ConditionResult(Sema &S, Decl *ConditionVar, ExprResult Condition,
77327732
bool IsConstexpr)
77337733
: ConditionVar(ConditionVar), Condition(Condition), Invalid(false) {
77347734
if (IsConstexpr && Condition.get()) {
@@ -7739,7 +7739,7 @@ class Sema final : public SemaBase {
77397739
}
77407740
}
77417741
explicit ConditionResult(bool Invalid)
7742-
: ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid),
7742+
: ConditionVar(nullptr), Condition(Invalid), Invalid(Invalid),
77437743
KnownValue(std::nullopt) {}
77447744

77457745
public:

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,15 +1931,13 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
19311931
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
19321932
}
19331933

1934-
ExprResult Expr = [&] {
1935-
EnterExpressionEvaluationContext Eval(
1936-
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
1937-
/*LambdaContextDecl=*/nullptr,
1938-
/*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_Other,
1939-
/*ShouldEnter=*/CK == Sema::ConditionKind::ConstexprIf);
1940-
// Parse the expression.
1941-
return ParseExpression(); // expression
1942-
}();
1934+
EnterExpressionEvaluationContext Eval(
1935+
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
1936+
/*LambdaContextDecl=*/nullptr,
1937+
/*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_Other,
1938+
/*ShouldEnter=*/CK == Sema::ConditionKind::ConstexprIf);
1939+
1940+
ExprResult Expr = ParseExpression();
19431941

19441942
if (Expr.isInvalid())
19451943
return Sema::ConditionError();

clang/lib/Sema/SemaExpr.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20629,6 +20629,9 @@ Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc,
2062920629

2063020630
case ConditionKind::ConstexprIf:
2063120631
Cond = CheckBooleanCondition(Loc, SubExpr, true);
20632+
assert(isa<FullExpr>(Cond.get()) &&
20633+
"we should have converted this expression to a FullExpr before "
20634+
"evaluating it");
2063220635
break;
2063320636

2063420637
case ConditionKind::Switch:
@@ -20641,12 +20644,10 @@ Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc,
2064120644
if (!Cond.get())
2064220645
return ConditionError();
2064320646
}
20644-
// FIXME: FullExprArg doesn't have an invalid bit, so check nullness instead.
20645-
FullExprArg FullExpr = MakeFullExpr(Cond.get(), Loc);
20646-
if (!FullExpr.get())
20647-
return ConditionError();
20647+
if (!isa<FullExpr>(Cond.get()))
20648+
Cond = ActOnFinishFullExpr(Cond.get(), Loc, /*DiscardedValue*/ false);
2064820649

20649-
return ConditionResult(*this, nullptr, FullExpr,
20650+
return ConditionResult(*this, nullptr, Cond,
2065020651
CK == ConditionKind::ConstexprIf);
2065120652
}
2065220653

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4357,7 +4357,8 @@ Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar,
43574357
CheckConditionVariable(cast<VarDecl>(ConditionVar), StmtLoc, CK);
43584358
if (E.isInvalid())
43594359
return ConditionError();
4360-
return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc),
4360+
E = ActOnFinishFullExpr(E.get(), /*DiscardedValue*/ false);
4361+
return ConditionResult(*this, ConditionVar, E,
43614362
CK == ConditionKind::ConstexprIf);
43624363
}
43634364

@@ -4417,6 +4418,12 @@ ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) {
44174418
if (!IsConstexpr || E.isInvalid() || E.get()->isValueDependent())
44184419
return E;
44194420

4421+
E = ActOnFinishFullExpr(E.get(), E.get()->getExprLoc(),
4422+
/*DiscardedValue*/ false,
4423+
/*IsConstexpr*/ true);
4424+
if (E.isInvalid())
4425+
return E;
4426+
44204427
// FIXME: Return this value to the caller so they don't need to recompute it.
44214428
llvm::APSInt Cond;
44224429
E = VerifyIntegerConstantExpression(

clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,36 @@ void f() {
242242
}
243243

244244
}
245+
246+
namespace GH134820 {
247+
struct S {
248+
char* c = new char;
249+
constexpr ~S() {
250+
delete c;
251+
}
252+
};
253+
254+
int f() {
255+
if constexpr((S{}, true)) {
256+
return 1;
257+
}
258+
return 0;
259+
}
260+
}
261+
262+
namespace GH120197{
263+
struct NonTrivialDtor {
264+
NonTrivialDtor() = default;
265+
NonTrivialDtor(const NonTrivialDtor&) = default;
266+
NonTrivialDtor(NonTrivialDtor&&) = default;
267+
NonTrivialDtor& operator=(const NonTrivialDtor&) = default;
268+
NonTrivialDtor& operator=(NonTrivialDtor&&) = default;
269+
constexpr ~NonTrivialDtor() noexcept {}
270+
};
271+
272+
static_assert(((void)NonTrivialDtor{}, true)); // passes
273+
274+
void f() {
275+
if constexpr ((void)NonTrivialDtor{}, true) {}
276+
}
277+
}

0 commit comments

Comments
 (0)