diff --git a/c2rust-transpile/src/c_ast/conversion.rs b/c2rust-transpile/src/c_ast/conversion.rs index e87d895f70..c6ca1d1bda 100644 --- a/c2rust-transpile/src/c_ast/conversion.rs +++ b/c2rust-transpile/src/c_ast/conversion.rs @@ -583,8 +583,7 @@ impl ConversionContext { }) } - /// Visit one node. - fn visit_node( + fn convert_node_as_type( &mut self, untyped_context: &AstContext, node_id: ClangId, // Clang ID of node to visit @@ -593,1528 +592,1473 @@ impl ConversionContext { ) { use self::node_types::*; - if expected_ty & TYPE != 0 { - // Convert the node - let ty_node: &TypeNode = match untyped_context.type_nodes.get(&node_id) { - Some(x) => x, - None => return, - }; - - match ty_node.tag { - TypeTag::TagBool if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Bool)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagVoid if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Void)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagChar if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Char)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagInt if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Int)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagShort if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Short)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagLong if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Long)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } - - TypeTag::TagLongLong if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::LongLong)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + // Convert the node + let ty_node: &TypeNode = match untyped_context.type_nodes.get(&node_id) { + Some(x) => x, + None => return, + }; - TypeTag::TagUInt if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::UInt)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + match ty_node.tag { + TypeTag::TagBool if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Bool)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagUChar if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::UChar)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagVoid if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Void)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagSChar if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::SChar)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagChar if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Char)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagUShort if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::UShort)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagInt if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Int)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagULong if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::ULong)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagShort if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Short)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagULongLong if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::ULongLong)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagLong if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Long)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagDouble if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Double)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagLongLong if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::LongLong)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagLongDouble if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::LongDouble)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagUInt if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::UInt)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagFloat if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Float)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagUChar if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::UChar)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagHalf if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Half)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagSChar if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::SChar)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagBFloat16 if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::BFloat16)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagUShort if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::UShort)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagInt128 if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::Int128)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagULong if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::ULong)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagUInt128 if expected_ty & OTHER_TYPE != 0 => { - self.add_type(new_id, not_located(CTypeKind::UInt128)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagULongLong if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::ULongLong)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagPointer if expected_ty & OTHER_TYPE != 0 => { - let pointed = - from_value(ty_node.extras[0].clone()).expect("Pointer child not found"); - let pointed_new = self.visit_qualified_type(pointed); + TypeTag::TagDouble if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Double)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let pointer_ty = CTypeKind::Pointer(pointed_new); - self.add_type(new_id, not_located(pointer_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagLongDouble if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::LongDouble)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagReference if expected_ty & OTHER_TYPE != 0 => { - let referenced = - from_value(ty_node.extras[0].clone()).expect("Reference child not found"); - let referenced_new = self.visit_qualified_type(referenced); + TypeTag::TagFloat if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Float)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let reference_ty = CTypeKind::Reference(referenced_new); - self.add_type(new_id, not_located(reference_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagHalf if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Half)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagBlockPointer if expected_ty & OTHER_TYPE != 0 => { - let pointed = from_value(ty_node.extras[0].clone()) - .expect("Block pointer child not found"); - let pointed_new = self.visit_qualified_type(pointed); + TypeTag::TagBFloat16 if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::BFloat16)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let pointer_ty = CTypeKind::BlockPointer(pointed_new); - self.add_type(new_id, not_located(pointer_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagInt128 if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::Int128)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagComplexType if expected_ty & OTHER_TYPE != 0 => { - let subelt = - from_value(ty_node.extras[0].clone()).expect("Complex child not found"); - let subelt_new = self.visit_type(subelt); + TypeTag::TagUInt128 if expected_ty & OTHER_TYPE != 0 => { + self.add_type(new_id, not_located(CTypeKind::UInt128)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let complex_ty = CTypeKind::Complex(subelt_new); - self.add_type(new_id, not_located(complex_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagPointer if expected_ty & OTHER_TYPE != 0 => { + let pointed = + from_value(ty_node.extras[0].clone()).expect("Pointer child not found"); + let pointed_new = self.visit_qualified_type(pointed); - TypeTag::TagStructType if expected_ty & OTHER_TYPE != 0 => { - let decl = - from_value(ty_node.extras[0].clone()).expect("Struct decl not found"); - let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL)); + let pointer_ty = CTypeKind::Pointer(pointed_new); + self.add_type(new_id, not_located(pointer_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let record_ty = CTypeKind::Struct(decl_new); - self.add_type(new_id, not_located(record_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagReference if expected_ty & OTHER_TYPE != 0 => { + let referenced = + from_value(ty_node.extras[0].clone()).expect("Reference child not found"); + let referenced_new = self.visit_qualified_type(referenced); - TypeTag::TagUnionType if expected_ty & OTHER_TYPE != 0 => { - let decl = from_value(ty_node.extras[0].clone()).expect("Union decl not found"); - let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL)); + let reference_ty = CTypeKind::Reference(referenced_new); + self.add_type(new_id, not_located(reference_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let record_ty = CTypeKind::Union(decl_new); - self.add_type(new_id, not_located(record_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagBlockPointer if expected_ty & OTHER_TYPE != 0 => { + let pointed = + from_value(ty_node.extras[0].clone()).expect("Block pointer child not found"); + let pointed_new = self.visit_qualified_type(pointed); - TypeTag::TagFunctionType if expected_ty & FUNC_TYPE != 0 => { - let mut arguments: Vec = - from_value::>(ty_node.extras[0].clone()) - .expect("Function type expects array argument") - .iter() - .map(|cbor| { - let arg = - from_value(cbor.clone()).expect("Bad function type child id"); - - self.visit_qualified_type(arg) - }) - .collect(); - let ret = arguments.remove(0); - let is_variadic = from_value(ty_node.extras[1].clone()) - .expect("Variadicity of function type not found"); - let is_noreturn = from_value(ty_node.extras[2].clone()) - .expect("NoReturn of function type not found"); - let has_proto = from_value(ty_node.extras[3].clone()) - .expect("HasProto of function type not found"); - let function_ty = - CTypeKind::Function(ret, arguments, is_variadic, is_noreturn, has_proto); - self.add_type(new_id, not_located(function_ty)); - self.processed_nodes.insert(new_id, FUNC_TYPE); - - // In addition to creating the function type for this node, ensure that a - // corresponding function pointer type is created. We may need to reference this - // type depending on how uses of functions of this type are translated. - let pointer_ty = CTypeKind::Pointer(CQualTypeId::new(CTypeId(new_id))); - let new_id = self.id_mapper.fresh_id(); - self.add_type(new_id, not_located(pointer_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let pointer_ty = CTypeKind::BlockPointer(pointed_new); + self.add_type(new_id, not_located(pointer_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagTypeOfType if expected_ty & TYPE != 0 => { - let type_of_old = from_value(ty_node.extras[0].clone()) - .expect("Type of (type) child not found"); - let type_of = self.visit_type(type_of_old); + TypeTag::TagComplexType if expected_ty & OTHER_TYPE != 0 => { + let subelt = + from_value(ty_node.extras[0].clone()).expect("Complex child not found"); + let subelt_new = self.visit_type(subelt); - let type_of_ty = CTypeKind::TypeOf(type_of); - self.add_type(new_id, not_located(type_of_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let complex_ty = CTypeKind::Complex(subelt_new); + self.add_type(new_id, not_located(complex_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagTypedefType => { - let decl = - from_value(ty_node.extras[0].clone()).expect("Typedef decl not found"); - let decl_new = CDeclId(self.visit_node_type(decl, TYPDEF_DECL)); + TypeTag::TagStructType if expected_ty & OTHER_TYPE != 0 => { + let decl = from_value(ty_node.extras[0].clone()).expect("Struct decl not found"); + let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL)); - let typedef_ty = CTypeKind::Typedef(decl_new); - self.add_type(new_id, not_located(typedef_ty)); - self.processed_nodes.insert(new_id, expected_ty); - } + let record_ty = CTypeKind::Struct(decl_new); + self.add_type(new_id, not_located(record_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagEnumType if expected_ty & OTHER_TYPE != 0 => { - let decl = from_value(ty_node.extras[0].clone()).expect("Enum decl not found"); - let decl_new = CDeclId(self.visit_node_type(decl, ENUM_DECL)); + TypeTag::TagUnionType if expected_ty & OTHER_TYPE != 0 => { + let decl = from_value(ty_node.extras[0].clone()).expect("Union decl not found"); + let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL)); - let enum_ty = CTypeKind::Enum(decl_new); - self.add_type(new_id, not_located(enum_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let record_ty = CTypeKind::Union(decl_new); + self.add_type(new_id, not_located(record_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagDecayedType if expected_ty & OTHER_TYPE != 0 => { - let decayed_id = from_value(ty_node.extras[0].clone()) - .expect("Decayed type child not found"); - let decayed = self.visit_type(decayed_id); + TypeTag::TagFunctionType if expected_ty & FUNC_TYPE != 0 => { + let mut arguments: Vec = + from_value::>(ty_node.extras[0].clone()) + .expect("Function type expects array argument") + .iter() + .map(|cbor| { + let arg = from_value(cbor.clone()).expect("Bad function type child id"); - let decayed_ty = CTypeKind::Decayed(decayed); - self.add_type(new_id, not_located(decayed_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + self.visit_qualified_type(arg) + }) + .collect(); + let ret = arguments.remove(0); + let is_variadic = from_value(ty_node.extras[1].clone()) + .expect("Variadicity of function type not found"); + let is_noreturn = from_value(ty_node.extras[2].clone()) + .expect("NoReturn of function type not found"); + let has_proto = from_value(ty_node.extras[3].clone()) + .expect("HasProto of function type not found"); + let function_ty = + CTypeKind::Function(ret, arguments, is_variadic, is_noreturn, has_proto); + self.add_type(new_id, not_located(function_ty)); + self.processed_nodes.insert(new_id, FUNC_TYPE); + + // In addition to creating the function type for this node, ensure that a + // corresponding function pointer type is created. We may need to reference this + // type depending on how uses of functions of this type are translated. + let pointer_ty = CTypeKind::Pointer(CQualTypeId::new(CTypeId(new_id))); + let new_id = self.id_mapper.fresh_id(); + self.add_type(new_id, not_located(pointer_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagElaboratedType if expected_ty & OTHER_TYPE != 0 => { - let elaborated_id = from_value(ty_node.extras[0].clone()) - .expect("Elaborated type child not found"); - let elaborated = self.visit_type(elaborated_id); + TypeTag::TagTypeOfType if expected_ty & TYPE != 0 => { + let type_of_old = + from_value(ty_node.extras[0].clone()).expect("Type of (type) child not found"); + let type_of = self.visit_type(type_of_old); - let elaborated_ty = CTypeKind::Elaborated(elaborated); - self.add_type(new_id, not_located(elaborated_ty)); - self.processed_nodes.insert(new_id, TYPE); - } + let type_of_ty = CTypeKind::TypeOf(type_of); + self.add_type(new_id, not_located(type_of_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagParenType => { - let paren_id = - from_value(ty_node.extras[0].clone()).expect("Paren type child not found"); - let paren = self.visit_type(paren_id); + TypeTag::TagTypedefType => { + let decl = from_value(ty_node.extras[0].clone()).expect("Typedef decl not found"); + let decl_new = CDeclId(self.visit_node_type(decl, TYPDEF_DECL)); - let paren_ty = CTypeKind::Paren(paren); - self.add_type(new_id, not_located(paren_ty)); - self.processed_nodes.insert(new_id, TYPE); - } + let typedef_ty = CTypeKind::Typedef(decl_new); + self.add_type(new_id, not_located(typedef_ty)); + self.processed_nodes.insert(new_id, expected_ty); + } - TypeTag::TagAttributedType => { - let ty_id = from_value(ty_node.extras[0].clone()) - .expect("Attributed type child not found"); - let ty = self.visit_qualified_type(ty_id); - - let kind = match expect_opt_str(&ty_node.extras[1]) - .expect("Attributed type kind not found") - { - None => None, - Some("noreturn") => Some(Attribute::NoReturn), - Some("nullable") => Some(Attribute::Nullable), - Some("notnull") => Some(Attribute::NotNull), - Some(other) => panic!("Unknown type attribute: {}", other), - }; + TypeTag::TagEnumType if expected_ty & OTHER_TYPE != 0 => { + let decl = from_value(ty_node.extras[0].clone()).expect("Enum decl not found"); + let decl_new = CDeclId(self.visit_node_type(decl, ENUM_DECL)); - let ty = CTypeKind::Attributed(ty, kind); - self.add_type(new_id, not_located(ty)); - self.processed_nodes.insert(new_id, TYPE); - } + let enum_ty = CTypeKind::Enum(decl_new); + self.add_type(new_id, not_located(enum_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagConstantArrayType => { - let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); - let element = self.visit_type(element_id); + TypeTag::TagDecayedType if expected_ty & OTHER_TYPE != 0 => { + let decayed_id = + from_value(ty_node.extras[0].clone()).expect("Decayed type child not found"); + let decayed = self.visit_type(decayed_id); - let count: usize = from_value(ty_node.extras[1].clone()).expect("count"); + let decayed_ty = CTypeKind::Decayed(decayed); + self.add_type(new_id, not_located(decayed_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let element_ty = CTypeKind::ConstantArray(element, count); - self.add_type(new_id, not_located(element_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagElaboratedType if expected_ty & OTHER_TYPE != 0 => { + let elaborated_id = + from_value(ty_node.extras[0].clone()).expect("Elaborated type child not found"); + let elaborated = self.visit_type(elaborated_id); - TypeTag::TagIncompleteArrayType => { - let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); - let element = self.visit_type(element_id); + let elaborated_ty = CTypeKind::Elaborated(elaborated); + self.add_type(new_id, not_located(elaborated_ty)); + self.processed_nodes.insert(new_id, TYPE); + } - let element_ty = CTypeKind::IncompleteArray(element); - self.add_type(new_id, not_located(element_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagParenType => { + let paren_id = + from_value(ty_node.extras[0].clone()).expect("Paren type child not found"); + let paren = self.visit_type(paren_id); - TypeTag::TagVariableArrayType => { - let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); - let element = self.visit_type(element_id); + let paren_ty = CTypeKind::Paren(paren); + self.add_type(new_id, not_located(paren_ty)); + self.processed_nodes.insert(new_id, TYPE); + } - let count_id = expect_opt_u64(&ty_node.extras[1]).expect("count id"); - let count = count_id.map(|x| self.visit_expr(x)); + TypeTag::TagAttributedType => { + let ty_id = + from_value(ty_node.extras[0].clone()).expect("Attributed type child not found"); + let ty = self.visit_qualified_type(ty_id); - let element_ty = CTypeKind::VariableArray(element, count); - self.add_type(new_id, not_located(element_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let kind = match expect_opt_str(&ty_node.extras[1]) + .expect("Attributed type kind not found") + { + None => None, + Some("noreturn") => Some(Attribute::NoReturn), + Some("nullable") => Some(Attribute::Nullable), + Some("notnull") => Some(Attribute::NotNull), + Some(other) => panic!("Unknown type attribute: {}", other), + }; + + let ty = CTypeKind::Attributed(ty, kind); + self.add_type(new_id, not_located(ty)); + self.processed_nodes.insert(new_id, TYPE); + } - TypeTag::TagBuiltinFn => { - let ty = CTypeKind::BuiltinFn; - self.add_type(new_id, not_located(ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagConstantArrayType => { + let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); + let element = self.visit_type(element_id); - TypeTag::TagBFloat16 => { - let ty = CTypeKind::BFloat16; - self.add_type(new_id, not_located(ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let count: usize = from_value(ty_node.extras[1].clone()).expect("count"); - TypeTag::TagSveCount - | TypeTag::TagSveBool - | TypeTag::TagSveBoolx2 - | TypeTag::TagSveBoolx4 => { - let ty = CTypeKind::UnhandledSveType; - self.add_type(new_id, not_located(ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let element_ty = CTypeKind::ConstantArray(element, count); + self.add_type(new_id, not_located(element_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - TypeTag::TagFloat128 => { - let ty = CTypeKind::Float128; - self.add_type(new_id, not_located(ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagIncompleteArrayType => { + let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); + let element = self.visit_type(element_id); - TypeTag::TagVectorType => { - let elt = - from_value(ty_node.extras[0].clone()).expect("Vector child not found"); - let elt_new = self.visit_qualified_type(elt); - let count: usize = from_value(ty_node.extras[1].clone()).expect("count"); + let element_ty = CTypeKind::IncompleteArray(element); + self.add_type(new_id, not_located(element_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - let vector_ty = CTypeKind::Vector(elt_new, count); - self.add_type(new_id, not_located(vector_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + TypeTag::TagVariableArrayType => { + let element_id = from_value(ty_node.extras[0].clone()).expect("element id"); + let element = self.visit_type(element_id); - TypeTag::TagAtomicType => { - let qty = from_value(ty_node.extras[0].clone()).expect("Inner type not found"); - let qty_new = self.visit_qualified_type(qty); - let atomic_ty = CTypeKind::Atomic(qty_new); - self.add_type(new_id, not_located(atomic_ty)); - self.processed_nodes.insert(new_id, OTHER_TYPE); - } + let count_id = expect_opt_u64(&ty_node.extras[1]).expect("count id"); + let count = count_id.map(|x| self.visit_expr(x)); - t => panic!( - "Type conversion not implemented for {:?} expecting {:?}", - t, expected_ty - ), + let element_ty = CTypeKind::VariableArray(element, count); + self.add_type(new_id, not_located(element_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); } - } else { - // Convert the node - let node: &AstNode = match untyped_context.ast_nodes.get(&node_id) { - Some(x) => x, - None => return, - }; - if expected_ty & EXPR != 0 { - for mac_id in &node.macro_expansions { - let mac = CDeclId(self.visit_node_type(*mac_id, MACRO_DECL)); - self.typed_context - .macro_invocations - .entry(CExprId(new_id)) - .or_default() - .push(mac); - } + TypeTag::TagBuiltinFn => { + let ty = CTypeKind::BuiltinFn; + self.add_type(new_id, not_located(ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); } - if let Some(text) = &node.macro_expansion_text { - self.typed_context - .macro_expansion_text - .insert(CExprId(new_id), text.clone()); + TypeTag::TagBFloat16 => { + let ty = CTypeKind::BFloat16; + self.add_type(new_id, not_located(ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); } - match node.tag { - // Statements - ASTEntryTag::TagBreakStmt if expected_ty & OTHER_STMT != 0 => { - self.add_stmt(new_id, located(node, CStmtKind::Break)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } - - ASTEntryTag::TagContinueStmt if expected_ty & OTHER_STMT != 0 => { - self.add_stmt(new_id, located(node, CStmtKind::Continue)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } - - ASTEntryTag::TagCompoundStmt if expected_ty & OTHER_STMT != 0 => { - let constituent_stmts: Vec = node - .children - .iter() - .map(|id| { - let arg_id = id.expect("Compound stmt child not found"); - self.visit_stmt(arg_id) - }) - .collect(); - - let compound_stmt = CStmtKind::Compound(constituent_stmts); + TypeTag::TagSveCount + | TypeTag::TagSveBool + | TypeTag::TagSveBoolx2 + | TypeTag::TagSveBoolx4 => { + let ty = CTypeKind::UnhandledSveType; + self.add_type(new_id, not_located(ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - self.add_stmt(new_id, located(node, compound_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + TypeTag::TagFloat128 => { + let ty = CTypeKind::Float128; + self.add_type(new_id, not_located(ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - ASTEntryTag::TagDeclStmt if expected_ty & OTHER_STMT != 0 => { - let decls = node - .children - .iter() - .map(|decl| { - let decl_id = decl.expect("Decl not found in decl-statement"); - self.visit_decl(decl_id) - }) - .collect(); + TypeTag::TagVectorType => { + let elt = from_value(ty_node.extras[0].clone()).expect("Vector child not found"); + let elt_new = self.visit_qualified_type(elt); + let count: usize = from_value(ty_node.extras[1].clone()).expect("count"); - let decls_stmt = CStmtKind::Decls(decls); + let vector_ty = CTypeKind::Vector(elt_new, count); + self.add_type(new_id, not_located(vector_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - self.add_stmt(new_id, located(node, decls_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + TypeTag::TagAtomicType => { + let qty = from_value(ty_node.extras[0].clone()).expect("Inner type not found"); + let qty_new = self.visit_qualified_type(qty); + let atomic_ty = CTypeKind::Atomic(qty_new); + self.add_type(new_id, not_located(atomic_ty)); + self.processed_nodes.insert(new_id, OTHER_TYPE); + } - ASTEntryTag::TagReturnStmt if expected_ty & OTHER_STMT != 0 => { - let return_expr_opt = node.children[0].map(|id| self.visit_expr(id)); + t => panic!( + "Type conversion not implemented for {:?} expecting {:?}", + t, expected_ty + ), + } + } - let return_stmt = CStmtKind::Return(return_expr_opt); + /// Visit one node. + fn visit_node( + &mut self, + untyped_context: &AstContext, + node_id: ClangId, // Clang ID of node to visit + new_id: ImporterId, // New ID of node to visit + expected_ty: NodeType, // Expected type of node to visit + ) { + use self::node_types::*; - self.add_stmt(new_id, located(node, return_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + if expected_ty & TYPE != 0 { + return self.convert_node_as_type(untyped_context, node_id, new_id, expected_ty); + } + // Convert the node + let node: &AstNode = match untyped_context.ast_nodes.get(&node_id) { + Some(x) => x, + None => return, + }; - ASTEntryTag::TagIfStmt if expected_ty & OTHER_STMT != 0 => { - let scrutinee_old = - node.children[0].expect("If condition expression not found"); - let scrutinee = self.visit_expr(scrutinee_old); + if expected_ty & EXPR != 0 { + for mac_id in &node.macro_expansions { + let mac = CDeclId(self.visit_node_type(*mac_id, MACRO_DECL)); + self.typed_context + .macro_invocations + .entry(CExprId(new_id)) + .or_default() + .push(mac); + } + } - let true_variant_old = - node.children[1].expect("If then body statement not found"); - let true_variant = self.visit_stmt(true_variant_old); + if let Some(text) = &node.macro_expansion_text { + self.typed_context + .macro_expansion_text + .insert(CExprId(new_id), text.clone()); + } - let false_variant = node.children[2].map(|id| self.visit_stmt(id)); + match node.tag { + // Statements + ASTEntryTag::TagBreakStmt if expected_ty & OTHER_STMT != 0 => { + self.add_stmt(new_id, located(node, CStmtKind::Break)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let if_stmt = CStmtKind::If { - scrutinee, - true_variant, - false_variant, - }; + ASTEntryTag::TagContinueStmt if expected_ty & OTHER_STMT != 0 => { + self.add_stmt(new_id, located(node, CStmtKind::Continue)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - self.add_stmt(new_id, located(node, if_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagCompoundStmt if expected_ty & OTHER_STMT != 0 => { + let constituent_stmts: Vec = node + .children + .iter() + .map(|id| { + let arg_id = id.expect("Compound stmt child not found"); + self.visit_stmt(arg_id) + }) + .collect(); - ASTEntryTag::TagGotoStmt if expected_ty & OTHER_STMT != 0 => { - let target_label_old = node.children[0].expect("Goto target label not found"); - let target_label = CStmtId(self.visit_node_type(target_label_old, LABEL_STMT)); + let compound_stmt = CStmtKind::Compound(constituent_stmts); - let goto_stmt = CStmtKind::Goto(target_label); + self.add_stmt(new_id, located(node, compound_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - self.add_stmt(new_id, located(node, goto_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagDeclStmt if expected_ty & OTHER_STMT != 0 => { + let decls = node + .children + .iter() + .map(|decl| { + let decl_id = decl.expect("Decl not found in decl-statement"); + self.visit_decl(decl_id) + }) + .collect(); - ASTEntryTag::TagNullStmt if expected_ty & OTHER_STMT != 0 => { - let null_stmt = CStmtKind::Empty; + let decls_stmt = CStmtKind::Decls(decls); - self.add_stmt(new_id, located(node, null_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + self.add_stmt(new_id, located(node, decls_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - ASTEntryTag::TagAttributedStmt if expected_ty & OTHER_STMT != 0 => { - let substatement = node.children[0].map(|id| self.visit_stmt(id)).unwrap(); - let mut attributes = vec![]; + ASTEntryTag::TagReturnStmt if expected_ty & OTHER_STMT != 0 => { + let return_expr_opt = node.children[0].map(|id| self.visit_expr(id)); - match expect_opt_str(&node.extras[0]) - .expect("Attributed statement kind not found") - { - Some("fallthrough") | Some("__fallthrough__") => { - attributes.push(Attribute::Fallthrough) - } - Some(str) => panic!("Unknown statement attribute: {}", str), - None => panic!("Invalid statement attribute"), - }; + let return_stmt = CStmtKind::Return(return_expr_opt); - let astmt = CStmtKind::Attributed { - attributes, - substatement, - }; + self.add_stmt(new_id, located(node, return_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - self.add_stmt(new_id, located(node, astmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagIfStmt if expected_ty & OTHER_STMT != 0 => { + let scrutinee_old = node.children[0].expect("If condition expression not found"); + let scrutinee = self.visit_expr(scrutinee_old); - ASTEntryTag::TagForStmt if expected_ty & OTHER_STMT != 0 => { - let init = node.children[0].map(|id| self.visit_stmt(id)); + let true_variant_old = node.children[1].expect("If then body statement not found"); + let true_variant = self.visit_stmt(true_variant_old); - let condition = node.children[1].map(|id| self.visit_expr(id)); + let false_variant = node.children[2].map(|id| self.visit_stmt(id)); - let increment = node.children[2].map(|id| self.visit_expr(id)); + let if_stmt = CStmtKind::If { + scrutinee, + true_variant, + false_variant, + }; - let body_old = node.children[3].expect("For loop body not found"); - let body = self.visit_stmt(body_old); + self.add_stmt(new_id, located(node, if_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let for_stmt = CStmtKind::ForLoop { - init, - condition, - increment, - body, - }; + ASTEntryTag::TagGotoStmt if expected_ty & OTHER_STMT != 0 => { + let target_label_old = node.children[0].expect("Goto target label not found"); + let target_label = CStmtId(self.visit_node_type(target_label_old, LABEL_STMT)); - self.add_stmt(new_id, located(node, for_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + let goto_stmt = CStmtKind::Goto(target_label); - ASTEntryTag::TagWhileStmt if expected_ty & OTHER_STMT != 0 => { - let condition_old = node.children[0].expect("While loop condition not found"); - let condition = self.visit_expr(condition_old); + self.add_stmt(new_id, located(node, goto_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let body_old = node.children[1].expect("While loop body not found"); - let body = self.visit_stmt(body_old); + ASTEntryTag::TagNullStmt if expected_ty & OTHER_STMT != 0 => { + let null_stmt = CStmtKind::Empty; - let while_stmt = CStmtKind::While { condition, body }; + self.add_stmt(new_id, located(node, null_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - self.add_stmt(new_id, located(node, while_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagAttributedStmt if expected_ty & OTHER_STMT != 0 => { + let substatement = node.children[0].map(|id| self.visit_stmt(id)).unwrap(); + let mut attributes = vec![]; - ASTEntryTag::TagDoStmt if expected_ty & OTHER_STMT != 0 => { - let body_old = node.children[0].expect("Do loop body not found"); - let body = self.visit_stmt(body_old); + match expect_opt_str(&node.extras[0]).expect("Attributed statement kind not found") + { + Some("fallthrough") | Some("__fallthrough__") => { + attributes.push(Attribute::Fallthrough) + } + Some(str) => panic!("Unknown statement attribute: {}", str), + None => panic!("Invalid statement attribute"), + }; - let condition_old = node.children[1].expect("Do loop condition not found"); - let condition = self.visit_expr(condition_old); + let astmt = CStmtKind::Attributed { + attributes, + substatement, + }; - let do_stmt = CStmtKind::DoWhile { body, condition }; + self.add_stmt(new_id, located(node, astmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - self.add_stmt(new_id, located(node, do_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagForStmt if expected_ty & OTHER_STMT != 0 => { + let init = node.children[0].map(|id| self.visit_stmt(id)); - ASTEntryTag::TagLabelStmt if expected_ty & LABEL_STMT != 0 => { - let substmt_old = node.children[0].expect("Label sub-statement not found"); - let substmt = self.visit_stmt(substmt_old); - - let label_name = from_value::>(node.extras[0].clone()) - .expect("unnamed label in C source code"); - if let Some(old_label_name) = self - .typed_context - .label_names - .insert(CStmtId(new_id), label_name.clone()) - { - panic!( - "Duplicate label name with id {}. Old name: {}. New name: {}", - new_id, old_label_name, label_name, - ); - } + let condition = node.children[1].map(|id| self.visit_expr(id)); - let label_stmt = CStmtKind::Label(substmt); + let increment = node.children[2].map(|id| self.visit_expr(id)); - self.add_stmt(new_id, located(node, label_stmt)); - self.processed_nodes.insert(new_id, LABEL_STMT); - } + let body_old = node.children[3].expect("For loop body not found"); + let body = self.visit_stmt(body_old); - ASTEntryTag::TagSwitchStmt if expected_ty & OTHER_STMT != 0 => { - let scrutinee_old = node.children[0].expect("Switch expression not found"); - let scrutinee = self.visit_expr(scrutinee_old); + let for_stmt = CStmtKind::ForLoop { + init, + condition, + increment, + body, + }; - let body_old = node.children[1].expect("Switch body not found"); - let body = self.visit_stmt(body_old); + self.add_stmt(new_id, located(node, for_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let switch_stmt = CStmtKind::Switch { scrutinee, body }; + ASTEntryTag::TagWhileStmt if expected_ty & OTHER_STMT != 0 => { + let condition_old = node.children[0].expect("While loop condition not found"); + let condition = self.visit_expr(condition_old); - self.add_stmt(new_id, located(node, switch_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + let body_old = node.children[1].expect("While loop body not found"); + let body = self.visit_stmt(body_old); - ASTEntryTag::TagCaseStmt if expected_ty & OTHER_STMT != 0 => { - let expr_old = node.children[0].expect("Case expression not found"); - let expr = self.visit_expr(expr_old); + let while_stmt = CStmtKind::While { condition, body }; - let substmt_old = node.children[1].expect("Case sub-statement not found"); - let substmt = self.visit_stmt(substmt_old); + self.add_stmt(new_id, located(node, while_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let is_signed = from_value(node.extras[0].clone()) - .expect("Case constant is_signed not found"); - let cie = match is_signed { - false => ConstIntExpr::U( - from_value(node.extras[1].clone()).expect("Case constant not found"), - ), - true => ConstIntExpr::I( - from_value(node.extras[1].clone()).expect("Case constant not found"), - ), - }; + ASTEntryTag::TagDoStmt if expected_ty & OTHER_STMT != 0 => { + let body_old = node.children[0].expect("Do loop body not found"); + let body = self.visit_stmt(body_old); - let case_stmt = CStmtKind::Case(expr, substmt, cie); + let condition_old = node.children[1].expect("Do loop condition not found"); + let condition = self.visit_expr(condition_old); - self.add_stmt(new_id, located(node, case_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + let do_stmt = CStmtKind::DoWhile { body, condition }; - ASTEntryTag::TagDefaultStmt if expected_ty & OTHER_STMT != 0 => { - let substmt_old = node.children[0].expect("Default sub-statement not found"); - let substmt = self.visit_stmt(substmt_old); + self.add_stmt(new_id, located(node, do_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let default_stmt = CStmtKind::Default(substmt); + ASTEntryTag::TagLabelStmt if expected_ty & LABEL_STMT != 0 => { + let substmt_old = node.children[0].expect("Label sub-statement not found"); + let substmt = self.visit_stmt(substmt_old); - self.add_stmt(new_id, located(node, default_stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); + let label_name = from_value::>(node.extras[0].clone()) + .expect("unnamed label in C source code"); + if let Some(old_label_name) = self + .typed_context + .label_names + .insert(CStmtId(new_id), label_name.clone()) + { + panic!( + "Duplicate label name with id {}. Old name: {}. New name: {}", + new_id, old_label_name, label_name, + ); } - ASTEntryTag::TagAsmStmt if expected_ty & OTHER_STMT != 0 => { - let is_volatile = from_value(node.extras[0].clone()).expect("volatile flag"); - let asm = from_value(node.extras[1].clone()).expect("assembly string"); - let raw_inputs = from_value::>(node.extras[2].clone()) - .expect("input constraints array"); - let raw_outputs = from_value::>(node.extras[3].clone()) - .expect("output constraints array"); - let raw_clobbers = - from_value::>(node.extras[4].clone()).expect("clobber array"); - - let (input_children, output_children) = - node.children.split_at(raw_inputs.len()); - - let inputs: Vec = raw_inputs - .into_iter() - .zip(input_children) - .map(|(c, e)| { - let constraints = from_value(c).expect("constraint string"); - let expression = self.visit_expr(e.expect("expression")); - AsmOperand { - constraints, - expression, - } - }) - .collect(); + let label_stmt = CStmtKind::Label(substmt); - let outputs: Vec = raw_outputs - .into_iter() - .zip(output_children) - .map(|(c, e)| { - let constraints = from_value(c).expect("constraint string"); - let expression = self.visit_expr(e.expect("expression")); - AsmOperand { - constraints, - expression, - } - }) - .collect(); - - let clobbers: Vec = raw_clobbers - .into_iter() - .map(|c| from_value(c).expect("clobber string")) - .collect(); + self.add_stmt(new_id, located(node, label_stmt)); + self.processed_nodes.insert(new_id, LABEL_STMT); + } - let stmt = CStmtKind::Asm { - is_volatile, - asm, - inputs, - outputs, - clobbers, - }; - self.add_stmt(new_id, located(node, stmt)); - self.processed_nodes.insert(new_id, OTHER_STMT); - } + ASTEntryTag::TagSwitchStmt if expected_ty & OTHER_STMT != 0 => { + let scrutinee_old = node.children[0].expect("Switch expression not found"); + let scrutinee = self.visit_expr(scrutinee_old); - // Expressions - ASTEntryTag::TagParenExpr if expected_ty & (EXPR | STMT) != 0 => { - let wrapped = node.children[0].expect("Expected wrapped paren expression"); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let body_old = node.children[1].expect("Switch body not found"); + let body = self.visit_stmt(body_old); - let expr = CExprKind::Paren(ty, self.visit_expr(wrapped)); + let switch_stmt = CStmtKind::Switch { scrutinee, body }; - self.expr_possibly_as_stmt(expected_ty, new_id, node, expr); - } + self.add_stmt(new_id, located(node, switch_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - ASTEntryTag::TagOffsetOfExpr if expected_ty & (EXPR | STMT) != 0 => { - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); - // Either we're able to evaluate the offsetof to an int constant expr - // or else we have to use the offset_of! macro from the memoffset crate - let offset_of = if let Ok(value) = from_value(node.extras[0].clone()) { - let kind = OffsetOfKind::Constant(value); + ASTEntryTag::TagCaseStmt if expected_ty & OTHER_STMT != 0 => { + let expr_old = node.children[0].expect("Case expression not found"); + let expr = self.visit_expr(expr_old); - CExprKind::OffsetOf(ty, kind) - } else { - let qty_int = from_value(node.extras[1].clone()) - .expect("Expected offset of to have struct type"); - let qty = self.visit_qualified_type(qty_int); - let field = - from_value(node.extras[2].clone()).expect("Expected offset of field"); - let field_id = self.visit_decl(field); - let index = from_value(node.extras[3].clone()) - .expect("Expected offset of index expr"); - let index_expr_id = self.visit_expr(index); - let kind = OffsetOfKind::Variable(qty, field_id, index_expr_id); - - CExprKind::OffsetOf(ty, kind) - }; + let substmt_old = node.children[1].expect("Case sub-statement not found"); + let substmt = self.visit_stmt(substmt_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, offset_of); - } + let is_signed = + from_value(node.extras[0].clone()).expect("Case constant is_signed not found"); + let cie = match is_signed { + false => ConstIntExpr::U( + from_value(node.extras[1].clone()).expect("Case constant not found"), + ), + true => ConstIntExpr::I( + from_value(node.extras[1].clone()).expect("Case constant not found"), + ), + }; - ASTEntryTag::TagIntegerLiteral if expected_ty & (EXPR | STMT) != 0 => { - let value = - from_value(node.extras[0].clone()).expect("Expected integer literal value"); - let base = - from_value(node.extras[1].clone()).expect("Expected integer base value"); - - let base = match base { - 8 => IntBase::Oct, - 10 => IntBase::Dec, - 16 => IntBase::Hex, - _ => panic!("Invalid base: {}", base), - }; + let case_stmt = CStmtKind::Case(expr, substmt, cie); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + self.add_stmt(new_id, located(node, case_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let integer_literal = CExprKind::Literal(ty, CLiteral::Integer(value, base)); + ASTEntryTag::TagDefaultStmt if expected_ty & OTHER_STMT != 0 => { + let substmt_old = node.children[0].expect("Default sub-statement not found"); + let substmt = self.visit_stmt(substmt_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, integer_literal); - } + let default_stmt = CStmtKind::Default(substmt); - ASTEntryTag::TagStringLiteral if expected_ty & (EXPR | STMT) != 0 => { - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); - let width: u8 = - from_value(node.extras[1].clone()).expect("string literal char width"); - let bytes = from_value::(node.extras[2].clone()) - .expect("string literal bytes"); - let string_literal = - CExprKind::Literal(ty, CLiteral::String(bytes.into_vec(), width)); - self.expr_possibly_as_stmt(expected_ty, new_id, node, string_literal); - } + self.add_stmt(new_id, located(node, default_stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - ASTEntryTag::TagCharacterLiteral if expected_ty & (EXPR | STMT) != 0 => { - let value = from_value(node.extras[0].clone()) - .expect("Expected character literal value"); + ASTEntryTag::TagAsmStmt if expected_ty & OTHER_STMT != 0 => { + let is_volatile = from_value(node.extras[0].clone()).expect("volatile flag"); + let asm = from_value(node.extras[1].clone()).expect("assembly string"); + let raw_inputs = from_value::>(node.extras[2].clone()) + .expect("input constraints array"); + let raw_outputs = from_value::>(node.extras[3].clone()) + .expect("output constraints array"); + let raw_clobbers = + from_value::>(node.extras[4].clone()).expect("clobber array"); + + let (input_children, output_children) = node.children.split_at(raw_inputs.len()); + + let inputs: Vec = raw_inputs + .into_iter() + .zip(input_children) + .map(|(c, e)| { + let constraints = from_value(c).expect("constraint string"); + let expression = self.visit_expr(e.expect("expression")); + AsmOperand { + constraints, + expression, + } + }) + .collect(); + + let outputs: Vec = raw_outputs + .into_iter() + .zip(output_children) + .map(|(c, e)| { + let constraints = from_value(c).expect("constraint string"); + let expression = self.visit_expr(e.expect("expression")); + AsmOperand { + constraints, + expression, + } + }) + .collect(); + + let clobbers: Vec = raw_clobbers + .into_iter() + .map(|c| from_value(c).expect("clobber string")) + .collect(); + + let stmt = CStmtKind::Asm { + is_volatile, + asm, + inputs, + outputs, + clobbers, + }; + self.add_stmt(new_id, located(node, stmt)); + self.processed_nodes.insert(new_id, OTHER_STMT); + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + // Expressions + ASTEntryTag::TagParenExpr if expected_ty & (EXPR | STMT) != 0 => { + let wrapped = node.children[0].expect("Expected wrapped paren expression"); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let character_literal = CExprKind::Literal(ty, CLiteral::Character(value)); + let expr = CExprKind::Paren(ty, self.visit_expr(wrapped)); - self.expr_possibly_as_stmt(expected_ty, new_id, node, character_literal); - } + self.expr_possibly_as_stmt(expected_ty, new_id, node, expr); + } - ASTEntryTag::TagFloatingLiteral if expected_ty & (EXPR | STMT) != 0 => { - let value = - from_value(node.extras[0].clone()).expect("Expected float literal value"); - let c_str = from_value::(node.extras[1].clone()) - .expect("Expected float literal string"); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagOffsetOfExpr if expected_ty & (EXPR | STMT) != 0 => { + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); + // Either we're able to evaluate the offsetof to an int constant expr + // or else we have to use the offset_of! macro from the memoffset crate + let offset_of = if let Ok(value) = from_value(node.extras[0].clone()) { + let kind = OffsetOfKind::Constant(value); + + CExprKind::OffsetOf(ty, kind) + } else { + let qty_int = from_value(node.extras[1].clone()) + .expect("Expected offset of to have struct type"); + let qty = self.visit_qualified_type(qty_int); + let field = + from_value(node.extras[2].clone()).expect("Expected offset of field"); + let field_id = self.visit_decl(field); + let index = + from_value(node.extras[3].clone()).expect("Expected offset of index expr"); + let index_expr_id = self.visit_expr(index); + let kind = OffsetOfKind::Variable(qty, field_id, index_expr_id); + + CExprKind::OffsetOf(ty, kind) + }; + + self.expr_possibly_as_stmt(expected_ty, new_id, node, offset_of); + } - let floating_literal = CExprKind::Literal(ty, CLiteral::Floating(value, c_str)); + ASTEntryTag::TagIntegerLiteral if expected_ty & (EXPR | STMT) != 0 => { + let value = + from_value(node.extras[0].clone()).expect("Expected integer literal value"); + let base = from_value(node.extras[1].clone()).expect("Expected integer base value"); - self.expr_possibly_as_stmt(expected_ty, new_id, node, floating_literal); - } + let base = match base { + 8 => IntBase::Oct, + 10 => IntBase::Dec, + 16 => IntBase::Hex, + _ => panic!("Invalid base: {}", base), + }; - ASTEntryTag::TagUnaryOperator if expected_ty & (EXPR | STMT) != 0 => { - let prefix = - from_value(node.extras[1].clone()).expect("Expected prefix information"); - - let operator = match from_value::(node.extras[0].clone()) - .expect("Expected operator") - .as_str() - { - "&" => UnOp::AddressOf, - "*" => UnOp::Deref, - "+" => UnOp::Plus, - "-" => UnOp::Negate, - "~" => UnOp::Complement, - "!" => UnOp::Not, - "++" => { - if prefix { - UnOp::PreIncrement - } else { - UnOp::PostIncrement - } - } - "--" => { - if prefix { - UnOp::PreDecrement - } else { - UnOp::PostDecrement - } - } - "__real" => UnOp::Real, - "__imag" => UnOp::Imag, - "__extension__" => UnOp::Extension, - "co_await" => UnOp::Coawait, - o => panic!("Unexpected operator: {}", o), - }; + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let operand_old = node.children[0].expect("Expected operand"); - let operand = self.visit_expr(operand_old); + let integer_literal = CExprKind::Literal(ty, CLiteral::Integer(value, base)); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, integer_literal); + } - let unary = CExprKind::Unary(ty, operator, operand, node.rvalue); + ASTEntryTag::TagStringLiteral if expected_ty & (EXPR | STMT) != 0 => { + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); + let width: u8 = + from_value(node.extras[1].clone()).expect("string literal char width"); + let bytes = + from_value::(node.extras[2].clone()).expect("string literal bytes"); + let string_literal = + CExprKind::Literal(ty, CLiteral::String(bytes.into_vec(), width)); + self.expr_possibly_as_stmt(expected_ty, new_id, node, string_literal); + } - self.expr_possibly_as_stmt(expected_ty, new_id, node, unary); - } + ASTEntryTag::TagCharacterLiteral if expected_ty & (EXPR | STMT) != 0 => { + let value = + from_value(node.extras[0].clone()).expect("Expected character literal value"); - ASTEntryTag::TagImplicitCastExpr if expected_ty & (EXPR | STMT) != 0 => { - let expression_old = - node.children[0].expect("Expected expression for implicit cast"); - let expression = self.visit_expr(expression_old); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let typ_old = node.type_id.expect("Expected type for implicit cast"); - let typ = self.visit_qualified_type(typ_old); + let character_literal = CExprKind::Literal(ty, CLiteral::Character(value)); - let kind = parse_cast_kind( - &from_value::(node.extras[0].clone()).expect("Expected cast kind"), - ); - let implicit = - CExprKind::ImplicitCast(typ, expression, kind, None, node.rvalue); + self.expr_possibly_as_stmt(expected_ty, new_id, node, character_literal); + } - self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit); - } + ASTEntryTag::TagFloatingLiteral if expected_ty & (EXPR | STMT) != 0 => { + let value = + from_value(node.extras[0].clone()).expect("Expected float literal value"); + let c_str = from_value::(node.extras[1].clone()) + .expect("Expected float literal string"); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - ASTEntryTag::TagCStyleCastExpr if expected_ty & (EXPR | STMT) != 0 => { - let expression_old = - node.children[0].expect("Expected expression for explicit cast"); - let expression = self.visit_expr(expression_old); + let floating_literal = CExprKind::Literal(ty, CLiteral::Floating(value, c_str)); - let typ_old = node.type_id.expect("Expected type for explicit cast"); - let typ = self.visit_qualified_type(typ_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, floating_literal); + } - let kind = parse_cast_kind( - &from_value::(node.extras[0].clone()).expect("Expected cast kind"), - ); + ASTEntryTag::TagUnaryOperator if expected_ty & (EXPR | STMT) != 0 => { + let prefix = + from_value(node.extras[1].clone()).expect("Expected prefix information"); - let opt_field_id = match kind { - CastKind::ToUnion => { - let id = node.children[1].expect("Expected field for union cast"); - Some(self.visit_decl(id)) + let operator = match from_value::(node.extras[0].clone()) + .expect("Expected operator") + .as_str() + { + "&" => UnOp::AddressOf, + "*" => UnOp::Deref, + "+" => UnOp::Plus, + "-" => UnOp::Negate, + "~" => UnOp::Complement, + "!" => UnOp::Not, + "++" => { + if prefix { + UnOp::PreIncrement + } else { + UnOp::PostIncrement } - _ => None, - }; - - let implicit = - CExprKind::ExplicitCast(typ, expression, kind, opt_field_id, node.rvalue); + } + "--" => { + if prefix { + UnOp::PreDecrement + } else { + UnOp::PostDecrement + } + } + "__real" => UnOp::Real, + "__imag" => UnOp::Imag, + "__extension__" => UnOp::Extension, + "co_await" => UnOp::Coawait, + o => panic!("Unexpected operator: {}", o), + }; - self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit); - } + let operand_old = node.children[0].expect("Expected operand"); + let operand = self.visit_expr(operand_old); - ASTEntryTag::TagCallExpr if expected_ty & (EXPR | STMT) != 0 => { - let func_old = node.children[0].expect("Expected function for function call"); - let func = self.visit_expr(func_old); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let args: Vec = node - .children - .iter() - .skip(1) - .map(|id| { - let arg_id = id.expect("Expected call expression argument"); - self.visit_expr(arg_id) - }) - .collect(); + let unary = CExprKind::Unary(ty, operator, operand, node.rvalue); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, unary); + } - let call = CExprKind::Call(ty, func, args); + ASTEntryTag::TagImplicitCastExpr if expected_ty & (EXPR | STMT) != 0 => { + let expression_old = + node.children[0].expect("Expected expression for implicit cast"); + let expression = self.visit_expr(expression_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, call); - } + let typ_old = node.type_id.expect("Expected type for implicit cast"); + let typ = self.visit_qualified_type(typ_old); - ASTEntryTag::TagMemberExpr if expected_ty & (EXPR | STMT) != 0 => { - let base_old = node.children[0].expect("Expected base for member expression"); - let base = self.visit_expr(base_old); + let kind = parse_cast_kind( + &from_value::(node.extras[0].clone()).expect("Expected cast kind"), + ); + let implicit = CExprKind::ImplicitCast(typ, expression, kind, None, node.rvalue); - let field_old = node.children[1].expect("Expected field for member expression"); - let field = self.visit_decl(field_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit); + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagCStyleCastExpr if expected_ty & (EXPR | STMT) != 0 => { + let expression_old = + node.children[0].expect("Expected expression for explicit cast"); + let expression = self.visit_expr(expression_old); - let member_kind = if from_value(node.extras[0].clone()).expect("is arrow") { - MemberKind::Arrow - } else { - MemberKind::Dot - }; + let typ_old = node.type_id.expect("Expected type for explicit cast"); + let typ = self.visit_qualified_type(typ_old); - let member = CExprKind::Member(ty, base, field, member_kind, node.rvalue); + let kind = parse_cast_kind( + &from_value::(node.extras[0].clone()).expect("Expected cast kind"), + ); - self.expr_possibly_as_stmt(expected_ty, new_id, node, member); - } + let opt_field_id = match kind { + CastKind::ToUnion => { + let id = node.children[1].expect("Expected field for union cast"); + Some(self.visit_decl(id)) + } + _ => None, + }; - ASTEntryTag::TagBinaryOperator if expected_ty & (EXPR | STMT) != 0 => { - let operator = match from_value::(node.extras[0].clone()) - .expect("Expected operator") - .as_str() - { - "*" => BinOp::Multiply, - "/" => BinOp::Divide, - "%" => BinOp::Modulus, - "+" => BinOp::Add, - "-" => BinOp::Subtract, - "<<" => BinOp::ShiftLeft, - ">>" => BinOp::ShiftRight, - "<" => BinOp::Less, - ">" => BinOp::Greater, - "<=" => BinOp::LessEqual, - ">=" => BinOp::GreaterEqual, - "==" => BinOp::EqualEqual, - "!=" => BinOp::NotEqual, - "&" => BinOp::BitAnd, - "^" => BinOp::BitXor, - "|" => BinOp::BitOr, - "&&" => BinOp::And, - "||" => BinOp::Or, - "+=" => BinOp::AssignAdd, - "-=" => BinOp::AssignSubtract, - "*=" => BinOp::AssignMultiply, - "/=" => BinOp::AssignDivide, - "%=" => BinOp::AssignModulus, - "^=" => BinOp::AssignBitXor, - "<<=" => BinOp::AssignShiftLeft, - ">>=" => BinOp::AssignShiftRight, - "|=" => BinOp::AssignBitOr, - "&=" => BinOp::AssignBitAnd, - "=" => BinOp::Assign, - "," => BinOp::Comma, - _ => unimplemented!(), - }; + let implicit = + CExprKind::ExplicitCast(typ, expression, kind, opt_field_id, node.rvalue); - let left_operand_old = node.children[0].expect("Expected left operand"); - let left_operand = self.visit_expr(left_operand_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit); + } - let right_operand_old = node.children[1].expect("Expected right operand"); - let right_operand = self.visit_expr(right_operand_old); + ASTEntryTag::TagCallExpr if expected_ty & (EXPR | STMT) != 0 => { + let func_old = node.children[0].expect("Expected function for function call"); + let func = self.visit_expr(func_old); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let args: Vec = node + .children + .iter() + .skip(1) + .map(|id| { + let arg_id = id.expect("Expected call expression argument"); + self.visit_expr(arg_id) + }) + .collect(); - let opt_lhs_type_id = - expect_opt_u64(&node.extras[1]).expect("Expected compute lhs type"); - let opt_lhs_type = opt_lhs_type_id.map(|x| self.visit_qualified_type(x)); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let opt_res_type_id = - expect_opt_u64(&node.extras[2]).expect("Expected compute lhs type"); - let opt_res_type = opt_res_type_id.map(|x| self.visit_qualified_type(x)); + let call = CExprKind::Call(ty, func, args); - let binary = CExprKind::Binary( - ty, - operator, - left_operand, - right_operand, - opt_lhs_type, - opt_res_type, - ); + self.expr_possibly_as_stmt(expected_ty, new_id, node, call); + } - self.expr_possibly_as_stmt(expected_ty, new_id, node, binary); - } + ASTEntryTag::TagMemberExpr if expected_ty & (EXPR | STMT) != 0 => { + let base_old = node.children[0].expect("Expected base for member expression"); + let base = self.visit_expr(base_old); - ASTEntryTag::TagDeclRefExpr if expected_ty & (EXPR | STMT) != 0 => { - let declaration_old = - node.children[0].expect("Expected declaration on expression tag decl"); - let declaration = self.visit_decl(declaration_old); + let field_old = node.children[1].expect("Expected field for member expression"); + let field = self.visit_decl(field_old); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let decl = CExprKind::DeclRef(ty, declaration, node.rvalue); + let member_kind = if from_value(node.extras[0].clone()).expect("is arrow") { + MemberKind::Arrow + } else { + MemberKind::Dot + }; - self.expr_possibly_as_stmt(expected_ty, new_id, node, decl); - } + let member = CExprKind::Member(ty, base, field, member_kind, node.rvalue); - ASTEntryTag::TagArraySubscriptExpr if expected_ty & (EXPR | STMT) != 0 => { - let lhs_old = - node.children[0].expect("Expected LHS on array subscript expression"); - let lhs = self.visit_expr(lhs_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, member); + } - let rhs_old = - node.children[1].expect("Expected RHS on array subscript expression"); - let rhs = self.visit_expr(rhs_old); + ASTEntryTag::TagBinaryOperator if expected_ty & (EXPR | STMT) != 0 => { + let operator = match from_value::(node.extras[0].clone()) + .expect("Expected operator") + .as_str() + { + "*" => BinOp::Multiply, + "/" => BinOp::Divide, + "%" => BinOp::Modulus, + "+" => BinOp::Add, + "-" => BinOp::Subtract, + "<<" => BinOp::ShiftLeft, + ">>" => BinOp::ShiftRight, + "<" => BinOp::Less, + ">" => BinOp::Greater, + "<=" => BinOp::LessEqual, + ">=" => BinOp::GreaterEqual, + "==" => BinOp::EqualEqual, + "!=" => BinOp::NotEqual, + "&" => BinOp::BitAnd, + "^" => BinOp::BitXor, + "|" => BinOp::BitOr, + "&&" => BinOp::And, + "||" => BinOp::Or, + "+=" => BinOp::AssignAdd, + "-=" => BinOp::AssignSubtract, + "*=" => BinOp::AssignMultiply, + "/=" => BinOp::AssignDivide, + "%=" => BinOp::AssignModulus, + "^=" => BinOp::AssignBitXor, + "<<=" => BinOp::AssignShiftLeft, + ">>=" => BinOp::AssignShiftRight, + "|=" => BinOp::AssignBitOr, + "&=" => BinOp::AssignBitAnd, + "=" => BinOp::Assign, + "," => BinOp::Comma, + _ => unimplemented!(), + }; + + let left_operand_old = node.children[0].expect("Expected left operand"); + let left_operand = self.visit_expr(left_operand_old); + + let right_operand_old = node.children[1].expect("Expected right operand"); + let right_operand = self.visit_expr(right_operand_old); + + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); + + let opt_lhs_type_id = + expect_opt_u64(&node.extras[1]).expect("Expected compute lhs type"); + let opt_lhs_type = opt_lhs_type_id.map(|x| self.visit_qualified_type(x)); + + let opt_res_type_id = + expect_opt_u64(&node.extras[2]).expect("Expected compute lhs type"); + let opt_res_type = opt_res_type_id.map(|x| self.visit_qualified_type(x)); + + let binary = CExprKind::Binary( + ty, + operator, + left_operand, + right_operand, + opt_lhs_type, + opt_res_type, + ); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, binary); + } - let subscript = CExprKind::ArraySubscript(ty, lhs, rhs, node.rvalue); + ASTEntryTag::TagDeclRefExpr if expected_ty & (EXPR | STMT) != 0 => { + let declaration_old = + node.children[0].expect("Expected declaration on expression tag decl"); + let declaration = self.visit_decl(declaration_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, subscript); - } + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - ASTEntryTag::TagConditionalOperator if expected_ty & (EXPR | STMT) != 0 => { - let cond_old = node.children[0].expect("Expected condition on if expression"); - let cond = self.visit_expr(cond_old); + let decl = CExprKind::DeclRef(ty, declaration, node.rvalue); - let lhs_old = node.children[1].expect("Expected 'then' on if expression"); - let lhs = self.visit_expr(lhs_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, decl); + } - let rhs_old = node.children[2].expect("Expected 'else' on if expression"); - let rhs = self.visit_expr(rhs_old); + ASTEntryTag::TagArraySubscriptExpr if expected_ty & (EXPR | STMT) != 0 => { + let lhs_old = node.children[0].expect("Expected LHS on array subscript expression"); + let lhs = self.visit_expr(lhs_old); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let rhs_old = node.children[1].expect("Expected RHS on array subscript expression"); + let rhs = self.visit_expr(rhs_old); - let conditional = CExprKind::Conditional(ty, cond, lhs, rhs); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional); - } + let subscript = CExprKind::ArraySubscript(ty, lhs, rhs, node.rvalue); - ASTEntryTag::TagBinaryConditionalOperator if expected_ty & (EXPR | STMT) != 0 => { - let lhs_old = node.children[0].expect("Expected condition on if expression"); - let lhs = self.visit_expr(lhs_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, subscript); + } - let rhs_old = node.children[1].expect("Expected 'else' on if expression"); - let rhs = self.visit_expr(rhs_old); + ASTEntryTag::TagConditionalOperator if expected_ty & (EXPR | STMT) != 0 => { + let cond_old = node.children[0].expect("Expected condition on if expression"); + let cond = self.visit_expr(cond_old); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let lhs_old = node.children[1].expect("Expected 'then' on if expression"); + let lhs = self.visit_expr(lhs_old); - let conditional = CExprKind::BinaryConditional(ty, lhs, rhs); + let rhs_old = node.children[2].expect("Expected 'else' on if expression"); + let rhs = self.visit_expr(rhs_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional); - } + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - ASTEntryTag::TagUnaryExprOrTypeTraitExpr if expected_ty & (EXPR | STMT) != 0 => { - let ty = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty); + let conditional = CExprKind::Conditional(ty, cond, lhs, rhs); - let expr = node.children[0].map(|x| self.visit_expr(x)); + self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional); + } - let kind_name = - from_value::(node.extras[0].clone()).expect("expected kind"); - let kind = match kind_name.as_str() { - "sizeof" => UnTypeOp::SizeOf, - "alignof" => UnTypeOp::AlignOf, - "preferredalignof" => UnTypeOp::PreferredAlignOf, - str => panic!("Unsupported operation: {}", str), - }; + ASTEntryTag::TagBinaryConditionalOperator if expected_ty & (EXPR | STMT) != 0 => { + let lhs_old = node.children[0].expect("Expected condition on if expression"); + let lhs = self.visit_expr(lhs_old); - let arg_ty = from_value(node.extras[1].clone()).expect("expected type id"); - let arg_ty = self.visit_qualified_type(arg_ty); + let rhs_old = node.children[1].expect("Expected 'else' on if expression"); + let rhs = self.visit_expr(rhs_old); - let operator = CExprKind::UnaryType(ty, kind, expr, arg_ty); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, operator); - } + let conditional = CExprKind::BinaryConditional(ty, lhs, rhs); - ASTEntryTag::TagCompoundLiteralExpr => { - let ty_old = node - .type_id - .expect("Expected compound literal to have type"); - let ty = self.visit_qualified_type(ty_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional); + } - let val_old = node.children[0].expect("Expected child on compound literal"); - let val = self.visit_expr(val_old); + ASTEntryTag::TagUnaryExprOrTypeTraitExpr if expected_ty & (EXPR | STMT) != 0 => { + let ty = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty); - self.expr_possibly_as_stmt( - expected_ty, - new_id, - node, - CExprKind::CompoundLiteral(ty, val), - ) - } + let expr = node.children[0].map(|x| self.visit_expr(x)); - ASTEntryTag::TagPredefinedExpr => { - let ty_old = node.type_id.expect("Expected predefined expr to have type"); - let ty = self.visit_qualified_type(ty_old); + let kind_name = + from_value::(node.extras[0].clone()).expect("expected kind"); + let kind = match kind_name.as_str() { + "sizeof" => UnTypeOp::SizeOf, + "alignof" => UnTypeOp::AlignOf, + "preferredalignof" => UnTypeOp::PreferredAlignOf, + str => panic!("Unsupported operation: {}", str), + }; - let val_old = node.children[0].expect("Expected child on predefined expr"); - let val = self.visit_expr(val_old); + let arg_ty = from_value(node.extras[1].clone()).expect("expected type id"); + let arg_ty = self.visit_qualified_type(arg_ty); - self.expr_possibly_as_stmt( - expected_ty, - new_id, - node, - CExprKind::Predefined(ty, val), - ) - } - - ASTEntryTag::TagImplicitValueInitExpr => { - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let operator = CExprKind::UnaryType(ty, kind, expr, arg_ty); - self.expr_possibly_as_stmt( - expected_ty, - new_id, - node, - CExprKind::ImplicitValueInit(ty), - ) - } + self.expr_possibly_as_stmt(expected_ty, new_id, node, operator); + } - ASTEntryTag::TagInitListExpr => { - let exprs: Vec = node - .children - .iter() - .map(|id| { - let expr_id = id.expect("init expression id"); - self.visit_expr(expr_id) - }) - .collect(); + ASTEntryTag::TagCompoundLiteralExpr => { + let ty_old = node + .type_id + .expect("Expected compound literal to have type"); + let ty = self.visit_qualified_type(ty_old); - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + let val_old = node.children[0].expect("Expected child on compound literal"); + let val = self.visit_expr(val_old); - let union_field_id = expect_opt_u64(&node.extras[0]) - .expect("Bad union field ID entry") - .map(|x| self.visit_decl(x)); - let syntax_id = expect_opt_u64(&node.extras[1]) - .expect("Bad syntax ID entry") - .map(|x| self.visit_expr(x)); + self.expr_possibly_as_stmt( + expected_ty, + new_id, + node, + CExprKind::CompoundLiteral(ty, val), + ) + } - let kind = CExprKind::InitList(ty, exprs, union_field_id, syntax_id); - self.expr_possibly_as_stmt(expected_ty, new_id, node, kind) - } + ASTEntryTag::TagPredefinedExpr => { + let ty_old = node.type_id.expect("Expected predefined expr to have type"); + let ty = self.visit_qualified_type(ty_old); - ASTEntryTag::TagDesignatedInitExpr => { - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); - - let designator_cbors = from_value::>(node.extras[0].clone()) - .expect("Expected designators array"); - let designators = designator_cbors - .into_iter() - .map(|x| { - let entry = - from_value::>(x).expect("expected designator array"); - match from_value(entry[0].clone()).expect("expected designator tag") { - 1 => Designator::Index( - from_value(entry[1].clone()).expect("expected array index"), - ), - 2 => Designator::Field(CDeclId( - from_value(entry[1].clone()).expect("expected field id"), - )), - 3 => Designator::Range( - from_value(entry[1].clone()).expect("expected array start"), - from_value(entry[2].clone()).expect("expected array end"), - ), - n => panic!("invalid designator tag: {}", n), - } - }) - .collect(); + let val_old = node.children[0].expect("Expected child on predefined expr"); + let val = self.visit_expr(val_old); - let init_id = node.children[0] - .expect("Expected initializer expression on designated init expr"); - let init_expr = self.visit_expr(init_id); + self.expr_possibly_as_stmt( + expected_ty, + new_id, + node, + CExprKind::Predefined(ty, val), + ) + } - let kind = CExprKind::DesignatedInitExpr(ty, designators, init_expr); + ASTEntryTag::TagImplicitValueInitExpr => { + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, kind) - } + self.expr_possibly_as_stmt( + expected_ty, + new_id, + node, + CExprKind::ImplicitValueInit(ty), + ) + } - ASTEntryTag::TagStmtExpr => { - let child_id = node.children[0].expect("Expected compound statement ID"); - let child = self.visit_stmt(child_id); + ASTEntryTag::TagInitListExpr => { + let exprs: Vec = node + .children + .iter() + .map(|id| { + let expr_id = id.expect("init expression id"); + self.visit_expr(expr_id) + }) + .collect(); + + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); + + let union_field_id = expect_opt_u64(&node.extras[0]) + .expect("Bad union field ID entry") + .map(|x| self.visit_decl(x)); + let syntax_id = expect_opt_u64(&node.extras[1]) + .expect("Bad syntax ID entry") + .map(|x| self.visit_expr(x)); + + let kind = CExprKind::InitList(ty, exprs, union_field_id, syntax_id); + self.expr_possibly_as_stmt(expected_ty, new_id, node, kind) + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagDesignatedInitExpr => { + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); + + let designator_cbors = from_value::>(node.extras[0].clone()) + .expect("Expected designators array"); + let designators = designator_cbors + .into_iter() + .map(|x| { + let entry = from_value::>(x).expect("expected designator array"); + match from_value(entry[0].clone()).expect("expected designator tag") { + 1 => Designator::Index( + from_value(entry[1].clone()).expect("expected array index"), + ), + 2 => Designator::Field(CDeclId( + from_value(entry[1].clone()).expect("expected field id"), + )), + 3 => Designator::Range( + from_value(entry[1].clone()).expect("expected array start"), + from_value(entry[2].clone()).expect("expected array end"), + ), + n => panic!("invalid designator tag: {}", n), + } + }) + .collect(); - let stmt_expr = CExprKind::Statements(ty, child); + let init_id = node.children[0] + .expect("Expected initializer expression on designated init expr"); + let init_expr = self.visit_expr(init_id); - self.expr_possibly_as_stmt(expected_ty, new_id, node, stmt_expr) - } + let kind = CExprKind::DesignatedInitExpr(ty, designators, init_expr); - ASTEntryTag::TagVAArgExpr => { - let child_id = node.children[0].expect("Expected subexpression"); - let child = self.visit_expr(child_id); + self.expr_possibly_as_stmt(expected_ty, new_id, node, kind) + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagStmtExpr => { + let child_id = node.children[0].expect("Expected compound statement ID"); + let child = self.visit_stmt(child_id); - let vaarg_expr = CExprKind::VAArg(ty, child); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, vaarg_expr) - } + let stmt_expr = CExprKind::Statements(ty, child); - ASTEntryTag::TagShuffleVectorExpr => { - let kids: Vec = node - .children - .iter() - .map(|id| { - let child_id = id.expect("Missing shuffle argument"); - self.visit_expr(child_id) - }) - .collect(); + self.expr_possibly_as_stmt(expected_ty, new_id, node, stmt_expr) + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagVAArgExpr => { + let child_id = node.children[0].expect("Expected subexpression"); + let child = self.visit_expr(child_id); - let e = CExprKind::ShuffleVector(ty, kids); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + let vaarg_expr = CExprKind::VAArg(ty, child); - ASTEntryTag::TagConvertVectorExpr => { - let kids: Vec = node - .children - .iter() - .map(|id| { - let child_id = id.expect("Missing convert argument"); - self.visit_expr(child_id) - }) - .collect(); + self.expr_possibly_as_stmt(expected_ty, new_id, node, vaarg_expr) + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagShuffleVectorExpr => { + let kids: Vec = node + .children + .iter() + .map(|id| { + let child_id = id.expect("Missing shuffle argument"); + self.visit_expr(child_id) + }) + .collect(); - let e = CExprKind::ConvertVector(ty, kids); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + let e = CExprKind::ShuffleVector(ty, kids); - ASTEntryTag::TagBuiltinBitCastExpr => { - let expression_old = node.children[0].expect("Expected expression for bitcast"); - let expression = self.visit_expr(expression_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let ty_old = node.type_id.expect("Expected type for bitcast"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagConvertVectorExpr => { + let kids: Vec = node + .children + .iter() + .map(|id| { + let child_id = id.expect("Missing convert argument"); + self.visit_expr(child_id) + }) + .collect(); - let e = CExprKind::ExplicitCast( - ty, - expression, - CastKind::BitCast, - None, - node.rvalue, - ); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + let e = CExprKind::ConvertVector(ty, kids); - ASTEntryTag::TagMaterializeTemporaryExpr => { - let expression_old = node.children[0] - .expect("Expected expression for materialize-temporary expr"); - let expression = self.visit_expr(expression_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let ty_old = node - .type_id - .expect("Expected type for materialize-temporary expr"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagBuiltinBitCastExpr => { + let expression_old = node.children[0].expect("Expected expression for bitcast"); + let expression = self.visit_expr(expression_old); - // C does not use this expression type (it has to do with C++ references), but - // it nonetheless shows up in some system SIMD intrinsic headers even when - // parsing as C. For now, just treat it as a trivial wrapper, i.e. parentheses. - let e = CExprKind::Paren(ty, expression); + let ty_old = node.type_id.expect("Expected type for bitcast"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + let e = + CExprKind::ExplicitCast(ty, expression, CastKind::BitCast, None, node.rvalue); - ASTEntryTag::TagExprWithCleanups => { - let expression_old = - node.children[0].expect("Expected expression for expr with cleanups"); - let expression = self.visit_expr(expression_old); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let ty_old = node.type_id.expect("Expected type for expr with cleanups"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagMaterializeTemporaryExpr => { + let expression_old = + node.children[0].expect("Expected expression for materialize-temporary expr"); + let expression = self.visit_expr(expression_old); - // C does not use this expression type, but it nonetheless shows up in some - // system SIMD intrinsic headers even when parsing as C. For now, just treat it - // as a trivial wrapper, i.e. parentheses. - let e = CExprKind::Paren(ty, expression); + let ty_old = node + .type_id + .expect("Expected type for materialize-temporary expr"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + // C does not use this expression type (it has to do with C++ references), but + // it nonetheless shows up in some system SIMD intrinsic headers even when + // parsing as C. For now, just treat it as a trivial wrapper, i.e. parentheses. + let e = CExprKind::Paren(ty, expression); - ASTEntryTag::TagConstantExpr => { - let expr = node.children[0].expect("Missing ConstantExpr subexpression"); - let expr = self.visit_expr(expr); - - let has_value = from_value(node.extras[0].clone()) - .expect("Case constant has_value not found"); - let cie = if has_value { - let is_signed = from_value(node.extras[1].clone()) - .expect("Case constant is_signed not found"); - Some(match is_signed { - false => ConstIntExpr::U( - from_value(node.extras[2].clone()) - .expect("Case constant not found"), - ), - true => ConstIntExpr::I( - from_value(node.extras[2].clone()) - .expect("Case constant not found"), - ), - }) - } else { - None - }; + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let ty_old = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty_old); + ASTEntryTag::TagExprWithCleanups => { + let expression_old = + node.children[0].expect("Expected expression for expr with cleanups"); + let expression = self.visit_expr(expression_old); - let e = CExprKind::ConstantExpr(ty, expr, cie); + let ty_old = node.type_id.expect("Expected type for expr with cleanups"); + let ty = self.visit_qualified_type(ty_old); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + // C does not use this expression type, but it nonetheless shows up in some + // system SIMD intrinsic headers even when parsing as C. For now, just treat it + // as a trivial wrapper, i.e. parentheses. + let e = CExprKind::Paren(ty, expression); - ASTEntryTag::TagChooseExpr => { - let condition = node.children[0].expect("ChooseExpr condition not found"); - let condition = self.visit_expr(condition); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let true_expr = node.children[1].expect("ChooseExpr true expression not found"); - let true_expr = self.visit_expr(true_expr); + ASTEntryTag::TagConstantExpr => { + let expr = node.children[0].expect("Missing ConstantExpr subexpression"); + let expr = self.visit_expr(expr); - let false_expr = - node.children[2].expect("ChooseExpr false expression not found"); - let false_expr = self.visit_expr(false_expr); + let has_value = + from_value(node.extras[0].clone()).expect("Case constant has_value not found"); + let cie = if has_value { + let is_signed = from_value(node.extras[1].clone()) + .expect("Case constant is_signed not found"); + Some(match is_signed { + false => ConstIntExpr::U( + from_value(node.extras[2].clone()).expect("Case constant not found"), + ), + true => ConstIntExpr::I( + from_value(node.extras[2].clone()).expect("Case constant not found"), + ), + }) + } else { + None + }; - let ty = node.type_id.expect("Expected expression to have type"); - let ty = self.visit_qualified_type(ty); + let ty_old = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty_old); - let condition_is_true = - from_value(node.extras[0].clone()).expect("Expected evaluated condition"); + let e = CExprKind::ConstantExpr(ty, expr, cie); - let e = - CExprKind::Choose(ty, condition, true_expr, false_expr, condition_is_true); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + ASTEntryTag::TagChooseExpr => { + let condition = node.children[0].expect("ChooseExpr condition not found"); + let condition = self.visit_expr(condition); - ASTEntryTag::TagAtomicExpr => { - let name = from_value::(node.extras[0].clone()) - .expect("Expected to find builtin operator name"); - - // The order of children is defined by Clang in class - // AtomicExpr - let mut children = node.children.iter(); - let ptr = self.visit_expr( - children - .next() - .unwrap() - .expect("Atomic must have a ptr argument"), - ); - let order = self.visit_expr( - children - .next() - .unwrap() - .expect("Atomic must have an order argument"), - ); - let val1 = children.next().map(|e| self.visit_expr(e.unwrap())); - let order_fail = children.next().map(|e| self.visit_expr(e.unwrap())); - let val2 = children.next().map(|e| self.visit_expr(e.unwrap())); - let weak = children.next().map(|e| self.visit_expr(e.unwrap())); - - let typ = node.type_id.expect("Expected expression to have type"); - let typ = self.visit_qualified_type(typ); - - // Perhaps as an optimization since atomic_init has no order, - // clang stores val1 in the position otherwise used for order - let is_atomic = name == "__c11_atomic_init" || name == "__opencl_atomic_init"; - let val1 = if is_atomic { Some(order) } else { val1 }; - - let e = CExprKind::Atomic { - typ, - name, - ptr, - order, - val1, - order_fail, - val2, - weak, - }; + let true_expr = node.children[1].expect("ChooseExpr true expression not found"); + let true_expr = self.visit_expr(true_expr); - self.expr_possibly_as_stmt(expected_ty, new_id, node, e) - } + let false_expr = node.children[2].expect("ChooseExpr false expression not found"); + let false_expr = self.visit_expr(false_expr); - // Declarations - ASTEntryTag::TagFunctionDecl if expected_ty & OTHER_DECL != 0 => { - let name = from_value::(node.extras[0].clone()) - .expect("Expected to find function name"); + let ty = node.type_id.expect("Expected expression to have type"); + let ty = self.visit_qualified_type(ty); - let is_global = - from_value(node.extras[1].clone()).expect("Expected to find visibility"); - let mut is_inline = - from_value(node.extras[2].clone()).expect("Expected to find inline"); + let condition_is_true = + from_value(node.extras[0].clone()).expect("Expected evaluated condition"); - let is_main = - from_value(node.extras[3].clone()).expect("Expected to find main"); - if is_main { - self.typed_context.c_main = Some(CDeclId(new_id)); - } + let e = CExprKind::Choose(ty, condition, true_expr, false_expr, condition_is_true); - let is_implicit = - from_value(node.extras[4].clone()).expect("Expected to find implicit"); - let is_extern = - from_value(node.extras[5].clone()).expect("Expected to find externness"); - let is_inline_externally_visible = from_value(node.extras[6].clone()) - .expect("Expected to find inline visibliity"); - let attributes = from_value::>(node.extras[7].clone()) - .expect("Expected to find attributes"); - let attrs = parse_attributes(attributes); - - // The always_inline attribute implies inline even if the - // inline keyword is not present. - is_inline |= attrs.contains(&Attribute::AlwaysInline); - - let typ_old = node - .type_id - .expect("Expected to find a type on a function decl"); - let typ = CTypeId(self.visit_node_type(typ_old, TYPE)); - - let (body_id, parameter_ids) = node - .children - .split_last() - .expect("Expected to find a function body"); - - let body = body_id.map(|b| self.visit_stmt(b)); - - let parameters = parameter_ids - .iter() - .map(|id| { - let param = id.expect("Param field decl not found"); - CDeclId(self.visit_node_type(param, VAR_DECL)) - }) - .collect(); + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - let function_decl = CDeclKind::Function { - attrs, - body, - is_extern, - is_global, - is_implicit, - is_inline, - is_inline_externally_visible, - name, - parameters, - typ, - }; + ASTEntryTag::TagAtomicExpr => { + let name = from_value::(node.extras[0].clone()) + .expect("Expected to find builtin operator name"); + + // The order of children is defined by Clang in class + // AtomicExpr + let mut children = node.children.iter(); + let ptr = self.visit_expr( + children + .next() + .unwrap() + .expect("Atomic must have a ptr argument"), + ); + let order = self.visit_expr( + children + .next() + .unwrap() + .expect("Atomic must have an order argument"), + ); + let val1 = children.next().map(|e| self.visit_expr(e.unwrap())); + let order_fail = children.next().map(|e| self.visit_expr(e.unwrap())); + let val2 = children.next().map(|e| self.visit_expr(e.unwrap())); + let weak = children.next().map(|e| self.visit_expr(e.unwrap())); + + let typ = node.type_id.expect("Expected expression to have type"); + let typ = self.visit_qualified_type(typ); + + // Perhaps as an optimization since atomic_init has no order, + // clang stores val1 in the position otherwise used for order + let is_atomic = name == "__c11_atomic_init" || name == "__opencl_atomic_init"; + let val1 = if is_atomic { Some(order) } else { val1 }; + + let e = CExprKind::Atomic { + typ, + name, + ptr, + order, + val1, + order_fail, + val2, + weak, + }; + + self.expr_possibly_as_stmt(expected_ty, new_id, node, e) + } - self.add_decl(new_id, located(node, function_decl)); - self.processed_nodes.insert(new_id, OTHER_DECL); - } + // Declarations + ASTEntryTag::TagFunctionDecl if expected_ty & OTHER_DECL != 0 => { + let name = from_value::(node.extras[0].clone()) + .expect("Expected to find function name"); + + let is_global = + from_value(node.extras[1].clone()).expect("Expected to find visibility"); + let mut is_inline = + from_value(node.extras[2].clone()).expect("Expected to find inline"); + + let is_main = from_value(node.extras[3].clone()).expect("Expected to find main"); + if is_main { + self.typed_context.c_main = Some(CDeclId(new_id)); + } + + let is_implicit = + from_value(node.extras[4].clone()).expect("Expected to find implicit"); + let is_extern = + from_value(node.extras[5].clone()).expect("Expected to find externness"); + let is_inline_externally_visible = + from_value(node.extras[6].clone()).expect("Expected to find inline visibliity"); + let attributes = from_value::>(node.extras[7].clone()) + .expect("Expected to find attributes"); + let attrs = parse_attributes(attributes); + + // The always_inline attribute implies inline even if the + // inline keyword is not present. + is_inline |= attrs.contains(&Attribute::AlwaysInline); + + let typ_old = node + .type_id + .expect("Expected to find a type on a function decl"); + let typ = CTypeId(self.visit_node_type(typ_old, TYPE)); + + let (body_id, parameter_ids) = node + .children + .split_last() + .expect("Expected to find a function body"); + + let body = body_id.map(|b| self.visit_stmt(b)); + + let parameters = parameter_ids + .iter() + .map(|id| { + let param = id.expect("Param field decl not found"); + CDeclId(self.visit_node_type(param, VAR_DECL)) + }) + .collect(); + + let function_decl = CDeclKind::Function { + attrs, + body, + is_extern, + is_global, + is_implicit, + is_inline, + is_inline_externally_visible, + name, + parameters, + typ, + }; + + self.add_decl(new_id, located(node, function_decl)); + self.processed_nodes.insert(new_id, OTHER_DECL); + } - ASTEntryTag::TagTypedefDecl if expected_ty & TYPDEF_DECL != 0 => { - let name = from_value::(node.extras[0].clone()) - .expect("Expected to find typedef name"); - let is_implicit = - from_value(node.extras[1].clone()).expect("Expected to find implicit"); - - let typ_old = node - .type_id - .expect("Expected to find type on typedef declaration"); - let mut typ = self.visit_qualified_type(typ_old); - - // Clang injects definitions of the form `#define __SIZE_TYPE__ unsigned int` into - // compilation units based on the target. (See lib/Frontend/InitPreprocessor.cpp - // in Clang). - // - // Later, headers contain defns like: `typedef __SIZE_TYPE__ size_t;` - // - // We detect these typedefs and alter them replacing the type to which the macro - // expands with a synthetic, portable `CTypeKind` chosen from the macro's name. - // - // This allows us to generate platform-independent Rust types like u64 or usize - // despite the C side internally working with a target-specific type. - let target_dependent_macro: Option = from_value(node.extras[2].clone()) - .expect("Expected to find optional target-dependent macro name"); - - typ = target_dependent_macro - .as_deref() - .and_then(|macro_name| { - let kind = match macro_name { - // Match names in the order Clang defines them. - "__INTMAX_TYPE__" => CTypeKind::IntMax, - "__UINTMAX_TYPE__" => CTypeKind::UIntMax, - "__PTRDIFF_TYPE__" => CTypeKind::PtrDiff, - "__INTPTR_TYPE__" => CTypeKind::IntPtr, - "__SIZE_TYPE__" => CTypeKind::Size, - "__WCHAR_TYPE__" => CTypeKind::WChar, - // __WINT_TYPE__ is defined by Clang but has no obvious translation - // __CHARn_TYPE__ for n ∈ {8, 16, 32} also lack obvious translation - "__UINTPTR_TYPE__" => CTypeKind::UIntPtr, - _ => { - log::debug!("Unknown target-dependent macro {macro_name}!"); - return None; - } - }; - log::trace!("Selected kind {kind} for typedef {name}"); - Some(CQualTypeId::new( - self.typed_context.type_for_kind(&kind).unwrap(), - )) - }) - .unwrap_or(typ); - - // Other fixed-size types are defined without special compiler involvement, by - // standard headers and their transitive includes. In these contexts, we - // recognize these typedefs by the name of the typedef type. - let id_for_name = |name| -> Option<_> { - let kind = match name { - "intmax_t" => CTypeKind::IntMax, - "uintmax_t" => CTypeKind::UIntMax, - "intptr_t" => CTypeKind::IntPtr, - "uintptr_t" => CTypeKind::UIntPtr, - // unlike `size_t`, `ssize_t` does not have a clang-provided `#define`. - "ssize_t" => CTypeKind::SSize, - // macOS defines `ssize_t` from `__darwin_ssize_t` in many headers, - // so we should handle `__darwin_ssize_t` itself. - "__darwin_ssize_t" => CTypeKind::SSize, - "__uint8_t" => CTypeKind::UInt8, - "__uint16_t" => CTypeKind::UInt16, - "__uint32_t" => CTypeKind::UInt32, - "__uint64_t" => CTypeKind::UInt64, - "__uint128_t" => CTypeKind::UInt128, - "__int8_t" => CTypeKind::Int8, - "__int16_t" => CTypeKind::Int16, - "__int32_t" => CTypeKind::Int32, - "__int64_t" => CTypeKind::Int64, - "__int128_t" => CTypeKind::Int128, - // macOS stdint.h typedefs [u]intN_t directly: - "int8_t" => CTypeKind::Int8, - "int16_t" => CTypeKind::Int16, - "int32_t" => CTypeKind::Int32, - "int64_t" => CTypeKind::Int64, - "uint8_t" => CTypeKind::UInt8, - "uint16_t" => CTypeKind::UInt16, - "uint32_t" => CTypeKind::UInt32, - "uint64_t" => CTypeKind::UInt64, + ASTEntryTag::TagTypedefDecl if expected_ty & TYPDEF_DECL != 0 => { + let name = from_value::(node.extras[0].clone()) + .expect("Expected to find typedef name"); + let is_implicit = + from_value(node.extras[1].clone()).expect("Expected to find implicit"); + + let typ_old = node + .type_id + .expect("Expected to find type on typedef declaration"); + let mut typ = self.visit_qualified_type(typ_old); + + // Clang injects definitions of the form `#define __SIZE_TYPE__ unsigned int` into + // compilation units based on the target. (See lib/Frontend/InitPreprocessor.cpp + // in Clang). + // + // Later, headers contain defns like: `typedef __SIZE_TYPE__ size_t;` + // + // We detect these typedefs and alter them replacing the type to which the macro + // expands with a synthetic, portable `CTypeKind` chosen from the macro's name. + // + // This allows us to generate platform-independent Rust types like u64 or usize + // despite the C side internally working with a target-specific type. + let target_dependent_macro: Option = from_value(node.extras[2].clone()) + .expect("Expected to find optional target-dependent macro name"); + + typ = target_dependent_macro + .as_deref() + .and_then(|macro_name| { + let kind = match macro_name { + // Match names in the order Clang defines them. + "__INTMAX_TYPE__" => CTypeKind::IntMax, + "__UINTMAX_TYPE__" => CTypeKind::UIntMax, + "__PTRDIFF_TYPE__" => CTypeKind::PtrDiff, + "__INTPTR_TYPE__" => CTypeKind::IntPtr, + "__SIZE_TYPE__" => CTypeKind::Size, + "__WCHAR_TYPE__" => CTypeKind::WChar, + // __WINT_TYPE__ is defined by Clang but has no obvious translation + // __CHARn_TYPE__ for n ∈ {8, 16, 32} also lack obvious translation + "__UINTPTR_TYPE__" => CTypeKind::UIntPtr, _ => { - log::debug!("Unknown fixed-size type typedef {name}!"); + log::debug!("Unknown target-dependent macro {macro_name}!"); return None; } }; @@ -2122,15 +2066,60 @@ impl ConversionContext { Some(CQualTypeId::new( self.typed_context.type_for_kind(&kind).unwrap(), )) + }) + .unwrap_or(typ); + + // Other fixed-size types are defined without special compiler involvement, by + // standard headers and their transitive includes. In these contexts, we + // recognize these typedefs by the name of the typedef type. + let id_for_name = |name| -> Option<_> { + let kind = match name { + "intmax_t" => CTypeKind::IntMax, + "uintmax_t" => CTypeKind::UIntMax, + "intptr_t" => CTypeKind::IntPtr, + "uintptr_t" => CTypeKind::UIntPtr, + // unlike `size_t`, `ssize_t` does not have a clang-provided `#define`. + "ssize_t" => CTypeKind::SSize, + // macOS defines `ssize_t` from `__darwin_ssize_t` in many headers, + // so we should handle `__darwin_ssize_t` itself. + "__darwin_ssize_t" => CTypeKind::SSize, + "__uint8_t" => CTypeKind::UInt8, + "__uint16_t" => CTypeKind::UInt16, + "__uint32_t" => CTypeKind::UInt32, + "__uint64_t" => CTypeKind::UInt64, + "__uint128_t" => CTypeKind::UInt128, + "__int8_t" => CTypeKind::Int8, + "__int16_t" => CTypeKind::Int16, + "__int32_t" => CTypeKind::Int32, + "__int64_t" => CTypeKind::Int64, + "__int128_t" => CTypeKind::Int128, + // macOS stdint.h typedefs [u]intN_t directly: + "int8_t" => CTypeKind::Int8, + "int16_t" => CTypeKind::Int16, + "int32_t" => CTypeKind::Int32, + "int64_t" => CTypeKind::Int64, + "uint8_t" => CTypeKind::UInt8, + "uint16_t" => CTypeKind::UInt16, + "uint32_t" => CTypeKind::UInt32, + "uint64_t" => CTypeKind::UInt64, + _ => { + log::debug!("Unknown fixed-size type typedef {name}!"); + return None; + } }; - let file = self - .typed_context - .files - .get(self.typed_context.file_map[node.loc.fileid as usize]); - let file = file.unwrap(); - if let Some(path) = file.path.as_ref() { - if let Some(filename) = path.file_name() { - if filename == "stdint.h" + log::trace!("Selected kind {kind} for typedef {name}"); + Some(CQualTypeId::new( + self.typed_context.type_for_kind(&kind).unwrap(), + )) + }; + let file = self + .typed_context + .files + .get(self.typed_context.file_map[node.loc.fileid as usize]); + let file = file.unwrap(); + if let Some(path) = file.path.as_ref() { + if let Some(filename) = path.file_name() { + if filename == "stdint.h" || filename == "types.h" || filename .to_str() @@ -2142,300 +2131,297 @@ impl ConversionContext { .to_str() .map(|s| s.starts_with("_int") || s.starts_with("_uint")) .unwrap_or(false) - { - typ = id_for_name(&*name).unwrap_or(typ); - } + { + typ = id_for_name(&*name).unwrap_or(typ); } } - - let typdef_decl = CDeclKind::Typedef { - name, - typ, - is_implicit, - target_dependent_macro, - }; - - self.add_decl(new_id, located(node, typdef_decl)); - self.processed_nodes.insert(new_id, TYPDEF_DECL); } - ASTEntryTag::TagEnumDecl if expected_ty & ENUM_DECL != 0 => { - let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); - - let variants = node - .children - .iter() - .map(|id| { - let con = id.expect("Enum constant not found"); - let id = CDeclId(self.visit_node_type(con, ENUM_CON)); - self.typed_context.parents.insert(id, CDeclId(new_id)); - id - }) - .collect(); - - let integral_type = node.type_id.map(|x| self.visit_qualified_type(x)); - - let enum_decl = CDeclKind::Enum { - name, - variants, - integral_type, - }; - - self.add_decl(new_id, located(node, enum_decl)); - self.processed_nodes.insert(new_id, ENUM_DECL); - } - - ASTEntryTag::TagEnumConstantDecl if expected_ty & ENUM_CON != 0 => { - let name = from_value::(node.extras[0].clone()) - .expect("Expected to find enum constant name"); - let is_signed = from_value(node.extras[1].clone()) - .expect("Enum constant signedness not found"); - let value = match is_signed { - false => ConstIntExpr::U( - from_value(node.extras[2].clone()).expect("Enum constant not found"), - ), - true => ConstIntExpr::I( - from_value(node.extras[2].clone()).expect("Enum constant not found"), - ), - }; + let typdef_decl = CDeclKind::Typedef { + name, + typ, + is_implicit, + target_dependent_macro, + }; - let enum_constant_decl = CDeclKind::EnumConstant { name, value }; + self.add_decl(new_id, located(node, typdef_decl)); + self.processed_nodes.insert(new_id, TYPDEF_DECL); + } - self.add_decl(new_id, located(node, enum_constant_decl)); - self.processed_nodes.insert(new_id, ENUM_CON); - } + ASTEntryTag::TagEnumDecl if expected_ty & ENUM_DECL != 0 => { + let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); + + let variants = node + .children + .iter() + .map(|id| { + let con = id.expect("Enum constant not found"); + let id = CDeclId(self.visit_node_type(con, ENUM_CON)); + self.typed_context.parents.insert(id, CDeclId(new_id)); + id + }) + .collect(); + + let integral_type = node.type_id.map(|x| self.visit_qualified_type(x)); + + let enum_decl = CDeclKind::Enum { + name, + variants, + integral_type, + }; + + self.add_decl(new_id, located(node, enum_decl)); + self.processed_nodes.insert(new_id, ENUM_DECL); + } - ASTEntryTag::TagVarDecl if expected_ty & VAR_DECL != 0 => { - let ident = from_value::(node.extras[0].clone()) - .expect("Expected to find variable name"); - - let has_static_duration = from_value(node.extras[1].clone()) - .expect("Expected to find static duration"); - let has_thread_duration = from_value(node.extras[2].clone()) - .expect("Expected to find thread duration"); - let is_externally_visible = from_value::(node.extras[3].clone()) - .expect("Expected to find visibility"); - let is_defn = from_value(node.extras[4].clone()) - .expect("Expected to find whether decl is definition"); - let attributes = from_value::>(node.extras[5].clone()) - .expect("Expected attribute array on var decl"); - - assert!( - has_static_duration || has_thread_duration || !is_externally_visible, - "Variable cannot be extern without also being static or thread-local: {}", - ident - ); + ASTEntryTag::TagEnumConstantDecl if expected_ty & ENUM_CON != 0 => { + let name = from_value::(node.extras[0].clone()) + .expect("Expected to find enum constant name"); + let is_signed = + from_value(node.extras[1].clone()).expect("Enum constant signedness not found"); + let value = match is_signed { + false => ConstIntExpr::U( + from_value(node.extras[2].clone()).expect("Enum constant not found"), + ), + true => ConstIntExpr::I( + from_value(node.extras[2].clone()).expect("Enum constant not found"), + ), + }; - let initializer = node - .children - .first() - .into_iter() - .flatten() - .map(|id| self.visit_expr(*id)) - .next(); - - let typ_id = node - .type_id - .expect("Expected to find type on variable declaration"); - let typ = self.visit_qualified_type(typ_id); - - let attrs = parse_attributes(attributes); - - let variable_decl = CDeclKind::Variable { - has_static_duration, - has_thread_duration, - is_externally_visible, - is_defn, - ident, - initializer, - typ, - attrs, - }; + let enum_constant_decl = CDeclKind::EnumConstant { name, value }; - self.add_decl(new_id, located(node, variable_decl)); - self.processed_nodes.insert(new_id, VAR_DECL); - } + self.add_decl(new_id, located(node, enum_constant_decl)); + self.processed_nodes.insert(new_id, ENUM_CON); + } - ASTEntryTag::TagStructDecl if expected_ty & RECORD_DECL != 0 => { - let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); - let has_def = from_value(node.extras[1].clone()) - .expect("Expected has_def flag on struct"); - let attrs = from_value::>(node.extras[2].clone()) - .expect("Expected attribute array on record"); - let manual_alignment = - expect_opt_u64(&node.extras[3]).expect("Expected struct alignment"); - let max_field_alignment = - expect_opt_u64(&node.extras[4]).expect("Expected struct field align"); - let platform_byte_size = - from_value(node.extras[5].clone()).expect("Expected struct size"); - let platform_alignment = - from_value(node.extras[6].clone()).expect("Expected struct alignment"); - - let fields: Option> = if has_def { - Some( - self.visit_record_children(untyped_context, node, new_id) - .collect(), - ) - } else { - None - }; + ASTEntryTag::TagVarDecl if expected_ty & VAR_DECL != 0 => { + let ident = from_value::(node.extras[0].clone()) + .expect("Expected to find variable name"); + + let has_static_duration = + from_value(node.extras[1].clone()).expect("Expected to find static duration"); + let has_thread_duration = + from_value(node.extras[2].clone()).expect("Expected to find thread duration"); + let is_externally_visible = from_value::(node.extras[3].clone()) + .expect("Expected to find visibility"); + let is_defn = from_value(node.extras[4].clone()) + .expect("Expected to find whether decl is definition"); + let attributes = from_value::>(node.extras[5].clone()) + .expect("Expected attribute array on var decl"); - let is_packed = has_packed_attribute(attrs); + assert!( + has_static_duration || has_thread_duration || !is_externally_visible, + "Variable cannot be extern without also being static or thread-local: {}", + ident + ); - let record = CDeclKind::Struct { - name, - fields, - is_packed, - manual_alignment, - max_field_alignment, - platform_byte_size, - platform_alignment, - }; + let initializer = node + .children + .first() + .into_iter() + .flatten() + .map(|id| self.visit_expr(*id)) + .next(); + + let typ_id = node + .type_id + .expect("Expected to find type on variable declaration"); + let typ = self.visit_qualified_type(typ_id); + + let attrs = parse_attributes(attributes); + + let variable_decl = CDeclKind::Variable { + has_static_duration, + has_thread_duration, + is_externally_visible, + is_defn, + ident, + initializer, + typ, + attrs, + }; + + self.add_decl(new_id, located(node, variable_decl)); + self.processed_nodes.insert(new_id, VAR_DECL); + } - self.add_decl(new_id, located(node, record)); - self.processed_nodes.insert(new_id, RECORD_DECL); - } + ASTEntryTag::TagStructDecl if expected_ty & RECORD_DECL != 0 => { + let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); + let has_def = + from_value(node.extras[1].clone()).expect("Expected has_def flag on struct"); + let attrs = from_value::>(node.extras[2].clone()) + .expect("Expected attribute array on record"); + let manual_alignment = + expect_opt_u64(&node.extras[3]).expect("Expected struct alignment"); + let max_field_alignment = + expect_opt_u64(&node.extras[4]).expect("Expected struct field align"); + let platform_byte_size = + from_value(node.extras[5].clone()).expect("Expected struct size"); + let platform_alignment = + from_value(node.extras[6].clone()).expect("Expected struct alignment"); + + let fields: Option> = if has_def { + Some( + self.visit_record_children(untyped_context, node, new_id) + .collect(), + ) + } else { + None + }; + + let is_packed = has_packed_attribute(attrs); + + let record = CDeclKind::Struct { + name, + fields, + is_packed, + manual_alignment, + max_field_alignment, + platform_byte_size, + platform_alignment, + }; + + self.add_decl(new_id, located(node, record)); + self.processed_nodes.insert(new_id, RECORD_DECL); + } - ASTEntryTag::TagUnionDecl if expected_ty & RECORD_DECL != 0 => { - let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); - let has_def = from_value(node.extras[1].clone()) - .expect("Expected has_def flag on struct"); - let attrs = from_value::>(node.extras[2].clone()) - .expect("Expected attribute array on record"); - let fields: Option> = if has_def { - Some( - self.visit_record_children(untyped_context, node, new_id) - .collect(), - ) - } else { - None - }; + ASTEntryTag::TagUnionDecl if expected_ty & RECORD_DECL != 0 => { + let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string); + let has_def = + from_value(node.extras[1].clone()).expect("Expected has_def flag on struct"); + let attrs = from_value::>(node.extras[2].clone()) + .expect("Expected attribute array on record"); + let fields: Option> = if has_def { + Some( + self.visit_record_children(untyped_context, node, new_id) + .collect(), + ) + } else { + None + }; - let is_packed = has_packed_attribute(attrs); + let is_packed = has_packed_attribute(attrs); - let record = CDeclKind::Union { - name, - fields, - is_packed, - }; + let record = CDeclKind::Union { + name, + fields, + is_packed, + }; - self.add_decl(new_id, located(node, record)); - self.processed_nodes.insert(new_id, RECORD_DECL); - } + self.add_decl(new_id, located(node, record)); + self.processed_nodes.insert(new_id, RECORD_DECL); + } - ASTEntryTag::TagFieldDecl if expected_ty & FIELD_DECL != 0 => { - let name = - from_value::(node.extras[0].clone()).expect("A field needs a name"); - let typ_id = node - .type_id - .expect("Expected to find type on field declaration"); - let typ = self.visit_qualified_type(typ_id); - let bitfield_width = from_value(node.extras[1].clone()).ok(); - let platform_bit_offset = - from_value(node.extras[2].clone()).expect("Did not find field bit offset"); - let platform_type_bitwidth = - from_value(node.extras[3].clone()).expect("Did not find field bitwidth"); - let field = CDeclKind::Field { - name, - typ, - bitfield_width, - platform_bit_offset, - platform_type_bitwidth, - }; - self.add_decl(new_id, located(node, field)); - self.processed_nodes.insert(new_id, FIELD_DECL); - } + ASTEntryTag::TagFieldDecl if expected_ty & FIELD_DECL != 0 => { + let name = + from_value::(node.extras[0].clone()).expect("A field needs a name"); + let typ_id = node + .type_id + .expect("Expected to find type on field declaration"); + let typ = self.visit_qualified_type(typ_id); + let bitfield_width = from_value(node.extras[1].clone()).ok(); + let platform_bit_offset = + from_value(node.extras[2].clone()).expect("Did not find field bit offset"); + let platform_type_bitwidth = + from_value(node.extras[3].clone()).expect("Did not find field bitwidth"); + let field = CDeclKind::Field { + name, + typ, + bitfield_width, + platform_bit_offset, + platform_type_bitwidth, + }; + self.add_decl(new_id, located(node, field)); + self.processed_nodes.insert(new_id, FIELD_DECL); + } - ASTEntryTag::TagMacroObjectDef | ASTEntryTag::TagMacroFunctionDef - if expected_ty & MACRO_DECL != 0 => - { - let name = from_value::(node.extras[0].clone()) - .expect("Macros must have a name"); + ASTEntryTag::TagMacroObjectDef | ASTEntryTag::TagMacroFunctionDef + if expected_ty & MACRO_DECL != 0 => + { + let name = + from_value::(node.extras[0].clone()).expect("Macros must have a name"); - let mac_object = match node.tag { - ASTEntryTag::TagMacroObjectDef => CDeclKind::MacroObject { name }, - ASTEntryTag::TagMacroFunctionDef => CDeclKind::MacroFunction { name }, - _ => unreachable!("Unexpected tag for macro"), - }; + let mac_object = match node.tag { + ASTEntryTag::TagMacroObjectDef => CDeclKind::MacroObject { name }, + ASTEntryTag::TagMacroFunctionDef => CDeclKind::MacroFunction { name }, + _ => unreachable!("Unexpected tag for macro"), + }; - self.add_decl(new_id, located(node, mac_object)); - self.processed_nodes.insert(new_id, MACRO_DECL); + self.add_decl(new_id, located(node, mac_object)); + self.processed_nodes.insert(new_id, MACRO_DECL); - // Macros aren't technically top-level decls, so clang - // doesn't put them in top_nodes, but we do need to process - // them early. - self.typed_context.c_decls_top.push(CDeclId(new_id)); - } + // Macros aren't technically top-level decls, so clang + // doesn't put them in top_nodes, but we do need to process + // them early. + self.typed_context.c_decls_top.push(CDeclId(new_id)); + } - ASTEntryTag::TagMacroFunctionDef if expected_ty & MACRO_DECL != 0 => { - let name = from_value::(node.extras[0].clone()) - .expect("Macros must have a name"); + ASTEntryTag::TagMacroFunctionDef if expected_ty & MACRO_DECL != 0 => { + let name = + from_value::(node.extras[0].clone()).expect("Macros must have a name"); - let mac_object = CDeclKind::MacroFunction { name }; - self.add_decl(new_id, located(node, mac_object)); - self.processed_nodes.insert(new_id, MACRO_DECL); + let mac_object = CDeclKind::MacroFunction { name }; + self.add_decl(new_id, located(node, mac_object)); + self.processed_nodes.insert(new_id, MACRO_DECL); - // Macros aren't technically top-level decls, so clang - // doesn't put them in top_nodes, but we do need to process - // them early. - self.typed_context.c_decls_top.push(CDeclId(new_id)); - } + // Macros aren't technically top-level decls, so clang + // doesn't put them in top_nodes, but we do need to process + // them early. + self.typed_context.c_decls_top.push(CDeclId(new_id)); + } - ASTEntryTag::TagNonCanonicalDecl if expected_ty & DECL != 0 => { - let canonical_decl = - node.children[0].expect("NonCanonicalDecl must point to a canonical decl"); - let canonical_decl = self.visit_decl(canonical_decl); - let record = CDeclKind::NonCanonicalDecl { canonical_decl }; - - self.add_decl(new_id, located(node, record)); - self.processed_nodes.insert(new_id, OTHER_DECL); - - // Look up the canonical declaration and see if it declares a - // struct. If so, check attributes of the non-canonical declaration - // and potentially update its `is_packed` property. - if let Some(v) = self.typed_context.c_decls.get_mut(&canonical_decl) { - match &mut v.kind { - CDeclKind::Struct { is_packed, .. } - | CDeclKind::Union { is_packed, .. } => { - let attrs = from_value::>(node.extras[0].clone()) - .expect( - "Expected attribute array on non-canonical record decl", - ); - - *is_packed = has_packed_attribute(attrs); - } - _ => {} + ASTEntryTag::TagNonCanonicalDecl if expected_ty & DECL != 0 => { + let canonical_decl = + node.children[0].expect("NonCanonicalDecl must point to a canonical decl"); + let canonical_decl = self.visit_decl(canonical_decl); + let record = CDeclKind::NonCanonicalDecl { canonical_decl }; + + self.add_decl(new_id, located(node, record)); + self.processed_nodes.insert(new_id, OTHER_DECL); + + // Look up the canonical declaration and see if it declares a + // struct. If so, check attributes of the non-canonical declaration + // and potentially update its `is_packed` property. + if let Some(v) = self.typed_context.c_decls.get_mut(&canonical_decl) { + match &mut v.kind { + CDeclKind::Struct { is_packed, .. } + | CDeclKind::Union { is_packed, .. } => { + let attrs = from_value::>(node.extras[0].clone()) + .expect("Expected attribute array on non-canonical record decl"); + + *is_packed = has_packed_attribute(attrs); } + _ => {} } } + } - ASTEntryTag::TagStaticAssertDecl if expected_ty & DECL != 0 => { - let assert_expr = - node.children[0].expect("StaticAssert must point to an expression"); - let assert_expr = self.visit_expr(assert_expr); - - let message = if node.children.len() > 1 { - let message = node.children[1].expect("Expected static assert message"); - let message = untyped_context - .ast_nodes - .get(&message) - .expect("Expected string literal node"); - let message = from_value::(message.extras[2].clone()) - .expect("string literal bytes"); - Some(message) - } else { - None - }; - let static_assert = CDeclKind::StaticAssert { - assert_expr, - message, - }; - self.add_decl(new_id, located(node, static_assert)); - self.processed_nodes.insert(new_id, OTHER_DECL); - } - - t => panic!("Could not translate node {:?} as type {}", t, expected_ty), + ASTEntryTag::TagStaticAssertDecl if expected_ty & DECL != 0 => { + let assert_expr = + node.children[0].expect("StaticAssert must point to an expression"); + let assert_expr = self.visit_expr(assert_expr); + + let message = if node.children.len() > 1 { + let message = node.children[1].expect("Expected static assert message"); + let message = untyped_context + .ast_nodes + .get(&message) + .expect("Expected string literal node"); + let message = from_value::(message.extras[2].clone()) + .expect("string literal bytes"); + Some(message) + } else { + None + }; + let static_assert = CDeclKind::StaticAssert { + assert_expr, + message, + }; + self.add_decl(new_id, located(node, static_assert)); + self.processed_nodes.insert(new_id, OTHER_DECL); } + + t => panic!("Could not translate node {:?} as type {}", t, expected_ty), } } }