Skip to content
Draft
4 changes: 4 additions & 0 deletions cpp/ql/lib/change-notes/2026-01-02-constant-folding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.
7 changes: 6 additions & 1 deletion cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ import UnsignedGEZero
//
// So to reduce the number of false positives, we do not report a result if
// the comparison is in a macro expansion. Similarly for template
// instantiations.
// instantiations, static asserts, non-type template arguments, enum constants,
// and constexprs.
from ComparisonOperation cmp, SmallSide ss, float left, float right, boolean value, string reason
where
not cmp.isInMacroExpansion() and
not cmp.isFromTemplateInstantiation(_) and
not exists(StaticAssert s | s.getCondition() = cmp.getParent*()) and
not exists(Declaration d | d.getATemplateArgument() = cmp.getParent*()) and
not exists(Variable v | v.isConstexpr() | v.getInitializer().getExpr() = cmp.getParent*()) and
not exists(EnumConstant e | e.getInitializer().getExpr() = cmp.getParent*()) and
not functionContainsDisabledCode(cmp.getEnclosingFunction()) and
reachablePointlessComparison(cmp, left, right, value, ss) and
// a comparison between an enum and zero is always valid because whether
Expand Down
4 changes: 4 additions & 0 deletions cpp/ql/src/change-notes/2026-01-02-constant-comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/constant-comparison` query has been updated to not produce false positives for constants that are now represented by their unfolded expression trees.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ void constantAddresses(int param) {
constexpr int *array2d = &int_arr_arr[1][1] + 1;
constexpr int *const_ints = &int_arr_arr[int_const][extern_int_const];

// Commented out because clang and EDG disagree on whether this is
// constant.
//constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];
constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];

constexpr int *comma_int = &int_arr[ ((void)0, 1) ];
constexpr int *comma_addr = ((void)0, &int_var);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
| addresses.cpp:29:35:29:54 | & ... | stmtexpr_int | misclassified as NOT constant |
| addresses.cpp:31:32:31:55 | & ... | comma_int | misclassified as NOT constant |
| addresses.cpp:36:39:36:70 | ... ? ... : ... | ternary_ptr_cond | misclassified as NOT constant |
| addresses.cpp:37:35:37:69 | & ... | ptr_subtract | misclassified as NOT constant |
| addresses.cpp:39:35:39:50 | ... + ... | constexpr_va | misclassified as NOT constant |
10 changes: 9 additions & 1 deletion cpp/ql/test/library-tests/ir/ir/PrintAST.expected
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
#-----| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] __va_list_tag &&
#-----| [CopyAssignmentOperator] std::__va_list& std::__va_list::operator=(std::__va_list const&)
#-----| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const __va_list &
#-----| [MoveAssignmentOperator] std::__va_list& std::__va_list::operator=(std::__va_list&&)
#-----| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] __va_list &&
#-----| [Operator,TopLevelFunction] void operator delete(void*)
#-----| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
Expand Down Expand Up @@ -4335,7 +4343,7 @@ generic.c:
# 3| ValueCategory = prvalue
# 3| getAssociationExpr(0): [ReuseExpr] reuse of x
# 3| Type = [IntType] unsigned int
# 3| ValueCategory = lvalue
# 3| ValueCategory = prvalue
# 3| getAssociationType(1): [TypeName] int
# 3| Type = [IntType] int
# 3| ValueCategory = prvalue
Expand Down
40 changes: 20 additions & 20 deletions cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -9648,29 +9648,29 @@ ir.cpp:
# 1054| r1054_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inits] :
# 1054| r1054_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1054:22] :
# 1054| m1054_3(decltype([...](...){...})) = Uninitialized[#temp1054:22] : &:r1054_2
# 1054| r1054_4(glval<String &>) = FieldAddress[s] : r1054_2
# 1054| r1054_5(glval<String &>) = VariableAddress[s] :
# 1054| r1054_6(String &) = Load[s] : &:r1054_5, m1040_9
# 1054| r1054_7(glval<String>) = CopyValue : r1054_6
# 1054| r1054_8(String &) = CopyValue : r1054_7
# 1054| m1054_9(String &) = Store[?] : &:r1054_4, r1054_8
# 1054| r1054_4(glval<int>) = FieldAddress[i] : r1054_2
# 1054| r1054_5(glval<int>) = VariableAddress[x] :
# 1054| r1054_6(int) = Load[x] : &:r1054_5, ~m1052_7
# 1054| r1054_7(int) = Constant[1] :
# 1054| r1054_8(int) = Add : r1054_6, r1054_7
# 1054| m1054_9(int) = Store[?] : &:r1054_4, r1054_8
# 1054| m1054_10(decltype([...](...){...})) = Chi : total:m1054_3, partial:m1054_9
# 1054| r1054_11(glval<int>) = FieldAddress[x] : r1054_2
# 1054| r1054_12(glval<int>) = VariableAddress[x] :
# 1054| r1054_13(int) = Load[x] : &:r1054_12, ~m1052_7
# 1054| m1054_14(int) = Store[?] : &:r1054_11, r1054_13
# 1054| r1054_11(glval<int &>) = FieldAddress[j] : r1054_2
# 1054| r1054_12(glval<int>) = VariableAddress[r] :
# 1054| r1054_13(int &) = CopyValue : r1054_12
# 1054| m1054_14(int &) = Store[?] : &:r1054_11, r1054_13
# 1054| m1054_15(decltype([...](...){...})) = Chi : total:m1054_10, partial:m1054_14
# 1054| r1054_16(glval<int>) = FieldAddress[i] : r1054_2
# 1054| r1054_17(glval<int>) = VariableAddress[x] :
# 1054| r1054_18(int) = Load[x] : &:r1054_17, ~m1052_7
# 1054| r1054_19(int) = Constant[1] :
# 1054| r1054_20(int) = Add : r1054_18, r1054_19
# 1054| m1054_21(int) = Store[?] : &:r1054_16, r1054_20
# 1054| r1054_16(glval<String &>) = FieldAddress[s] : r1054_2
# 1054| r1054_17(glval<String &>) = VariableAddress[s] :
# 1054| r1054_18(String &) = Load[s] : &:r1054_17, m1040_9
# 1054| r1054_19(glval<String>) = CopyValue : r1054_18
# 1054| r1054_20(String &) = CopyValue : r1054_19
# 1054| m1054_21(String &) = Store[?] : &:r1054_16, r1054_20
# 1054| m1054_22(decltype([...](...){...})) = Chi : total:m1054_15, partial:m1054_21
# 1054| r1054_23(glval<int &>) = FieldAddress[j] : r1054_2
# 1054| r1054_24(glval<int>) = VariableAddress[r] :
# 1054| r1054_25(int &) = CopyValue : r1054_24
# 1054| m1054_26(int &) = Store[?] : &:r1054_23, r1054_25
# 1054| r1054_23(glval<int>) = FieldAddress[x] : r1054_2
# 1054| r1054_24(glval<int>) = VariableAddress[x] :
# 1054| r1054_25(int) = Load[x] : &:r1054_24, ~m1052_7
# 1054| m1054_26(int) = Store[?] : &:r1054_23, r1054_25
# 1054| m1054_27(decltype([...](...){...})) = Chi : total:m1054_22, partial:m1054_26
# 1054| r1054_28(decltype([...](...){...})) = Load[#temp1054:22] : &:r1054_2, m1054_27
# 1054| m1054_29(decltype([...](...){...})) = Store[lambda_inits] : &:r1054_1, r1054_28
Expand Down
40 changes: 20 additions & 20 deletions cpp/ql/test/library-tests/ir/ir/raw_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -8892,26 +8892,26 @@ ir.cpp:
# 1054| r1054_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inits] :
# 1054| r1054_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1054:22] :
# 1054| mu1054_3(decltype([...](...){...})) = Uninitialized[#temp1054:22] : &:r1054_2
# 1054| r1054_4(glval<String &>) = FieldAddress[s] : r1054_2
# 1054| r1054_5(glval<String &>) = VariableAddress[s] :
# 1054| r1054_6(String &) = Load[s] : &:r1054_5, ~m?
# 1054| r1054_7(glval<String>) = CopyValue : r1054_6
# 1054| r1054_8(String &) = CopyValue : r1054_7
# 1054| mu1054_9(String &) = Store[?] : &:r1054_4, r1054_8
# 1054| r1054_10(glval<int>) = FieldAddress[x] : r1054_2
# 1054| r1054_11(glval<int>) = VariableAddress[x] :
# 1054| r1054_12(int) = Load[x] : &:r1054_11, ~m?
# 1054| mu1054_13(int) = Store[?] : &:r1054_10, r1054_12
# 1054| r1054_14(glval<int>) = FieldAddress[i] : r1054_2
# 1054| r1054_15(glval<int>) = VariableAddress[x] :
# 1054| r1054_16(int) = Load[x] : &:r1054_15, ~m?
# 1054| r1054_17(int) = Constant[1] :
# 1054| r1054_18(int) = Add : r1054_16, r1054_17
# 1054| mu1054_19(int) = Store[?] : &:r1054_14, r1054_18
# 1054| r1054_20(glval<int &>) = FieldAddress[j] : r1054_2
# 1054| r1054_21(glval<int>) = VariableAddress[r] :
# 1054| r1054_22(int &) = CopyValue : r1054_21
# 1054| mu1054_23(int &) = Store[?] : &:r1054_20, r1054_22
# 1054| r1054_4(glval<int>) = FieldAddress[i] : r1054_2
# 1054| r1054_5(glval<int>) = VariableAddress[x] :
# 1054| r1054_6(int) = Load[x] : &:r1054_5, ~m?
# 1054| r1054_7(int) = Constant[1] :
# 1054| r1054_8(int) = Add : r1054_6, r1054_7
# 1054| mu1054_9(int) = Store[?] : &:r1054_4, r1054_8
# 1054| r1054_10(glval<int &>) = FieldAddress[j] : r1054_2
# 1054| r1054_11(glval<int>) = VariableAddress[r] :
# 1054| r1054_12(int &) = CopyValue : r1054_11
# 1054| mu1054_13(int &) = Store[?] : &:r1054_10, r1054_12
# 1054| r1054_14(glval<String &>) = FieldAddress[s] : r1054_2
# 1054| r1054_15(glval<String &>) = VariableAddress[s] :
# 1054| r1054_16(String &) = Load[s] : &:r1054_15, ~m?
# 1054| r1054_17(glval<String>) = CopyValue : r1054_16
# 1054| r1054_18(String &) = CopyValue : r1054_17
# 1054| mu1054_19(String &) = Store[?] : &:r1054_14, r1054_18
# 1054| r1054_20(glval<int>) = FieldAddress[x] : r1054_2
# 1054| r1054_21(glval<int>) = VariableAddress[x] :
# 1054| r1054_22(int) = Load[x] : &:r1054_21, ~m?
# 1054| mu1054_23(int) = Store[?] : &:r1054_20, r1054_22
# 1054| r1054_24(decltype([...](...){...})) = Load[#temp1054:22] : &:r1054_2, ~m?
# 1054| mu1054_25(decltype([...](...){...})) = Store[lambda_inits] : &:r1054_1, r1054_24
# 1055| r1055_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inits] :
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/test/library-tests/scopes/parents/parents.expected
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
| 0 | file://:0:0:0:0 | (global namespace) | file://:0:0:0:0 | __va_list_tag |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:2:11:2:13 | foo |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:18:3:18:3 | var |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:18:7:18:7 | var |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:18:3:18:5 | var |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:20:5:20:5 | g |
| 1 | file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | fp_offset |
| 1 | file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | gp_offset |
Expand All @@ -22,6 +22,6 @@
| 1 | parents.cpp:6:11:10:7 | { ... } | parents.cpp:7:9:9:9 | for(...;...;...) ... |
| 1 | parents.cpp:6:11:10:7 | { ... } | parents.cpp:7:33:9:9 | { ... } |
| 1 | parents.cpp:7:33:9:9 | { ... } | parents.cpp:8:15:8:15 | k |
| 1 | parents.cpp:18:7:18:7 | var | parents.cpp:17:19:17:19 | T |
| 1 | parents.cpp:18:3:18:5 | var | parents.cpp:17:19:17:19 | T |
| 1 | parents.cpp:20:5:20:5 | g | parents.cpp:20:9:24:1 | { ... } |
| 1 | parents.cpp:20:9:24:1 | { ... } | parents.cpp:21:16:21:16 | l |
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ isFromUninstantiatedTemplate
| isfromtemplateinstantiation.cpp:99:1:99:1 | return ... | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass<T> |
| isfromtemplateinstantiation.cpp:99:1:99:1 | return ... | isfromtemplateinstantiation.cpp:97:25:97:60 | myMethod2 |
| isfromtemplateinstantiation.cpp:99:1:99:1 | return ... | isfromtemplateinstantiation.cpp:97:52:97:52 | myMethod2 |
| isfromtemplateinstantiation.cpp:110:15:110:15 | definition of var_template | isfromtemplateinstantiation.cpp:110:15:110:15 | var_template |
| isfromtemplateinstantiation.cpp:110:15:110:15 | var_template | isfromtemplateinstantiation.cpp:110:15:110:15 | var_template |
| isfromtemplateinstantiation.cpp:110:3:110:14 | definition of var_template | isfromtemplateinstantiation.cpp:110:3:110:14 | var_template |
| isfromtemplateinstantiation.cpp:110:3:110:14 | var_template | isfromtemplateinstantiation.cpp:110:3:110:14 | var_template |
| isfromtemplateinstantiation.cpp:128:7:128:30 | AnotherTemplateClass<T *> | isfromtemplateinstantiation.cpp:128:7:128:30 | AnotherTemplateClass<T *> |
| isfromtemplateinstantiation.cpp:128:7:128:30 | definition of AnotherTemplateClass<T *> | isfromtemplateinstantiation.cpp:128:7:128:30 | AnotherTemplateClass<T *> |
| isfromtemplateinstantiation.cpp:129:6:129:6 | definition of f | isfromtemplateinstantiation.cpp:128:7:128:30 | AnotherTemplateClass<T *> |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16 | T | |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16, variables.cpp:37:16:37:24 | float | |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16, variables.cpp:38:16:38:22 | int | |
| variables.cpp:2:16:2:16 | pi | | T | TemplateVariable |
| variables.cpp:2:13:2:14 | pi | | T | TemplateVariable |
| variables.cpp:5:23:5:37 | pi | | const char * | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | S, T | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | float, char | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | short, long | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:40:23:40:60 | unsigned int, unsigned char | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:41:23:41:42 | int, char | |
| variables.cpp:8:23:8:23 | multi_arg | | S, T | TemplateVariable |
| variables.cpp:8:13:8:21 | multi_arg | | S, T | TemplateVariable |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | T | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | float | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16, variables.cpp:43:3:43:18 | int | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:44:3:44:19 | long | |
| variables.cpp:11:15:11:15 | mutable_val | | T | TemplateVariable |
| variables.cpp:11:3:11:13 | mutable_val | | T | TemplateVariable |
| variables.cpp:19:3:19:10 | bar | | T | TemplateVariable |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | T | |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | float | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
| main.cpp:4:5:4:6 | ys | Poor global variable name 'ys'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:9:5:9:6 | v1 | Poor global variable name 'v1'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:10:5:10:6 | v2 | Poor global variable name 'v2'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:12:5:12:5 | v3 | Poor global variable name 'v3'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:14:5:14:5 | v4 | Poor global variable name 'v4'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:16:5:16:5 | v5 | Poor global variable name 'v5'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:12:3:12:4 | v3 | Poor global variable name 'v3'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:14:3:14:4 | v4 | Poor global variable name 'v4'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:16:3:16:4 | v5 | Poor global variable name 'v5'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
| code2.cpp:7:6:7:7 | v3 | Variable v3 is not used. |
| code2.cpp:11:16:11:17 | v7 | Variable v7 is not used. |
| code2.cpp:26:16:26:17 | v1 | Variable v1 is not used. |
| code2.cpp:27:16:27:17 | v2 | Variable v2 is not used. |
| code2.cpp:42:11:42:16 | myVar1 | Variable myVar1 is not used. |
| code2.cpp:64:7:64:8 | v3 | Variable v3 is not used. |
| code2.cpp:108:11:108:12 | v2 | Variable v2 is not used. |
Expand Down
Loading