C++: Support if consteval and if ! consteval

This commit is contained in:
Jeroen Ketema
2025-01-15 19:59:52 +01:00
parent 84c674b992
commit bc2f203c4b
14 changed files with 902 additions and 0 deletions

View File

@@ -912,6 +912,10 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
or
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
or
s.(ConstevalOrNotConstevalIfStmt).getThen() = e and pred = "getThen()"
or
s.(ConstevalOrNotConstevalIfStmt).getElse() = e and pred = "getElse()"
or
s.(Handler).getParameter() = e and pred = "getParameter()"
or
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"

View File

@@ -876,6 +876,25 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
p2.nodeAfter(n2, s)
)
or
// ConstevalOrNotConstevalIfStmt -> { then, else } ->
exists(ConstevalOrNotConstevalIfStmt s |
p1.nodeAt(n1, s) and
p2.nodeBefore(n2, s.getThen())
or
p1.nodeAt(n1, s) and
p2.nodeBefore(n2, s.getElse())
or
p1.nodeAt(n1, s) and
not exists(s.getElse()) and
p2.nodeAfter(n2, s)
or
p1.nodeAfter(n1, s.getThen()) and
p2.nodeAfter(n2, s)
or
p1.nodeAfter(n1, s.getElse()) and
p2.nodeAfter(n2, s)
)
or
// WhileStmt -> condition ; body -> condition ; after dtors -> after
exists(WhileStmt s |
p1.nodeAt(n1, s) and

View File

@@ -1098,6 +1098,61 @@ class TranslatedConstExprIfStmt extends TranslatedIfLikeStmt {
override predicate hasElse() { exists(stmt.getElse()) }
}
class TranslatedConstevalOrNotConstevalIfStmt extends TranslatedStmt {
override ConstevalOrNotConstevalIfStmt stmt;
override Instruction getFirstInstruction(EdgeKind kind) {
if not this.hasEvaluatedBranch()
then
kind instanceof GotoEdge and
result = this.getInstruction(OnlyInstructionTag())
else result = this.getEvaluatedBranch().getFirstInstruction(kind)
}
override TranslatedElement getChildInternal(int id) {
id = 0 and
result = this.getThen()
or
id = 1 and
result = this.getElse()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
not this.hasEvaluatedBranch() and
opcode instanceof Opcode::NoOp and
tag = OnlyInstructionTag() and
resultType = getVoidType()
}
override Instruction getALastInstructionInternal() {
if not this.hasEvaluatedBranch()
then result = this.getInstruction(OnlyInstructionTag())
else result = this.getEvaluatedBranch().getALastInstruction()
}
override TranslatedElement getLastChild() { result = this.getEvaluatedBranch() }
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
(child = this.getThen() or child = this.getElse()) and
result = this.getParent().getChildSuccessor(this, kind)
}
TranslatedStmt getEvaluatedBranch() {
result = getTranslatedStmt(stmt.getRuntimeEvaluatedBranch())
}
predicate hasEvaluatedBranch() { stmt.hasRuntimeEvaluatedBranch() }
TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
}
abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
override Loop stmt;

View File

