@@ -30,6 +30,21 @@ module CfgImpl {
3030 Input:: implicitFieldSelection ( e , index , implicitField )
3131 }
3232
33+ /**
34+ * Holds if `root` is a constant root: a constant expression (with any
35+ * enclosing parentheses stripped) whose parent expression is not itself
36+ * constant. The strict sub-expressions of a constant root are folded at
37+ * compile time and are not evaluated at run time, so they get no evaluation
38+ * node; the constant root itself is evaluated as a single leaf value.
39+ */
40+ private predicate constantRoot ( Go:: Expr root ) {
41+ exists ( Go:: Expr c |
42+ c .isConst ( ) and
43+ not c .getParent ( ) .( Go:: Expr ) .isConst ( ) and
44+ root = c .stripParens ( )
45+ )
46+ }
47+
3348 /** Provides an implementation of the AST signature for Go. */
3449 private module Ast implements CfgLib:: AstSig< Go:: Location > {
3550 class AstNode = Go:: AstNode ;
@@ -78,6 +93,10 @@ module CfgImpl {
7893 // the switch expression (see `Switch.getExpr`), so the wrapping
7994 // statement must not introduce its own assignment or expression nodes.
8095 e = any ( Go:: TypeSwitchStmt ts ) .getTest ( )
96+ or
97+ // The strict sub-expressions of a constant expression are not evaluated
98+ // at run time, so they must not get their own evaluation nodes.
99+ constantRoot ( e .( Go:: Expr ) .getParent + ( ) )
81100 }
82101
83102 AstNode getChild ( AstNode n , int index ) {
@@ -345,17 +364,29 @@ module CfgImpl {
345364
346365 class BinaryExpr = Go:: BinaryExpr ;
347366
348- class LogicalAndExpr = Go:: LandExpr ;
367+ // Constant short-circuiting operators are folded at compile time and their
368+ // operands are not evaluated at run time, so they are not treated as
369+ // logical operators here (which would give their operands their own
370+ // evaluation nodes via `getLeftOperand`/`getRightOperand`/`getOperand`,
371+ // bypassing `skipCfg`). Instead they are handled as constant-root leaf
372+ // value nodes (see `postOrInOrder`).
373+ class LogicalAndExpr extends Go:: LandExpr {
374+ LogicalAndExpr ( ) { not this .isConst ( ) }
375+ }
349376
350- class LogicalOrExpr = Go:: LorExpr ;
377+ class LogicalOrExpr extends Go:: LorExpr {
378+ LogicalOrExpr ( ) { not this .isConst ( ) }
379+ }
351380
352381 class NullCoalescingExpr extends BinaryExpr {
353382 NullCoalescingExpr ( ) { none ( ) }
354383 }
355384
356385 class UnaryExpr = Go:: UnaryExpr ;
357386
358- class LogicalNotExpr = Go:: NotExpr ;
387+ class LogicalNotExpr extends Go:: NotExpr {
388+ LogicalNotExpr ( ) { not this .isConst ( ) }
389+ }
359390
360391 class BooleanLiteral extends Expr {
361392 boolean val ;
@@ -473,6 +504,13 @@ module CfgImpl {
473504 // needs an explicit in-order (allocation) node.
474505 n instanceof Go:: CompositeLit
475506 or
507+ // A constant expression is folded at compile time and its sub-expressions
508+ // are not evaluated (they are pruned by `skipCfg`), so the constant root
509+ // has no CFG children. It therefore needs an explicit in-order node to
510+ // remain a single value-producing leaf (e.g. `unsafe.Sizeof(test())`,
511+ // `1 << 10`, or `!d` for constant `d`).
512+ constantRoot ( n )
513+ or
476514 // Statements/declarations that compute a value or perform an operation and
477515 // are not among the statements the shared library makes post-order by
478516 // default.
0 commit comments