[clang] [clang][bytecode] Always initialize scope before conditional operator (PR #171133)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `llvm-clang-x86_64-gcc-ubuntu` running on `sie-linux-worker3` while building `clang` at step 6 "test-build-unified-tree-check-all". Full details are available at: https://lab.llvm.org/buildbot/#/builders/174/builds/28604 Here is the relevant piece of the build log for the reference ``` Step 6 (test-build-unified-tree-check-all) failure: test (failure) TEST 'SanitizerCommon-asan-x86_64-Linux :: Linux/soft_rss_limit_mb_test.cpp' FAILED Exit Code: 1 Command Output (stdout): -- # RUN: at line 2 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang --driver-mode=g++ -gline-tables-only -fsanitize=address -m64 -funwind-tables -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test -ldl -O2 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp # executed command: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang --driver-mode=g++ -gline-tables-only -fsanitize=address -m64 -funwind-tables -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test -ldl -O2 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp # note: command had no output on stdout or stderr # RUN: at line 5 env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=1 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp 2>&1 | FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -check-prefix=CHECK_MAY_RETURN_1 # executed command: env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=1 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp # note: command had no output on stdout or stderr # executed command: FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -check-prefix=CHECK_MAY_RETURN_1 # note: command had no output on stdout or stderr # RUN: at line 6 env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=0 not /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp 2>&1 | FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -check-prefix=CHECK_MAY_RETURN_0 --implicit-check-not="returned null" # executed command: env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=0 not /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp # note: command had no output on stdout or stderr # executed command: FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -check-prefix=CHECK_MAY_RETURN_0 '--implicit-check-not=returned null' # note: command had no output on stdout or stderr # RUN: at line 10 env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=0:can_use_proc_maps_statm=0 not /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/soft_rss_limit_mb_test.cpp.tmp 2>&1 | FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp -check-prefix=CHECK_MAY_RETURN_0 --implicit-check-not="returned null" # executed command: env ASAN_OPTIONS=soft_rss_limit_mb=250:quarantine_size=1:allocator_may_return_null=0:can_use_proc_maps_statm=0 not /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/asan-x86_64-Linux/Linux/Output/sof
[clang] [clang][bytecode] Always initialize scope before conditional operator (PR #171133)
https://github.com/tbaederr closed https://github.com/llvm/llvm-project/pull/171133 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][bytecode] Always initialize scope before conditional operator (PR #171133)
llvmbot wrote:
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
Changes
Otherwise, the scope might be (lazily) initialized in one of the arms of the
conditional operator, which means the will NOT be intialized in the other arm.
Fixes https://github.com/llvm/llvm-project/issues/170981
---
Full diff: https://github.com/llvm/llvm-project/pull/171133.diff
3 Files Affected:
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+9-7)
- (modified) clang/lib/AST/ByteCode/Compiler.h (+14-2)
- (modified) clang/test/AST/ByteCode/cxx20.cpp (+14)
``diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp
b/clang/lib/AST/ByteCode/Compiler.cpp
index 14b6bb7bf61d5..ed5493c315dd7 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2503,6 +2503,15 @@ bool Compiler::VisitAbstractConditionalOperator(
const Expr *TrueExpr = E->getTrueExpr();
const Expr *FalseExpr = E->getFalseExpr();
+ if (std::optional BoolValue = getBoolValue(Condition)) {
+if (*BoolValue)
+ return this->delegate(TrueExpr);
+return this->delegate(FalseExpr);
+ }
+
+ // Force-init the scope, which creates a InitScope op. This is necessary so
+ // the scope is not only initialized in one arm of the conditional operator.
+ this->VarScope->forceInit();
// The TrueExpr and FalseExpr of a conditional operator do _not_ create a
// scope, which means the local variables created within them unconditionally
// always exist. However, we need to later differentiate which branch was
@@ -2510,13 +2519,6 @@ bool Compiler::VisitAbstractConditionalOperator(
// "enabled" flags on local variables are used for.
llvm::SaveAndRestore LAAA(this->VarScope->LocalsAlwaysEnabled,
/*NewValue=*/false);
-
- if (std::optional BoolValue = getBoolValue(Condition)) {
-if (*BoolValue)
- return this->delegate(TrueExpr);
-return this->delegate(FalseExpr);
- }
-
bool IsBcpCall = false;
if (const auto *CE = dyn_cast(Condition->IgnoreParenCasts());
CE && CE->getBuiltinCallee() == Builtin::BI__builtin_constant_p) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h
b/clang/lib/AST/ByteCode/Compiler.h
index c641af52c2811..1bd15c3d79563 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -505,6 +505,7 @@ template class VariableScope {
virtual bool emitDestructors(const Expr *E = nullptr) { return true; }
virtual bool destroyLocals(const Expr *E = nullptr) { return true; }
+ virtual void forceInit() {}
VariableScope *getParent() const { return Parent; }
ScopeKind getKind() const { return Kind; }
@@ -534,7 +535,6 @@ template class LocalScope : public
VariableScope {
this->Ctx->emitDestroy(*Idx, SourceInfo{});
removeStoredOpaqueValues();
}
-
/// Explicit destruction of local variables.
bool destroyLocals(const Expr *E = nullptr) override {
if (!Idx)
@@ -558,10 +558,22 @@ template class LocalScope : public
VariableScope {
this->Ctx->Descriptors[*Idx].emplace_back(Local);
}
+ /// Force-initialize this scope. Usually, scopes are lazily initialized when
+ /// the first local variable is created, but in scenarios with conditonal
+ /// operators, we need to ensure scope is initialized just in case one of the
+ /// arms will create a local and the other won't. In such a case, the
+ /// InitScope() op would be part of the arm that created the local.
+ void forceInit() override {
+if (!Idx) {
+ Idx = static_cast(this->Ctx->Descriptors.size());
+ this->Ctx->Descriptors.emplace_back();
+ this->Ctx->emitInitScope(*Idx, {});
+}
+ }
+
bool emitDestructors(const Expr *E = nullptr) override {
if (!Idx)
return true;
-assert(!this->Ctx->Descriptors[*Idx].empty());
// Emit destructor calls for local variables of record
// type with a destructor.
diff --git a/clang/test/AST/ByteCode/cxx20.cpp
b/clang/test/AST/ByteCode/cxx20.cpp
index ea4843e95b01f..227f34cee80ff 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -1211,3 +1211,17 @@ namespace DyamicCast {
constexpr const X *p = &y;
constexpr const Y *q = dynamic_cast(p);
}
+
+namespace ConditionalTemporaries {
+ class F {
+ public:
+constexpr F(int a ) {this->a = a;}
+constexpr ~F() {}
+int a;
+ };
+ constexpr int foo(bool b) {
+return b ? F{12}.a : F{13}.a;
+ }
+ static_assert(foo(false)== 13);
+ static_assert(foo(true)== 12);
+}
``
https://github.com/llvm/llvm-project/pull/171133
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][bytecode] Always initialize scope before conditional operator (PR #171133)
https://github.com/tbaederr created
https://github.com/llvm/llvm-project/pull/171133
Otherwise, the scope might be (lazily) initialized in one of the arms of the
conditional operator, which means the will NOT be intialized in the other arm.
Fixes https://github.com/llvm/llvm-project/issues/170981
>From 43e90aa06c40d4025833351f788114e531430f8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?=
Date: Mon, 8 Dec 2025 14:56:02 +0100
Subject: [PATCH] [clang][bytecode] Always initialize scope before conditional
operator
Otherwise, the scope might be (lazily) initialized in one of the arms
of the conditional operator, which means the will NOT be intialized in
the other arm.
Fixes https://github.com/llvm/llvm-project/issues/170981
---
clang/lib/AST/ByteCode/Compiler.cpp | 16 +---
clang/lib/AST/ByteCode/Compiler.h | 16 ++--
clang/test/AST/ByteCode/cxx20.cpp | 14 ++
3 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp
b/clang/lib/AST/ByteCode/Compiler.cpp
index 14b6bb7bf61d5..ed5493c315dd7 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2503,6 +2503,15 @@ bool Compiler::VisitAbstractConditionalOperator(
const Expr *TrueExpr = E->getTrueExpr();
const Expr *FalseExpr = E->getFalseExpr();
+ if (std::optional BoolValue = getBoolValue(Condition)) {
+if (*BoolValue)
+ return this->delegate(TrueExpr);
+return this->delegate(FalseExpr);
+ }
+
+ // Force-init the scope, which creates a InitScope op. This is necessary so
+ // the scope is not only initialized in one arm of the conditional operator.
+ this->VarScope->forceInit();
// The TrueExpr and FalseExpr of a conditional operator do _not_ create a
// scope, which means the local variables created within them unconditionally
// always exist. However, we need to later differentiate which branch was
@@ -2510,13 +2519,6 @@ bool Compiler::VisitAbstractConditionalOperator(
// "enabled" flags on local variables are used for.
llvm::SaveAndRestore LAAA(this->VarScope->LocalsAlwaysEnabled,
/*NewValue=*/false);
-
- if (std::optional BoolValue = getBoolValue(Condition)) {
-if (*BoolValue)
- return this->delegate(TrueExpr);
-return this->delegate(FalseExpr);
- }
-
bool IsBcpCall = false;
if (const auto *CE = dyn_cast(Condition->IgnoreParenCasts());
CE && CE->getBuiltinCallee() == Builtin::BI__builtin_constant_p) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h
b/clang/lib/AST/ByteCode/Compiler.h
index c641af52c2811..1bd15c3d79563 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -505,6 +505,7 @@ template class VariableScope {
virtual bool emitDestructors(const Expr *E = nullptr) { return true; }
virtual bool destroyLocals(const Expr *E = nullptr) { return true; }
+ virtual void forceInit() {}
VariableScope *getParent() const { return Parent; }
ScopeKind getKind() const { return Kind; }
@@ -534,7 +535,6 @@ template class LocalScope : public
VariableScope {
this->Ctx->emitDestroy(*Idx, SourceInfo{});
removeStoredOpaqueValues();
}
-
/// Explicit destruction of local variables.
bool destroyLocals(const Expr *E = nullptr) override {
if (!Idx)
@@ -558,10 +558,22 @@ template class LocalScope : public
VariableScope {
this->Ctx->Descriptors[*Idx].emplace_back(Local);
}
+ /// Force-initialize this scope. Usually, scopes are lazily initialized when
+ /// the first local variable is created, but in scenarios with conditonal
+ /// operators, we need to ensure scope is initialized just in case one of the
+ /// arms will create a local and the other won't. In such a case, the
+ /// InitScope() op would be part of the arm that created the local.
+ void forceInit() override {
+if (!Idx) {
+ Idx = static_cast(this->Ctx->Descriptors.size());
+ this->Ctx->Descriptors.emplace_back();
+ this->Ctx->emitInitScope(*Idx, {});
+}
+ }
+
bool emitDestructors(const Expr *E = nullptr) override {
if (!Idx)
return true;
-assert(!this->Ctx->Descriptors[*Idx].empty());
// Emit destructor calls for local variables of record
// type with a destructor.
diff --git a/clang/test/AST/ByteCode/cxx20.cpp
b/clang/test/AST/ByteCode/cxx20.cpp
index ea4843e95b01f..227f34cee80ff 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -1211,3 +1211,17 @@ namespace DyamicCast {
constexpr const X *p = &y;
constexpr const Y *q = dynamic_cast(p);
}
+
+namespace ConditionalTemporaries {
+ class F {
+ public:
+constexpr F(int a ) {this->a = a;}
+constexpr ~F() {}
+int a;
+ };
+ constexpr int foo(bool b) {
+return b ? F{12}.a : F{13}.a;
+ }
+ static_assert(foo(false)== 13);
+ static_assert(foo(true)== 12);
+}
___
cfe-commits