@@ -437,6 +437,168 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
}
}
/**
* A C/C++ '(not) consteval if'. For example, the `if consteval` statement
* in the following code:
* ```cpp
* if consteval {
* ...
* }
* ```
*/
class ConstevalOrNotConstevalIfStmt extends Stmt, @stmt_consteval_or_not_consteval_if {
/**
* Gets the 'then' statement of this '(not) consteval if' statement.
*
* For example, for
* ```cpp
* if consteval { return true; }
* ```
* the result is the `BlockStmt` `{ return true; }`.
*/
Stmt getThen() { consteval_if_then(underlyingElement(this), unresolveElement(result)) }
/**
* Gets the 'else' statement of this '(not) constexpr if' statement, if any.
*
* For example, for
* ```cpp
* if consteval { return true; } else { return false; }
* ```
* the result is the `BlockStmt` `{ return false; }`, and for
* ```cpp
* if consteval { return true; }
* ```
* there is no result.
*/
Stmt getElse() { consteval_if_else(underlyingElement(this), unresolveElement(result)) }
/**
* Holds if this '(not) constexpr if' statement has an 'else' statement.
*
* For example, this holds for
* ```cpp
* if consteval { return true; } else { return false; }
* ```
* but not for
* ```cpp
* if consteval { return true; }
* ```
*/
predicate hasElse() { exists(this.getElse()) }
override predicate mayBeImpure() {
this.getThen().mayBeImpure() or
this.getElse().mayBeImpure()
}
override predicate mayBeGloballyImpure() {
this.getThen().mayBeGloballyImpure() or
this.getElse().mayBeGloballyImpure()
}
override MacroInvocation getGeneratingMacro() {
this.getThen().getGeneratingMacro() = result and
(this.hasElse() implies this.getElse().getGeneratingMacro() = result)
}
/**
* Gets the statement of this '(not) consteval if' statement evaluated during compile time, if any.
*
* For example, for
* ```cpp
* if ! consteval { return true; } else { return false; }
* ```
* the result is the `BlockStmt` `{ return false; }`, and for
* ```cpp
* if ! consteval { return true; }
* ```
* there is no result.
*/
Stmt getCompileTimeEvaluatedBranch() { none() }
/**
* Holds if this '(not) constexpr if' statement has a compile time evaluated statement.
*
* For example, this holds for
* ```cpp
* if ! consteval { return true; } else { return false; }
* ```
* but not for
* ```cpp
* if ! consteval { return true; }
* ```
*/
predicate hasCompileTimeEvaluatedBranch() { exists(this.getCompileTimeEvaluatedBranch()) }
/**
* Gets the statement of this '(not) consteval if' statement evaluated during runtime, if any.
*
* For example, for
* ```cpp
* if consteval { return true; } else { return false; }
* ```
* the result is the `BlockStmt` `{ return false; }`, and for
* ```cpp
* if consteval { return true; }
* ```
* there is no result.
*/
Stmt getRuntimeEvaluatedBranch() { none() }
/**
* Holds if this '(not) constexpr if' statement has a runtime evaluated statement.
*
* For example, this holds for
* ```cpp
* if consteval { return true; } else { return false; }
* ```
* but not for
* ```cpp
* if consteval { return true; }
* ```
*/
predicate hasRuntimeEvaluatedBranch() { exists(this.getRuntimeEvaluatedBranch()) }
}
/**
* A C/C++ 'consteval if'. For example, the `if consteval` statement
* in the following code:
* ```cpp
* if consteval {
* ...
* }
* ```
*/
class ConstevalIfStmt extends ConstevalOrNotConstevalIfStmt, @stmt_consteval_if {
override string getAPrimaryQlClass() { result = "ConstevalIfStmt" }
override string toString() { result = "if consteval ..." }
override Stmt getCompileTimeEvaluatedBranch() { result = this.getThen() }
override Stmt getRuntimeEvaluatedBranch() { result = this.getElse() }
}
/**
* A C/C++ 'not consteval if'. For example, the `if ! consteval` statement
* in the following code:
* ```cpp
* if ! consteval {
* ...
* }
* ```
*/
class NotConstevalIfStmt extends ConstevalOrNotConstevalIfStmt, @stmt_not_consteval_if {
override string getAPrimaryQlClass() { result = "NotConstevalIfStmt" }
override string toString() { result = "if ! consteval ..." }
override Stmt getCompileTimeEvaluatedBranch() { result = this.getElse() }
override Stmt getRuntimeEvaluatedBranch() { result = this.getThen() }
}
private class TLoop = @stmt_while or @stmt_end_test_while or @stmt_range_based_for or @stmt_for;
/**

View File

@@ -2152,6 +2152,8 @@ case @stmt.kind of
// ... 34 @stmt_finally_end deprecated
| 35 = @stmt_constexpr_if
| 37 = @stmt_co_return
| 38 = @stmt_consteval_if
| 39 = @stmt_not_consteval_if
;
type_vla(
@@ -2194,6 +2196,18 @@ constexpr_if_else(
int else_id: @stmt ref
);
@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if;
consteval_if_then(
unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
int then_id: @stmt ref
);
consteval_if_else(
unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
int else_id: @stmt ref
);
while_body(
unique int while_stmt: @stmt_while ref,
int body_id: @stmt ref

View File

@@ -0,0 +1,124 @@
| ClassWithDestructor::ClassWithDestructor | false | 157 | 157 | ClassWithDestructor |
| ClassWithDestructor::ClassWithDestructor | false | 296 | 296 | ClassWithDestructor |
| ClassWithDestructor::ClassWithDestructor | false | 302 | 302 | ClassWithDestructor |
| ClassWithDestructor::operator bool | false | 173 | 173 | operator bool |
| ClassWithDestructor::operator= | false | 288 | 288 | operator= |
| ClassWithDestructor::~ClassWithDestructor | false | 190 | 190 | ~ClassWithDestructor |
| __va_list_tag::operator= | false | 66 | 66 | operator= |
| __va_list_tag::operator= | false | 72 | 72 | operator= |
| destruction_on_consteval | false | 193 | 193 | destruction_on_consteval |
| destruction_on_consteval | false | 198 | 198 | if consteval ... |
| destruction_on_consteval | false | 200 | 200 | return ... |
| destruction_on_consteval | false | 204 | 204 | 1 |
| destruction_on_consteval | false | 205 | 205 | { ... } |
| destruction_on_consteval | false | 208 | 208 | call to ClassWithDestructor |
| destruction_on_consteval | false | 210 | 210 | initializer for cwd |
| destruction_on_consteval | false | 213 | 213 | declaration |
| destruction_on_consteval | false | 215 | 215 | return ... |
| destruction_on_consteval | false | 218 | 218 | call to operator bool |
| destruction_on_consteval | false | 219 | 219 | cwd |
| destruction_on_consteval | false | 221 | 221 | (const ClassWithDestructor)... |
| destruction_on_consteval | false | 222 | 222 | { ... } |
| destruction_on_consteval | false | 224 | 224 | { ... } |
| destruction_on_consteval | false | 226 | 226 | cwd |
| destruction_on_consteval | false | 228 | 228 | call to cwd.~ClassWithDestructor |
| destruction_on_consteval | false | 229 | 229 | cwd |
| destruction_on_consteval | false | 230 | 230 | call to cwd.~ClassWithDestructor |
| destruction_on_consteval | true | 198 | 205 | |
| destruction_on_consteval | true | 198 | 222 | |
| destruction_on_consteval | true | 200 | 204 | |
| destruction_on_consteval | true | 204 | 193 | |
| destruction_on_consteval | true | 205 | 200 | |
| destruction_on_consteval | true | 208 | 215 | |
| destruction_on_consteval | true | 210 | 208 | |
| destruction_on_consteval | true | 213 | 210 | |
| destruction_on_consteval | true | 215 | 219 | |
| destruction_on_consteval | true | 218 | 226 | |
| destruction_on_consteval | true | 219 | 218 | |
| destruction_on_consteval | true | 222 | 213 | |
| destruction_on_consteval | true | 224 | 198 | |
| destruction_on_consteval | true | 226 | 228 | |
| destruction_on_consteval | true | 228 | 193 | |
| destruction_on_consteval | true | 229 | 230 | |
| destruction_on_consteval | true | 230 | 193 | |
| destruction_on_consteval2 | false | 147 | 147 | destruction_on_consteval2 |
| destruction_on_consteval2 | false | 152 | 152 | declaration |
| destruction_on_consteval2 | false | 155 | 155 | call to ClassWithDestructor |
| destruction_on_consteval2 | false | 158 | 158 | initializer for cwd |
| destruction_on_consteval2 | false | 161 | 161 | if consteval ... |
| destruction_on_consteval2 | false | 163 | 163 | return ... |
| destruction_on_consteval2 | false | 167 | 167 | 1 |
| destruction_on_consteval2 | false | 168 | 168 | { ... } |
| destruction_on_consteval2 | false | 170 | 170 | return ... |
| destruction_on_consteval2 | false | 178 | 178 | call to operator bool |
| destruction_on_consteval2 | false | 179 | 179 | cwd |
| destruction_on_consteval2 | false | 182 | 182 | (const ClassWithDestructor)... |
| destruction_on_consteval2 | false | 183 | 183 | { ... } |
| destruction_on_consteval2 | false | 185 | 185 | { ... } |
| destruction_on_consteval2 | false | 187 | 187 | cwd |
| destruction_on_consteval2 | false | 189 | 189 | call to cwd.~ClassWithDestructor |
| destruction_on_consteval2 | false | 191 | 191 | cwd |
| destruction_on_consteval2 | false | 192 | 192 | call to cwd.~ClassWithDestructor |
| destruction_on_consteval2 | true | 152 | 158 | |
| destruction_on_consteval2 | true | 155 | 161 | |
| destruction_on_consteval2 | true | 158 | 155 | |
| destruction_on_consteval2 | true | 161 | 168 | |
| destruction_on_consteval2 | true | 161 | 183 | |
| destruction_on_consteval2 | true | 163 | 167 | |
| destruction_on_consteval2 | true | 167 | 187 | |
| destruction_on_consteval2 | true | 168 | 163 | |
| destruction_on_consteval2 | true | 170 | 179 | |
| destruction_on_consteval2 | true | 178 | 191 | |
| destruction_on_consteval2 | true | 179 | 178 | |
| destruction_on_consteval2 | true | 183 | 170 | |
| destruction_on_consteval2 | true | 185 | 152 | |
| destruction_on_consteval2 | true | 187 | 189 | |
| destruction_on_consteval2 | true | 189 | 147 | |
| destruction_on_consteval2 | true | 191 | 192 | |
| destruction_on_consteval2 | true | 192 | 147 | |
| test | false | 231 | 231 | test |
| test | false | 236 | 236 | declaration |
| test | false | 241 | 241 | if consteval ... |
| test | false | 243 | 243 | ExprStmt |
| test | false | 245 | 245 | x |
| test | false | 249 | 249 | 1 |
| test | false | 250 | 250 | ... = ... |
| test | false | 252 | 252 | { ... } |
| test | false | 254 | 254 | ExprStmt |
| test | false | 256 | 256 | x |
| test | false | 260 | 260 | 2 |
| test | false | 261 | 261 | ... = ... |
| test | false | 263 | 263 | { ... } |
| test | false | 265 | 265 | if consteval ... |
| test | false | 267 | 267 | ExprStmt |
| test | false | 269 | 269 | x |
| test | false | 273 | 273 | 3 |
| test | false | 274 | 274 | ... = ... |
| test | false | 276 | 276 | { ... } |
| test | false | 278 | 278 | return ... |
| test | false | 280 | 280 | x |
| test | false | 282 | 282 | (bool)... |
| test | false | 283 | 283 | { ... } |
| test | true | 236 | 241 | |
| test | true | 241 | 252 | |
| test | true | 241 | 263 | |
| test | true | 243 | 249 | |
| test | true | 245 | 250 | |
| test | true | 249 | 245 | |
| test | true | 250 | 265 | |
| test | true | 252 | 243 | |
| test | true | 254 | 260 | |
| test | true | 256 | 261 | |
| test | true | 260 | 256 | |
| test | true | 261 | 265 | |
| test | true | 263 | 254 | |
| test | true | 265 | 276 | |
| test | true | 265 | 278 | |
| test | true | 267 | 273 | |
| test | true | 269 | 274 | |
| test | true | 273 | 269 | |
| test | true | 274 | 278 | |
| test | true | 276 | 267 | |
| test | true | 278 | 280 | |
| test | true | 280 | 231 | |
| test | true | 283 | 236 | |

View File

@@ -0,0 +1,42 @@
/**
* query-type: graph
*
* @kind graph-equivalence-test
*/
import cpp
class DestructorCallEnhanced extends DestructorCall {
override string toString() {
if exists(this.getQualifier().(VariableAccess).getTarget().getName())
then
result =
"call to " + this.getQualifier().(VariableAccess).getTarget().getName() + "." +
this.getTarget().getName()
else result = super.toString()
}
}
string scope(ControlFlowNode x) {
if exists(x.getControlFlowScope().getQualifiedName())
then result = x.getControlFlowScope().getQualifiedName()
else result = "<no scope>"
}
predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
isEdge = false and x = y and label = x.toString()
}
predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
exists(string truelabel, string falselabel |
isEdge = true and
x.getASuccessor() = y and
(if x.getATrueSuccessor() = y then truelabel = "T" else truelabel = "") and
(if x.getAFalseSuccessor() = y then falselabel = "F" else falselabel = "") and
label = truelabel + falselabel
)
}
from boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label
where isNode(isEdge, x, y, label) or isSuccessor(isEdge, x, y, label)
select scope(x), isEdge, x, y, label

