@@ -624,6 +624,76 @@ impl TypedAstContext {
624624 }
625625 }
626626
627+ /// Pessimistically try to check if an expression is `const`.
628+ /// If it's not, or we can't tell if it is, return `false`.
629+ pub fn is_const_expr ( & self , expr : CExprId ) -> bool {
630+ let is_const = |expr| self . is_const_expr ( expr) ;
631+
632+ use CExprKind :: * ;
633+ match self [ expr] . kind {
634+ // A literal is always `const`.
635+ Literal ( _, _) => true ,
636+ // Unary ops should be `const`.
637+ // TODO handle `f128` or use the primitive type.
638+ Unary ( _, _, expr, _) => is_const ( expr) ,
639+ UnaryType ( _, _, _, _) => false , // TODO disabled for now as tests are broken
640+ // Not sure what a `None` `CExprId` means here
641+ // or how to detect a `sizeof` of a VLA, which is non-`const`,
642+ // although it seems we don't handle `sizeof(VLAs)`
643+ // correctly in macros elsewhere already.
644+ #[ allow( unreachable_patterns) ]
645+ UnaryType ( _, _, expr, _) => expr. map_or ( true , is_const) ,
646+ // Not sure what a `OffsetOfKind::Variable` means.
647+ OffsetOf ( _, _) => true ,
648+ // `ptr::offset` (ptr `BinOp::Add`) was `const` stabilized in `1.61.0`.
649+ // `ptr::offset_from` (ptr `BinOp::Subtract`) was `const` stabilized in `1.65.0`.
650+ // TODO `f128` is not yet handled, as we should eventually
651+ // switch to the (currently unstable) `f128` primitive type (#1262).
652+ Binary ( _, _, lhs, rhs, _, _) => is_const ( lhs) && is_const ( rhs) ,
653+ ImplicitCast ( _, _, CastKind :: ArrayToPointerDecay , _, _) => false , // TODO disabled for now as tests are broken
654+ // `as` casts are always `const`.
655+ ImplicitCast ( _, expr, _, _, _) => is_const ( expr) ,
656+ // `as` casts are always `const`.
657+ // TODO This is `const`, although there's a bug #853.
658+ ExplicitCast ( _, expr, _, _, _) => is_const ( expr) ,
659+ // This is used in `const` locations like `match` patterns and array lengths, so it must be `const`.
660+ ConstantExpr ( _, _, _) => true ,
661+ // A reference in an already otherwise `const` context should be `const` itself.
662+ DeclRef ( _, _, _) => true ,
663+ Call ( _, fn_expr, ref args) => {
664+ let is_const_fn = false ; // TODO detect which `fn`s are `const`.
665+ is_const ( fn_expr) && args. iter ( ) . copied ( ) . all ( is_const) && is_const_fn
666+ }
667+ Member ( _, expr, _, _, _) => is_const ( expr) ,
668+ ArraySubscript ( _, array, index, _) => is_const ( array) && is_const ( index) ,
669+ Conditional ( _, cond, if_true, if_false) => {
670+ is_const ( cond) && is_const ( if_true) && is_const ( if_false)
671+ }
672+ BinaryConditional ( _, cond, if_false) => is_const ( cond) && is_const ( if_false) ,
673+ InitList ( _, ref inits, _, _) => inits. iter ( ) . copied ( ) . all ( is_const) ,
674+ ImplicitValueInit ( _) => true ,
675+ Paren ( _, expr) => is_const ( expr) ,
676+ CompoundLiteral ( _, expr) => is_const ( expr) ,
677+ Predefined ( _, expr) => is_const ( expr) ,
678+ Statements ( _, stmt) => self . is_const_stmt ( stmt) ,
679+ VAArg ( _, expr) => is_const ( expr) ,
680+ // SIMD is not yet `const` in Rust.
681+ ShuffleVector ( _, _) | ConvertVector ( _, _) => false ,
682+ DesignatedInitExpr ( _, _, expr) => is_const ( expr) ,
683+ Choose ( _, cond, if_true, if_false, _) => {
684+ is_const ( cond) && is_const ( if_true) && is_const ( if_false)
685+ }
686+ // Atomics are not yet `const` in Rust.
687+ Atomic { .. } => false ,
688+ BadExpr => false ,
689+ }
690+ }
691+
692+ pub fn is_const_stmt ( & self , _stmt : CStmtId ) -> bool {
693+ // TODO
694+ false
695+ }
696+
627697 pub fn prune_unwanted_decls ( & mut self , want_unused_functions : bool ) {
628698 // Starting from a set of root declarations, walk each one to find declarations it
629699 // depends on. Then walk each of those, recursively.
0 commit comments