@@ -33,6 +33,21 @@ module GoCfg {
3333 Input:: implicitFieldSelection ( e , index , implicitField )
3434 }
3535
36+ /**
37+ * Holds if `root` is a constant root: a constant expression (with any
38+ * enclosing parentheses stripped) whose parent expression is not itself
39+ * constant. The strict sub-expressions of a constant root are folded at
40+ * compile time and are not evaluated at run time, so they get no evaluation
41+ * node; the constant root itself is evaluated as a single leaf value.
42+ */
43+ private predicate constRoot ( Go:: Expr root ) {
44+ exists ( Go:: Expr c |
45+ c .isConst ( ) and
46+ not c .getParent ( ) .( Go:: Expr ) .isConst ( ) and
47+ root = c .stripParens ( )
48+ )
49+ }
50+
3651 /** Provides an implementation of the AST signature for Go. */
3752 private module Ast implements CfgLib:: AstSig< Go:: Location > {
3853 class AstNode = Go:: AstNode ;
@@ -81,6 +96,10 @@ module GoCfg {
8196 // the switch expression (see `Switch.getExpr`), so the wrapping
8297 // statement must not introduce its own assignment or expression nodes.
8398 e = any ( Go:: TypeSwitchStmt ts ) .getTest ( )
99+ or
100+ // The strict sub-expressions of a constant expression are not evaluated
101+ // at run time, so they must not get their own evaluation nodes.
102+ constRoot ( e .( Go:: Expr ) .getParent + ( ) )
84103 }
85104
86105 AstNode getChild ( AstNode n , int index ) {
@@ -346,17 +365,29 @@ module GoCfg {
346365
347366 class BinaryExpr = Go:: BinaryExpr ;
348367
349- class LogicalAndExpr = Go:: LandExpr ;
368+ // Constant short-circuiting operators are folded at compile time and their
369+ // operands are not evaluated at run time, so they are not treated as
370+ // logical operators here (which would give their operands their own
371+ // evaluation nodes via `getLeftOperand`/`getRightOperand`/`getOperand`,
372+ // bypassing `skipCfg`). Instead they are handled as constant-root leaf
373+ // value nodes (see `postOrInOrder`).
374+ class LogicalAndExpr extends Go:: LandExpr {
375+ LogicalAndExpr ( ) { not this .isConst ( ) }
376+ }
350377
351- class LogicalOrExpr = Go:: LorExpr ;
378+ class LogicalOrExpr extends Go:: LorExpr {
379+ LogicalOrExpr ( ) { not this .isConst ( ) }
380+ }
352381
353382 class NullCoalescingExpr extends BinaryExpr {
354383 NullCoalescingExpr ( ) { none ( ) }
355384 }
356385
357386 class UnaryExpr = Go:: UnaryExpr ;
358387
359- class LogicalNotExpr = Go:: NotExpr ;
388+ class LogicalNotExpr extends Go:: NotExpr {
389+ LogicalNotExpr ( ) { not this .isConst ( ) }
390+ }
360391
361392 class BooleanLiteral extends Expr {
362393 boolean val ;
@@ -474,6 +505,13 @@ module GoCfg {
474505 // needs an explicit in-order (allocation) node.
475506 n instanceof Go:: CompositeLit
476507 or
508+ // A constant expression is folded at compile time and its sub-expressions
509+ // are not evaluated (they are pruned by `skipCfg`), so the constant root
510+ // has no CFG children. It therefore needs an explicit in-order node to
511+ // remain a single value-producing leaf (e.g. `unsafe.Sizeof(test())`,
512+ // `1 << 10`, or `!d` for constant `d`).
513+ constRoot ( n )
514+ or
477515 // Statements/declarations that compute a value or perform an operation and
478516 // are not among the statements the shared library makes post-order by
479517 // default.
0 commit comments