View File

@@ -0,0 +1,25 @@
| test.cpp:3:23:14:1 | { ... } |
| test.cpp:4:5:4:10 | declaration |
| test.cpp:5:5:9:5 | if consteval ... |
| test.cpp:5:18:7:5 | { ... } |
| test.cpp:6:9:6:14 | ExprStmt |
| test.cpp:7:12:9:5 | { ... } |
| test.cpp:8:9:8:14 | ExprStmt |
| test.cpp:10:5:12:5 | if consteval ... |
| test.cpp:10:18:12:5 | { ... } |
| test.cpp:11:9:11:14 | ExprStmt |
| test.cpp:13:5:13:13 | return ... |
| test.cpp:24:33:31:1 | { ... } |
| test.cpp:25:3:30:3 | if consteval ... |
| test.cpp:25:16:27:3 | { ... } |
| test.cpp:26:5:26:16 | return ... |
| test.cpp:27:10:30:3 | { ... } |
| test.cpp:28:5:28:28 | declaration |
| test.cpp:29:5:29:15 | return ... |
| test.cpp:33:34:40:1 | { ... } |
| test.cpp:34:3:34:26 | declaration |
| test.cpp:35:3:39:3 | if consteval ... |
| test.cpp:35:16:37:3 | { ... } |
| test.cpp:36:5:36:16 | return ... |
| test.cpp:37:10:39:3 | { ... } |
| test.cpp:38:5:38:15 | return ... |

