1+ use crate :: c_ast:: iterators:: { immediate_children_all_types, NodeVisitor } ;
2+ use crate :: iterators:: { DFNodes , SomeId } ;
13use c2rust_ast_exporter:: clang_ast:: LRValue ;
24use indexmap:: { IndexMap , IndexSet } ;
35use std:: cell:: RefCell ;
@@ -9,8 +11,14 @@ use std::ops::Index;
911use std:: path:: { Path , PathBuf } ;
1012use std:: rc:: Rc ;
1113
14+ pub use self :: conversion:: * ;
15+ pub use self :: print:: Printer ;
1216pub use c2rust_ast_exporter:: clang_ast:: { BuiltinVaListKind , SrcFile , SrcLoc , SrcSpan } ;
1317
18+ mod conversion;
19+ pub mod iterators;
20+ mod print;
21+
1422#[ derive( Eq , PartialEq , Ord , PartialOrd , Hash , Debug , Copy , Clone ) ]
1523pub struct CTypeId ( pub u64 ) ;
1624
@@ -33,15 +41,6 @@ pub type CTypedefId = CDeclId; // Typedef types need to point to 'DeclKind::Type
3341pub type CEnumId = CDeclId ; // Enum types need to point to 'DeclKind::Enum'
3442pub type CEnumConstantId = CDeclId ; // Enum's need to point to child 'DeclKind::EnumConstant's
3543
36- pub use self :: conversion:: * ;
37- pub use self :: print:: Printer ;
38-
39- mod conversion;
40- pub mod iterators;
41- mod print;
42-
43- use iterators:: { DFNodes , SomeId } ;
44-
4544/// AST context containing all of the nodes in the Clang AST
4645#[ derive( Debug , Clone ) ]
4746pub struct TypedAstContext {
@@ -638,12 +637,10 @@ impl TypedAstContext {
638637 // Unary ops should be `const`.
639638 // TODO handle `f128` or use the primitive type.
640639 Unary ( _, _, expr, _) => is_const ( expr) ,
641- UnaryType ( _, _, _, _) => false , // TODO disabled for now as tests are broken
642640 // Not sure what a `None` `CExprId` means here
643641 // or how to detect a `sizeof` of a VLA, which is non-`const`,
644642 // although it seems we don't handle `sizeof(VLAs)`
645643 // correctly in macros elsewhere already.
646- #[ allow( unreachable_patterns) ]
647644 UnaryType ( _, _, expr, _) => expr. map_or ( true , is_const) ,
648645 // Not sure what a `OffsetOfKind::Variable` means.
649646 OffsetOf ( _, _) => true ,
@@ -652,7 +649,6 @@ impl TypedAstContext {
652649 // TODO `f128` is not yet handled, as we should eventually
653650 // switch to the (currently unstable) `f128` primitive type (#1262).
654651 Binary ( _, _, lhs, rhs, _, _) => is_const ( lhs) && is_const ( rhs) ,
655- ImplicitCast ( _, _, CastKind :: ArrayToPointerDecay , _, _) => false , // TODO disabled for now as tests are broken
656652 // `as` casts are always `const`.
657653 ImplicitCast ( _, expr, _, _, _) => is_const ( expr) ,
658654 // `as` casts are always `const`.
@@ -691,9 +687,61 @@ impl TypedAstContext {
691687 }
692688 }
693689
694- pub fn is_const_stmt ( & self , _stmt : CStmtId ) -> bool {
695- // TODO
696- false
690+ pub fn is_const_stmt ( & self , stmt : CStmtId ) -> bool {
691+ let is_const = |stmt| self . is_const_stmt ( stmt) ;
692+ let is_const_expr = |expr| self . is_const_expr ( expr) ;
693+
694+ use CStmtKind :: * ;
695+ match self [ stmt] . kind {
696+ Case ( expr, stmt, _const_expr) => is_const_expr ( expr) && is_const ( stmt) ,
697+ Default ( stmt) => is_const ( stmt) ,
698+ Compound ( ref stmts) => stmts. iter ( ) . copied ( ) . all ( is_const) ,
699+ Expr ( expr) => is_const_expr ( expr) ,
700+ Empty => true ,
701+ If {
702+ scrutinee,
703+ true_variant,
704+ false_variant,
705+ } => {
706+ is_const_expr ( scrutinee)
707+ && is_const ( true_variant)
708+ && false_variant. map_or ( true , is_const)
709+ }
710+ Switch { scrutinee, body } => is_const_expr ( scrutinee) && is_const ( body) ,
711+ While { condition, body } => is_const_expr ( condition) && is_const ( body) ,
712+ DoWhile { body, condition } => is_const ( body) && is_const_expr ( condition) ,
713+ ForLoop {
714+ init,
715+ condition,
716+ increment,
717+ body,
718+ } => {
719+ init. map_or ( true , is_const)
720+ && condition. map_or ( true , is_const_expr)
721+ && increment. map_or ( true , is_const_expr)
722+ && is_const ( body)
723+ }
724+ Break => true ,
725+ Continue => true ,
726+ Return ( expr) => expr. map_or ( true , is_const_expr) ,
727+ Decls ( ref _decls) => true ,
728+ Asm { .. } => false ,
729+ Attributed {
730+ attributes : _,
731+ substatement,
732+ } => is_const ( substatement) ,
733+ // `goto`s are tricky, because they can be non-local
734+ // and jump out of the context of the macro.
735+ // A `goto` and its labels are `const` if the whole state machine
736+ // we compile to has all `const` statements,
737+ // but determining what that is exactly is trickier,
738+ // and might depend on the context in which the macro is used.
739+ // This is probably fairly uncommon, so we just assume it's not `const` for now.
740+ // Note that in C, labels are for `goto`s.
741+ // There are no labeled `break`s and `continue`s.
742+ Label ( _stmt) => false ,
743+ Goto ( _label) => false ,
744+ }
697745 }
698746
699747 pub fn prune_unwanted_decls ( & mut self , want_unused_functions : bool ) {
@@ -836,76 +884,90 @@ impl TypedAstContext {
836884 ast_context : & ' a mut TypedAstContext ,
837885 }
838886
839- use iterators:: { immediate_children_all_types, NodeVisitor } ;
840887 impl < ' a > NodeVisitor for BubbleExprTypes < ' a > {
841888 fn children ( & mut self , id : SomeId ) -> Vec < SomeId > {
842889 immediate_children_all_types ( self . ast_context , id)
843890 }
891+
844892 fn post ( & mut self , id : SomeId ) {
845- if let SomeId :: Expr ( e) = id {
846- let new_ty = match self . ast_context . c_exprs [ & e] . kind {
847- CExprKind :: Conditional ( _ty, _cond, lhs, rhs) => {
848- let lhs_type_id =
849- self . ast_context . c_exprs [ & lhs] . kind . get_qual_type ( ) . unwrap ( ) ;
850- let rhs_type_id =
851- self . ast_context . c_exprs [ & rhs] . kind . get_qual_type ( ) . unwrap ( ) ;
893+ let e = match id {
894+ SomeId :: Expr ( e) => e,
895+ _ => return ,
896+ } ;
897+
898+ let new_ty = match self . ast_context . c_exprs [ & e] . kind {
899+ CExprKind :: Conditional ( _ty, _cond, lhs, rhs) => {
900+ let lhs_type_id =
901+ self . ast_context . c_exprs [ & lhs] . kind . get_qual_type ( ) . unwrap ( ) ;
902+ let rhs_type_id =
903+ self . ast_context . c_exprs [ & rhs] . kind . get_qual_type ( ) . unwrap ( ) ;
904+
905+ let lhs_resolved_ty = self . ast_context . resolve_type ( lhs_type_id. ctype ) ;
906+ let rhs_resolved_ty = self . ast_context . resolve_type ( rhs_type_id. ctype ) ;
907+
908+ if CTypeKind :: PULLBACK_KINDS . contains ( & lhs_resolved_ty. kind ) {
909+ Some ( lhs_type_id)
910+ } else if CTypeKind :: PULLBACK_KINDS . contains ( & rhs_resolved_ty. kind ) {
911+ Some ( rhs_type_id)
912+ } else {
913+ None
914+ }
915+ }
916+ CExprKind :: Binary ( _ty, op, lhs, rhs, _, _) => {
917+ let rhs_type_id =
918+ self . ast_context . c_exprs [ & rhs] . kind . get_qual_type ( ) . unwrap ( ) ;
919+ let lhs_kind = & self . ast_context . c_exprs [ & lhs] . kind ;
920+ let lhs_type_id = lhs_kind. get_qual_type ( ) . unwrap ( ) ;
921+
922+ let lhs_resolved_ty = self . ast_context . resolve_type ( lhs_type_id. ctype ) ;
923+ let rhs_resolved_ty = self . ast_context . resolve_type ( rhs_type_id. ctype ) ;
852924
853- let lhs_resolved_ty = self . ast_context . resolve_type ( lhs_type_id . ctype ) ;
854- let rhs_resolved_ty = self . ast_context . resolve_type ( rhs_type_id . ctype ) ;
925+ let neither_ptr = !lhs_resolved_ty . kind . is_pointer ( )
926+ && ! rhs_resolved_ty. kind . is_pointer ( ) ;
855927
928+ if op. all_types_same ( ) && neither_ptr {
856929 if CTypeKind :: PULLBACK_KINDS . contains ( & lhs_resolved_ty. kind ) {
857930 Some ( lhs_type_id)
858- } else if CTypeKind :: PULLBACK_KINDS . contains ( & rhs_resolved_ty. kind ) {
859- Some ( rhs_type_id)
860- } else {
861- None
862- }
863- }
864- CExprKind :: Binary ( _ty, op, lhs, rhs, _, _) => {
865- let rhs_type_id =
866- self . ast_context . c_exprs [ & rhs] . kind . get_qual_type ( ) . unwrap ( ) ;
867- let lhs_kind = & self . ast_context . c_exprs [ & lhs] . kind ;
868- let lhs_type_id = lhs_kind. get_qual_type ( ) . unwrap ( ) ;
869-
870- let lhs_resolved_ty = self . ast_context . resolve_type ( lhs_type_id. ctype ) ;
871- let rhs_resolved_ty = self . ast_context . resolve_type ( rhs_type_id. ctype ) ;
872-
873- let neither_ptr = !lhs_resolved_ty. kind . is_pointer ( )
874- && !rhs_resolved_ty. kind . is_pointer ( ) ;
875-
876- if op. all_types_same ( ) && neither_ptr {
877- if CTypeKind :: PULLBACK_KINDS . contains ( & lhs_resolved_ty. kind ) {
878- Some ( lhs_type_id)
879- } else {
880- Some ( rhs_type_id)
881- }
882- } else if op == BinOp :: ShiftLeft || op == BinOp :: ShiftRight {
883- Some ( lhs_type_id)
884931 } else {
885- return ;
932+ Some ( rhs_type_id )
886933 }
934+ } else if op == BinOp :: ShiftLeft || op == BinOp :: ShiftRight {
935+ Some ( lhs_type_id)
936+ } else {
937+ return ;
887938 }
888- CExprKind :: Unary ( _ty, op, e, _idk) => op. expected_result_type (
889- self . ast_context ,
890- self . ast_context . c_exprs [ & e] . kind . get_qual_type ( ) . unwrap ( ) ,
891- ) ,
892- CExprKind :: Paren ( _ty, e) => {
893- self . ast_context . c_exprs [ & e] . kind . get_qual_type ( )
894- }
895- _ => return ,
896- } ;
897- if let ( Some ( ty) , Some ( new_ty) ) = (
898- self . ast_context
899- . c_exprs
900- . get_mut ( & e)
901- . and_then ( |e| e. kind . get_qual_type_mut ( ) ) ,
902- new_ty,
903- ) {
904- * ty = new_ty;
905- } ;
906- }
939+ }
940+ CExprKind :: Unary ( _ty, op, e, _idk) => op. expected_result_type (
941+ self . ast_context ,
942+ self . ast_context . c_exprs [ & e] . kind . get_qual_type ( ) . unwrap ( ) ,
943+ ) ,
944+ CExprKind :: Paren ( _ty, e) => self . ast_context . c_exprs [ & e] . kind . get_qual_type ( ) ,
945+ CExprKind :: UnaryType ( _, op, _, _) => {
946+ // All of these `UnTypeOp`s should return `size_t`.
947+ let kind = match op {
948+ UnTypeOp :: SizeOf => CTypeKind :: Size ,
949+ UnTypeOp :: AlignOf => CTypeKind :: Size ,
950+ UnTypeOp :: PreferredAlignOf => CTypeKind :: Size ,
951+ } ;
952+ let ty = self
953+ . ast_context
954+ . type_for_kind ( & kind)
955+ . expect ( "CTypeKind::Size should be size_t" ) ;
956+ Some ( CQualTypeId :: new ( ty) )
957+ }
958+ _ => return ,
959+ } ;
960+ let ty = self
961+ . ast_context
962+ . c_exprs
963+ . get_mut ( & e)
964+ . and_then ( |e| e. kind . get_qual_type_mut ( ) ) ;
965+ if let ( Some ( ty) , Some ( new_ty) ) = ( ty, new_ty) {
966+ * ty = new_ty;
967+ } ;
907968 }
908969 }
970+
909971 for decl in self . c_decls_top . clone ( ) {
910972 BubbleExprTypes { ast_context : self } . visit_tree ( SomeId :: Decl ( decl) ) ;
911973 }
@@ -2267,6 +2329,17 @@ impl CTypeKind {
22672329 } ;
22682330 Some ( ty)
22692331 }
2332+
2333+ /// Return the element type of a pointer or array
2334+ pub fn element_ty ( & self ) -> Option < CTypeId > {
2335+ Some ( match * self {
2336+ Self :: Pointer ( ty) => ty. ctype ,
2337+ Self :: ConstantArray ( ty, _) => ty,
2338+ Self :: IncompleteArray ( ty) => ty,
2339+ Self :: VariableArray ( ty, _) => ty,
2340+ _ => return None ,
2341+ } )
2342+ }
22702343}
22712344
22722345#[ cfg( test) ]
0 commit comments