Merge branch 'main' into remove-conflation-from-out-nodes

This commit is contained in:
Mathias Vorreiter Pedersen
2025-01-20 12:42:26 +00:00
161 changed files with 12268 additions and 1245 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
class Stmt extends @stmt {
string toString() { none() }
}
class Location extends @location_stmt {
string toString() { none() }
}
predicate isConstevalIf(Stmt stmt) {
exists(int kind | stmts(stmt, kind, _) | kind = 38 or kind = 39)
}
from Stmt stmt, int kind, int kind_new, Location location
where
stmts(stmt, kind, location) and
if isConstevalIf(stmt) then kind_new = 7 else kind_new = kind // Turns consteval if into a block with two block statements in it
select stmt, kind_new, location

View File

@@ -0,0 +1,5 @@
description: Support (not) consteval if
compatibility: full
consteval_if_then.rel: delete
consteval_if_else.rel: delete
stmts.rel: run stmts.qlo

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* A new class `ConstevalIfStmt` was introduced, which represents the C++23 `if consteval` and `if ! consteval` statements.

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.(ConstevalIfStmt).getThen() = e and pred = "getThen()"
or
s.(ConstevalIfStmt).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
// NotConstevalIfStmt -> { then, else } ->
exists(ConstevalIfStmt 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

@@ -47,7 +47,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
{
TranslatedFlexibleCondition() { this = TTranslatedFlexibleCondition(expr) }
final override predicate handlesDestructorsExplicitly() { none() } // TODO: this needs to be revisted when we get unnamed destructors
final override predicate handlesDestructorsExplicitly() { none() } // TODO: this needs to be revisited when we get unnamed destructors
final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() }

View File

@@ -166,7 +166,7 @@ private predicate ignoreExpr(Expr expr) {
}
/**
* Holds if the side effects of `expr` should be ignoredf for the purposes of IR generation.
* Holds if the side effects of `expr` should be ignored for the purposes of IR generation.
*
* In cases involving `constexpr`, a call can wind up as a constant expression. `ignoreExpr()` will
* not hold for such a call, since we do need to translate the call (as a constant), but we need to

View File

@@ -1098,6 +1098,61 @@ class TranslatedConstExprIfStmt extends TranslatedIfLikeStmt {
override predicate hasElse() { exists(stmt.getElse()) }
}
class TranslatedConstevalIfStmt extends TranslatedStmt {
override ConstevalIfStmt 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,154 @@ 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 ConstevalIfStmt extends Stmt, @stmt_consteval_or_not_consteval_if {
override string getAPrimaryQlClass() { result = "ConstevalIfStmt" }
override string toString() {
if this.isNot() then result = "if ! consteval ..." else result = "if consteval ..."
}
/**
* Holds if this is a 'not consteval if' statement.
*
* For example, this holds for
* ```cpp
* if ! consteval { return true; }
* ```
* but not for
* ```cpp
* if consteval { return true; }
* ```
*/
predicate isNot() { this instanceof @stmt_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() {
if this.isNot() then result = this.getElse() else result = this.getThen()
}
/**
* 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() {
if this.isNot() then result = this.getThen() else result = this.getElse()
}
/**
* 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()) }
}
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support (not) consteval if
compatibility: partial

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

@@ -24145,6 +24145,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): [ConstevalIfStmt] 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): [ConstevalIfStmt] 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): [ConstevalIfStmt] 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

@@ -19819,6 +19819,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

@@ -18132,6 +18132,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

View File

@@ -9,7 +9,7 @@
#endif
// semmle-extractor-options: -I${testdir}/more_headers/ "-U SOME_SYM"
#undef BAR
//#define SCARY(a,aa,aaah) /* we ignore a */ (aa /* but we take aa */) /* and we ignore aaa */
#define SCARY(a,aa,aaah) /* we ignore a */ (aa /* but we take aa */) /* and we ignore aaa */
#define LOG(fmt, ...) printf("Warning: %s", fmt, __VA__ARGS__)
#include "pp.h"

View File

@@ -1,7 +1,7 @@
#pragma once
//#warning "This should happen"
#warning "This should happen"
#line 33 "emerald_city.h" // Magic!
//#pragma byte_order(big_endian)
#pragma byte_order(big_endian)
#warning "Not in Kansas any more"
#define MULTILINE \

View File

@@ -7,6 +7,7 @@
| pp.cpp:0:0:0:0 | pp.cpp | 7 | 1 | 7 | 5 | PreprocessorElse | N/A | N/A |
| pp.cpp:0:0:0:0 | pp.cpp | 9 | 1 | 9 | 6 | PreprocessorEndif | N/A | N/A |
| pp.cpp:0:0:0:0 | pp.cpp | 11 | 1 | 11 | 10 | PreprocessorUndef | BAR | N/A |
| pp.cpp:0:0:0:0 | pp.cpp | 12 | 1 | 12 | 68 | Macro | SCARY(a,aa,aaah) | (aa ) |
| pp.cpp:0:0:0:0 | pp.cpp | 13 | 1 | 13 | 63 | Macro | LOG(fmt,__VA_ARGS__...) | printf("Warning: %s", fmt, __VA__ARGS__) |
| pp.cpp:0:0:0:0 | pp.cpp | 14 | 1 | 14 | 15 | Include | "pp.h" | N/A |
| pp.cpp:0:0:0:0 | pp.cpp | 16 | 1 | 16 | 5 | PreprocessorIf | 0 | N/A |
@@ -32,7 +33,9 @@
| pp.cpp:0:0:0:0 | pp.cpp | 76 | 1 | 76 | 20 | PreprocessorWarning | BAR defined | N/A |
| pp.cpp:0:0:0:0 | pp.cpp | 77 | 1 | 77 | 6 | PreprocessorEndif | N/A | N/A |
| pp.h:0:0:0:0 | pp.h | 1 | 1 | 1 | 12 | PreprocessorPragma | once | N/A |
| pp.h:0:0:0:0 | pp.h | 2 | 1 | 2 | 29 | PreprocessorWarning | "This should happen" | N/A |
| pp.h:0:0:0:0 | pp.h | 3 | 1 | 3 | 27 | PreprocessorLine | 33 "emerald_city.h" | N/A |
| pp.h:0:0:0:0 | pp.h | 4 | 1 | 4 | 30 | PreprocessorPragma | byte_order(big_endian) | N/A |
| pp.h:0:0:0:0 | pp.h | 5 | 1 | 5 | 33 | PreprocessorWarning | "Not in Kansas any more" | N/A |
| pp.h:0:0:0:0 | pp.h | 7 | 1 | 11 | 8 | Macro | MULTILINE | world a long |
| pp.h:0:0:0:0 | pp.h | 13 | 1 | 14 | 11 | PreprocessorUndef | MULTILINE | N/A |