View File

@@ -0,0 +1,4 @@
import cpp
from Stmt s
select s

View File

@@ -0,0 +1,40 @@
// semmle-extractor-options: -std=c++23
constexpr bool test() {
int x;
if consteval {
x = 1;
} else {
x = 2;
}
if consteval {
x = 3;
}
return x;
}
struct ClassWithDestructor
{
ClassWithDestructor();
ClassWithDestructor(const char*);
~ClassWithDestructor();
operator bool() const;
};
bool destruction_on_consteval() {
if consteval {
return true;
} else {
ClassWithDestructor cwd;
return cwd;
}
}
bool destruction_on_consteval2() {
ClassWithDestructor cwd;
if consteval {
return true;
} else {
return cwd;
}
}

View File

@@ -24118,6 +24118,125 @@ ir.cpp:
# 2725| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2725| Type = [PlainCharType] char
# 2725| ValueCategory = prvalue(load)
ir23.cpp:
# 1| [TopLevelFunction] bool consteval_1()
# 1| <params>:
# 2| getEntryPoint(): [BlockStmt] { ... }
# 3| getStmt(0): [ConstevalIfStmt] if consteval ...
# 3| getThen(): [BlockStmt] { ... }
# 4| getStmt(0): [ReturnStmt] return ...
# 4| getExpr(): [Literal] 1
# 4| Type = [BoolType] bool
# 4| Value = [Literal] 1
# 4| ValueCategory = prvalue
# 5| getElse(): [BlockStmt] { ... }
# 6| getStmt(0): [ReturnStmt] return ...
# 6| getExpr(): [Literal] 0
# 6| Type = [BoolType] bool
# 6| Value = [Literal] 0
# 6| ValueCategory = prvalue
# 10| [TopLevelFunction] bool consteval_2()
# 10| <params>:
# 11| getEntryPoint(): [BlockStmt] { ... }
# 12| getStmt(0): [NotConstevalIfStmt] if ! consteval ...
# 12| getThen(): [BlockStmt] { ... }
# 13| getStmt(0): [ReturnStmt] return ...
# 13| getExpr(): [Literal] 1
# 13| Type = [BoolType] bool
# 13| Value = [Literal] 1
# 13| ValueCategory = prvalue
# 14| getElse(): [BlockStmt] { ... }
# 15| getStmt(0): [ReturnStmt] return ...
# 15| getExpr(): [Literal] 0
# 15| Type = [BoolType] bool
# 15| Value = [Literal] 0
# 15| ValueCategory = prvalue
# 19| [TopLevelFunction] bool consteval_3()
# 19| <params>:
# 20| getEntryPoint(): [BlockStmt] { ... }
# 21| getStmt(0): [ConstevalIfStmt] if consteval ...
# 21| getThen(): [BlockStmt] { ... }
# 22| getStmt(0): [ReturnStmt] return ...
# 22| getExpr(): [Literal] 1
# 22| Type = [BoolType] bool
# 22| Value = [Literal] 1
# 22| ValueCategory = prvalue
# 25| getStmt(1): [ReturnStmt] return ...
# 25| getExpr(): [Literal] 0
# 25| Type = [BoolType] bool
# 25| Value = [Literal] 0
# 25| ValueCategory = prvalue
# 28| [TopLevelFunction] bool consteval_4()
# 28| <params>:
# 29| getEntryPoint(): [BlockStmt] { ... }
# 30| getStmt(0): [NotConstevalIfStmt] if ! consteval ...
# 30| getThen(): [BlockStmt] { ... }
# 31| getStmt(0): [ReturnStmt] return ...
# 31| getExpr(): [Literal] 1
# 31| Type = [BoolType] bool
# 31| Value = [Literal] 1
# 31| ValueCategory = prvalue
# 34| getStmt(1): [ReturnStmt] return ...
# 34| getExpr(): [Literal] 0
# 34| Type = [BoolType] bool
# 34| Value = [Literal] 0
# 34| ValueCategory = prvalue
# 37| [TopLevelFunction] bool consteval_5()
# 37| <params>:
# 38| getEntryPoint(): [BlockStmt] { ... }
# 39| getStmt(0): [DeclStmt] declaration
# 39| getDeclarationEntry(0): [VariableDeclarationEntry] definition of r
# 39| Type = [BoolType] bool
# 39| getVariable().getInitializer(): [Initializer] initializer for r
# 39| getExpr(): [Literal] 1
# 39| Type = [BoolType] bool
# 39| Value = [Literal] 1
# 39| ValueCategory = prvalue
# 41| getStmt(1): [NotConstevalIfStmt] if ! consteval ...
# 41| getThen(): [BlockStmt] { ... }
# 42| getStmt(0): [ExprStmt] ExprStmt
# 42| getExpr(): [AssignExpr] ... = ...
# 42| Type = [BoolType] bool
# 42| ValueCategory = lvalue
# 42| getLValue(): [VariableAccess] r
# 42| Type = [BoolType] bool
# 42| ValueCategory = lvalue
# 42| getRValue(): [Literal] 0
# 42| Type = [BoolType] bool
# 42| Value = [Literal] 0
# 42| ValueCategory = prvalue
# 45| getStmt(2): [ReturnStmt] return ...
# 45| getExpr(): [VariableAccess] r
# 45| Type = [BoolType] bool
# 45| ValueCategory = prvalue(load)
# 48| [TopLevelFunction] bool consteval_6()
# 48| <params>:
# 49| getEntryPoint(): [BlockStmt] { ... }
# 50| getStmt(0): [DeclStmt] declaration
# 50| getDeclarationEntry(0): [VariableDeclarationEntry] definition of r
# 50| Type = [BoolType] bool
# 50| getVariable().getInitializer(): [Initializer] initializer for r
# 50| getExpr(): [Literal] 1
# 50| Type = [BoolType] bool
# 50| Value = [Literal] 1
# 50| ValueCategory = prvalue
# 52| getStmt(1): [ConstevalIfStmt] if consteval ...
# 52| getThen(): [BlockStmt] { ... }
# 53| getStmt(0): [ExprStmt] ExprStmt
# 53| getExpr(): [AssignExpr] ... = ...
# 53| Type = [BoolType] bool
# 53| ValueCategory = lvalue
# 53| getLValue(): [VariableAccess] r
# 53| Type = [BoolType] bool
# 53| ValueCategory = lvalue
# 53| getRValue(): [Literal] 0
# 53| Type = [BoolType] bool
# 53| Value = [Literal] 0
# 53| ValueCategory = prvalue
# 56| getStmt(2): [ReturnStmt] return ...
# 56| getExpr(): [VariableAccess] r
# 56| Type = [BoolType] bool
# 56| ValueCategory = prvalue(load)
many-defs-per-use.cpp:
# 34| [TopLevelFunction] void many_defs_per_use()
# 34| <params>:

View File

@@ -19740,6 +19740,104 @@ ir.cpp:
# 2724| v2724_12(void) = AliasedUse : ~m2725_8
# 2724| v2724_13(void) = ExitFunction :
ir23.cpp:
# 1| bool consteval_1()
# 1| Block 0
# 1| v1_1(void) = EnterFunction :
# 1| m1_2(unknown) = AliasedDefinition :
# 1| m1_3(unknown) = InitializeNonLocal :
# 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3
# 6| r6_1(glval<bool>) = VariableAddress[#return] :
# 6| r6_2(bool) = Constant[0] :
# 6| m6_3(bool) = Store[#return] : &:r6_1, r6_2
# 1| r1_5(glval<bool>) = VariableAddress[#return] :
# 1| v1_6(void) = ReturnValue : &:r1_5, m6_3
# 1| v1_7(void) = AliasedUse : m1_3
# 1| v1_8(void) = ExitFunction :
# 10| bool consteval_2()
# 10| Block 0
# 10| v10_1(void) = EnterFunction :
# 10| m10_2(unknown) = AliasedDefinition :
# 10| m10_3(unknown) = InitializeNonLocal :
# 10| m10_4(unknown) = Chi : total:m10_2, partial:m10_3
# 13| r13_1(glval<bool>) = VariableAddress[#return] :
# 13| r13_2(bool) = Constant[1] :
# 13| m13_3(bool) = Store[#return] : &:r13_1, r13_2
# 10| r10_5(glval<bool>) = VariableAddress[#return] :
# 10| v10_6(void) = ReturnValue : &:r10_5, m13_3
# 10| v10_7(void) = AliasedUse : m10_3
# 10| v10_8(void) = ExitFunction :
# 19| bool consteval_3()
# 19| Block 0
# 19| v19_1(void) = EnterFunction :
# 19| m19_2(unknown) = AliasedDefinition :
# 19| m19_3(unknown) = InitializeNonLocal :
# 19| m19_4(unknown) = Chi : total:m19_2, partial:m19_3
# 21| v21_1(void) = NoOp :
# 25| r25_1(glval<bool>) = VariableAddress[#return] :
# 25| r25_2(bool) = Constant[0] :
# 25| m25_3(bool) = Store[#return] : &:r25_1, r25_2
# 19| r19_5(glval<bool>) = VariableAddress[#return] :
# 19| v19_6(void) = ReturnValue : &:r19_5, m25_3
# 19| v19_7(void) = AliasedUse : m19_3
# 19| v19_8(void) = ExitFunction :
# 28| bool consteval_4()
# 28| Block 0
# 28| v28_1(void) = EnterFunction :
# 28| m28_2(unknown) = AliasedDefinition :
# 28| m28_3(unknown) = InitializeNonLocal :
# 28| m28_4(unknown) = Chi : total:m28_2, partial:m28_3
# 31| r31_1(glval<bool>) = VariableAddress[#return] :
# 31| r31_2(bool) = Constant[1] :
# 31| m31_3(bool) = Store[#return] : &:r31_1, r31_2
# 28| r28_5(glval<bool>) = VariableAddress[#return] :
# 28| v28_6(void) = ReturnValue : &:r28_5, m31_3
# 28| v28_7(void) = AliasedUse : m28_3
# 28| v28_8(void) = ExitFunction :
# 37| bool consteval_5()
# 37| Block 0
# 37| v37_1(void) = EnterFunction :
# 37| m37_2(unknown) = AliasedDefinition :
# 37| m37_3(unknown) = InitializeNonLocal :
# 37| m37_4(unknown) = Chi : total:m37_2, partial:m37_3
# 39| r39_1(glval<bool>) = VariableAddress[r] :
# 39| r39_2(bool) = Constant[1] :
# 39| m39_3(bool) = Store[r] : &:r39_1, r39_2
# 42| r42_1(bool) = Constant[0] :
# 42| r42_2(glval<bool>) = VariableAddress[r] :
# 42| m42_3(bool) = Store[r] : &:r42_2, r42_1
# 45| r45_1(glval<bool>) = VariableAddress[#return] :
# 45| r45_2(glval<bool>) = VariableAddress[r] :
# 45| r45_3(bool) = Load[r] : &:r45_2, m42_3
# 45| m45_4(bool) = Store[#return] : &:r45_1, r45_3
# 37| r37_5(glval<bool>) = VariableAddress[#return] :
# 37| v37_6(void) = ReturnValue : &:r37_5, m45_4
# 37| v37_7(void) = AliasedUse : m37_3
# 37| v37_8(void) = ExitFunction :
# 48| bool consteval_6()
# 48| Block 0
# 48| v48_1(void) = EnterFunction :
# 48| m48_2(unknown) = AliasedDefinition :
# 48| m48_3(unknown) = InitializeNonLocal :
# 48| m48_4(unknown) = Chi : total:m48_2, partial:m48_3
# 50| r50_1(glval<bool>) = VariableAddress[r] :
# 50| r50_2(bool) = Constant[1] :
# 50| m50_3(bool) = Store[r] : &:r50_1, r50_2
# 52| v52_1(void) = NoOp :
# 56| r56_1(glval<bool>) = VariableAddress[#return] :
# 56| r56_2(glval<bool>) = VariableAddress[r] :
# 56| r56_3(bool) = Load[r] : &:r56_2, m50_3
# 56| m56_4(bool) = Store[#return] : &:r56_1, r56_3
# 48| r48_5(glval<bool>) = VariableAddress[#return] :
# 48| v48_6(void) = ReturnValue : &:r48_5, m56_4
# 48| v48_7(void) = AliasedUse : m48_3
# 48| v48_8(void) = ExitFunction :
many-defs-per-use.cpp:
# 34| void many_defs_per_use()
# 34| Block 0

View File

@@ -0,0 +1,59 @@
constexpr bool consteval_1() noexcept
{
if consteval {
return true;
} else {
return false;
}
}
constexpr bool consteval_2() noexcept
{
if ! consteval {
return true;
} else {
return false;
}
}
constexpr bool consteval_3() noexcept
{
if consteval {
return true;
}
return false;
}
constexpr bool consteval_4() noexcept
{
if ! consteval {
return true;
}
return false;
}
constexpr bool consteval_5() noexcept
{
bool r = true;
if ! consteval {
r = false;
}
return r;
}
constexpr bool consteval_6() noexcept
{
bool r = true;
if consteval {
r = false;
}
return r;
}
// semmle-extractor-options: -std=c++23

View File

@@ -18055,6 +18055,143 @@ ir.cpp:
# 2724| v2724_10(void) = AliasedUse : ~m?
# 2724| v2724_11(void) = ExitFunction :
ir23.cpp:
# 1| bool consteval_1()
# 1| Block 0
# 1| v1_1(void) = EnterFunction :
# 1| mu1_2(unknown) = AliasedDefinition :
# 1| mu1_3(unknown) = InitializeNonLocal :
# 6| r6_1(glval<bool>) = VariableAddress[#return] :
# 6| r6_2(bool) = Constant[0] :
# 6| mu6_3(bool) = Store[#return] : &:r6_1, r6_2
#-----| Goto -> Block 1
# 1| Block 1
# 1| r1_4(glval<bool>) = VariableAddress[#return] :
# 1| v1_5(void) = ReturnValue : &:r1_4, ~m?
# 1| v1_6(void) = AliasedUse : ~m?
# 1| v1_7(void) = ExitFunction :
# 4| Block 2
# 4| r4_1(glval<bool>) = VariableAddress[#return] :
# 4| r4_2(bool) = Constant[1] :
# 4| mu4_3(bool) = Store[#return] : &:r4_1, r4_2
#-----| Goto -> Block 1
# 10| bool consteval_2()
# 10| Block 0
# 10| v10_1(void) = EnterFunction :
# 10| mu10_2(unknown) = AliasedDefinition :
# 10| mu10_3(unknown) = InitializeNonLocal :
# 13| r13_1(glval<bool>) = VariableAddress[#return] :
# 13| r13_2(bool) = Constant[1] :
# 13| mu13_3(bool) = Store[#return] : &:r13_1, r13_2
#-----| Goto -> Block 1
# 10| Block 1
# 10| r10_4(glval<bool>) = VariableAddress[#return] :
# 10| v10_5(void) = ReturnValue : &:r10_4, ~m?
# 10| v10_6(void) = AliasedUse : ~m?
# 10| v10_7(void) = ExitFunction :
# 15| Block 2
# 15| r15_1(glval<bool>) = VariableAddress[#return] :
# 15| r15_2(bool) = Constant[0] :
# 15| mu15_3(bool) = Store[#return] : &:r15_1, r15_2
#-----| Goto -> Block 1
# 19| bool consteval_3()
# 19| Block 0
# 19| v19_1(void) = EnterFunction :
# 19| mu19_2(unknown) = AliasedDefinition :
# 19| mu19_3(unknown) = InitializeNonLocal :
# 21| v21_1(void) = NoOp :
# 25| r25_1(glval<bool>) = VariableAddress[#return] :
# 25| r25_2(bool) = Constant[0] :
# 25| mu25_3(bool) = Store[#return] : &:r25_1, r25_2
#-----| Goto -> Block 1
# 19| Block 1
# 19| r19_4(glval<bool>) = VariableAddress[#return] :
# 19| v19_5(void) = ReturnValue : &:r19_4, ~m?
# 19| v19_6(void) = AliasedUse : ~m?
# 19| v19_7(void) = ExitFunction :
# 22| Block 2
# 22| r22_1(glval<bool>) = VariableAddress[#return] :
# 22| r22_2(bool) = Constant[1] :
# 22| mu22_3(bool) = Store[#return] : &:r22_1, r22_2
#-----| Goto -> Block 1
# 28| bool consteval_4()
# 28| Block 0
# 28| v28_1(void) = EnterFunction :
# 28| mu28_2(unknown) = AliasedDefinition :
# 28| mu28_3(unknown) = InitializeNonLocal :
# 31| r31_1(glval<bool>) = VariableAddress[#return] :
# 31| r31_2(bool) = Constant[1] :
# 31| mu31_3(bool) = Store[#return] : &:r31_1, r31_2
#-----| Goto -> Block 1
# 28| Block 1
# 28| r28_4(glval<bool>) = VariableAddress[#return] :
# 28| v28_5(void) = ReturnValue : &:r28_4, ~m?
# 28| v28_6(void) = AliasedUse : ~m?
# 28| v28_7(void) = ExitFunction :
# 34| Block 2
# 34| r34_1(glval<bool>) = VariableAddress[#return] :
# 34| r34_2(bool) = Constant[0] :
# 34| mu34_3(bool) = Store[#return] : &:r34_1, r34_2
#-----| Goto -> Block 1
# 37| bool consteval_5()
# 37| Block 0
# 37| v37_1(void) = EnterFunction :
# 37| mu37_2(unknown) = AliasedDefinition :
# 37| mu37_3(unknown) = InitializeNonLocal :
# 39| r39_1(glval<bool>) = VariableAddress[r] :
# 39| r39_2(bool) = Constant[1] :
# 39| mu39_3(bool) = Store[r] : &:r39_1, r39_2
# 42| r42_1(bool) = Constant[0] :
# 42| r42_2(glval<bool>) = VariableAddress[r] :
# 42| mu42_3(bool) = Store[r] : &:r42_2, r42_1
# 45| r45_1(glval<bool>) = VariableAddress[#return] :
# 45| r45_2(glval<bool>) = VariableAddress[r] :
# 45| r45_3(bool) = Load[r] : &:r45_2, ~m?
# 45| mu45_4(bool) = Store[#return] : &:r45_1, r45_3
# 37| r37_4(glval<bool>) = VariableAddress[#return] :
# 37| v37_5(void) = ReturnValue : &:r37_4, ~m?
# 37| v37_6(void) = AliasedUse : ~m?
# 37| v37_7(void) = ExitFunction :
# 48| bool consteval_6()
# 48| Block 0
# 48| v48_1(void) = EnterFunction :
# 48| mu48_2(unknown) = AliasedDefinition :
# 48| mu48_3(unknown) = InitializeNonLocal :
# 50| r50_1(glval<bool>) = VariableAddress[r] :
# 50| r50_2(bool) = Constant[1] :
# 50| mu50_3(bool) = Store[r] : &:r50_1, r50_2
# 52| v52_1(void) = NoOp :
#-----| Goto -> Block 2
# 53| Block 1
# 53| r53_1(bool) = Constant[0] :
# 53| r53_2(glval<bool>) = VariableAddress[r] :
# 53| mu53_3(bool) = Store[r] : &:r53_2, r53_1
#-----| Goto -> Block 2
# 56| Block 2
# 56| r56_1(glval<bool>) = VariableAddress[#return] :
# 56| r56_2(glval<bool>) = VariableAddress[r] :
# 56| r56_3(bool) = Load[r] : &:r56_2, ~m?
# 56| mu56_4(bool) = Store[#return] : &:r56_1, r56_3
# 48| r48_4(glval<bool>) = VariableAddress[#return] :
# 48| v48_5(void) = ReturnValue : &:r48_4, ~m?
# 48| v48_6(void) = AliasedUse : ~m?
# 48| v48_7(void) = ExitFunction :
many-defs-per-use.cpp:
# 34| void many_defs_per_use()
# 34| Block 0