Skip to content

Commit 067aa23

Browse files
committed
transpile: Move bubble_expr_types to conversion.rs
1 parent acdb02a commit 067aa23

3 files changed

Lines changed: 114 additions & 113 deletions

File tree

c2rust-transpile/src/c_ast/conversion.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::c_ast::c_expr::{
55
};
66
use crate::c_ast::c_stmt::{AsmOperand, CStmt, CStmtId, CStmtKind};
77
use crate::c_ast::c_type::{CQualTypeId, CType, CTypeId, CTypeKind, Qualifiers};
8+
use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor, SomeId};
89
use crate::c_ast::{Attribute, DisplaySrcSpan, TypedAstContext};
910
use crate::diagnostics::diag;
1011
use c2rust_ast_exporter::clang_ast::*;
@@ -564,6 +565,116 @@ impl ConversionContext {
564565

565566
self.typed_context.va_list_kind = untyped_context.va_list_kind;
566567
self.typed_context.target = untyped_context.target.clone();
568+
569+
self.bubble_expr_types();
570+
}
571+
572+
/// Bubble types of unary and binary operators up from their args into the expression type.
573+
///
574+
/// In Clang 15 and below, the Clang AST resolves typedefs in the expression type of unary and
575+
/// binary expressions. For example, a BinaryExpr node adding two `size_t` expressions will be
576+
/// given an `unsigned long` type rather than the `size_t` typedef type. This behavior changed
577+
/// in Clang 16. This method adjusts AST node types to match those produced by Clang 16 and
578+
/// newer; on these later Clang versions, it should have no effect.
579+
///
580+
/// This pass is necessary because we reify some typedef types (such as `size_t`) into their own
581+
/// distinct Rust types. As such, we need to make sure we know the exact type to generate when
582+
/// we translate an expr, not just its resolved type (looking through typedefs).
583+
fn bubble_expr_types(&mut self) {
584+
struct BubbleExprTypes<'a> {
585+
ast_context: &'a mut TypedAstContext,
586+
}
587+
588+
impl<'a> NodeVisitor for BubbleExprTypes<'a> {
589+
fn children(&mut self, id: SomeId) -> Vec<SomeId> {
590+
immediate_children_all_types(self.ast_context, id)
591+
}
592+
593+
fn post(&mut self, id: SomeId) {
594+
let e = match id {
595+
SomeId::Expr(e) => e,
596+
_ => return,
597+
};
598+
599+
let new_ty = match self.ast_context.c_exprs[&e].kind {
600+
CExprKind::Conditional(_ty, _cond, lhs, rhs) => {
601+
let lhs_type_id =
602+
self.ast_context.c_exprs[&lhs].kind.get_qual_type().unwrap();
603+
let rhs_type_id =
604+
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();
605+
606+
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
607+
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
608+
609+
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
610+
Some(lhs_type_id)
611+
} else if CTypeKind::PULLBACK_KINDS.contains(&rhs_resolved_ty.kind) {
612+
Some(rhs_type_id)
613+
} else {
614+
None
615+
}
616+
}
617+
CExprKind::Binary(_ty, op, lhs, rhs, _, _) => {
618+
let rhs_type_id =
619+
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();
620+
let lhs_kind = &self.ast_context.c_exprs[&lhs].kind;
621+
let lhs_type_id = lhs_kind.get_qual_type().unwrap();
622+
623+
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
624+
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
625+
626+
let neither_ptr = !lhs_resolved_ty.kind.is_pointer()
627+
&& !rhs_resolved_ty.kind.is_pointer();
628+
629+
if op.all_types_same() && neither_ptr {
630+
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
631+
Some(lhs_type_id)
632+
} else {
633+
Some(rhs_type_id)
634+
}
635+
} else if op == BinOp::ShiftLeft || op == BinOp::ShiftRight {
636+
Some(lhs_type_id)
637+
} else {
638+
return;
639+
}
640+
}
641+
CExprKind::Unary(_ty, op, e, _idk) => op.expected_result_type(
642+
self.ast_context,
643+
self.ast_context.c_exprs[&e].kind.get_qual_type().unwrap(),
644+
),
645+
CExprKind::Paren(_ty, e) => self.ast_context.c_exprs[&e].kind.get_qual_type(),
646+
CExprKind::UnaryType(_, op, _, _) => {
647+
// All of these `UnTypeOp`s should return `size_t`.
648+
let kind = match op {
649+
UnTypeOp::SizeOf => CTypeKind::Size,
650+
UnTypeOp::AlignOf => CTypeKind::Size,
651+
UnTypeOp::PreferredAlignOf => CTypeKind::Size,
652+
};
653+
let ty = self
654+
.ast_context
655+
.type_for_kind(&kind)
656+
.expect("CTypeKind::Size should be size_t");
657+
Some(CQualTypeId::new(ty))
658+
}
659+
_ => return,
660+
};
661+
let ty = self
662+
.ast_context
663+
.c_exprs
664+
.get_mut(&e)
665+
.and_then(|e| e.kind.get_qual_type_mut());
666+
if let (Some(ty), Some(new_ty)) = (ty, new_ty) {
667+
*ty = new_ty;
668+
};
669+
}
670+
}
671+
672+
for decl in self.typed_context.c_decls_top.clone() {
673+
BubbleExprTypes {
674+
ast_context: &mut self.typed_context,
675+
}
676+
.visit_tree(SomeId::Decl(decl));
677+
}
567678
}
568679

569680
/// Visit child nodes of a `RecordDecl` (`struct` or `union`) and collect `FieldDecl` node IDs.

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 3 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::c_ast::c_decl::{CDecl, CDeclId, CDeclKind};
2-
use crate::c_ast::c_expr::{BinOp, CExpr, CExprId, CExprKind, UnTypeOp};
2+
use crate::c_ast::c_expr::{CExpr, CExprId, CExprKind};
33
use crate::c_ast::c_stmt::{CLabelId, CStmt, CStmtId};
4-
use crate::c_ast::c_type::{CQualTypeId, CType, CTypeId, CTypeKind};
5-
use crate::c_ast::iterators::{immediate_children_all_types, DFNodes, NodeVisitor, SomeId};
4+
use crate::c_ast::c_type::{CType, CTypeId, CTypeKind};
5+
use crate::c_ast::iterators::{DFNodes, SomeId};
66
use indexmap::IndexMap;
77
use itertools::Itertools;
88
use std::cell::RefCell;
@@ -435,111 +435,6 @@ impl TypedAstContext {
435435
self.c_decls_top.retain(|x| wanted.contains(x));
436436
}
437437

438-
/// Bubble types of unary and binary operators up from their args into the expression type.
439-
///
440-
/// In Clang 15 and below, the Clang AST resolves typedefs in the expression type of unary and
441-
/// binary expressions. For example, a BinaryExpr node adding two `size_t` expressions will be
442-
/// given an `unsigned long` type rather than the `size_t` typedef type. This behavior changed
443-
/// in Clang 16. This method adjusts AST node types to match those produced by Clang 16 and
444-
/// newer; on these later Clang versions, it should have no effect.
445-
///
446-
/// This pass is necessary because we reify some typedef types (such as `size_t`) into their own
447-
/// distinct Rust types. As such, we need to make sure we know the exact type to generate when
448-
/// we translate an expr, not just its resolved type (looking through typedefs).
449-
pub fn bubble_expr_types(&mut self) {
450-
struct BubbleExprTypes<'a> {
451-
ast_context: &'a mut TypedAstContext,
452-
}
453-
454-
impl<'a> NodeVisitor for BubbleExprTypes<'a> {
455-
fn children(&mut self, id: SomeId) -> Vec<SomeId> {
456-
immediate_children_all_types(self.ast_context, id)
457-
}
458-
459-
fn post(&mut self, id: SomeId) {
460-
let e = match id {
461-
SomeId::Expr(e) => e,
462-
_ => return,
463-
};
464-
465-
let new_ty = match self.ast_context.c_exprs[&e].kind {
466-
CExprKind::Conditional(_ty, _cond, lhs, rhs) => {
467-
let lhs_type_id =
468-
self.ast_context.c_exprs[&lhs].kind.get_qual_type().unwrap();
469-
let rhs_type_id =
470-
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();
471-
472-
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
473-
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
474-
475-
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
476-
Some(lhs_type_id)
477-
} else if CTypeKind::PULLBACK_KINDS.contains(&rhs_resolved_ty.kind) {
478-
Some(rhs_type_id)
479-
} else {
480-
None
481-
}
482-
}
483-
CExprKind::Binary(_ty, op, lhs, rhs, _, _) => {
484-
let rhs_type_id =
485-
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();
486-
let lhs_kind = &self.ast_context.c_exprs[&lhs].kind;
487-
let lhs_type_id = lhs_kind.get_qual_type().unwrap();
488-
489-
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
490-
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
491-
492-
let neither_ptr = !lhs_resolved_ty.kind.is_pointer()
493-
&& !rhs_resolved_ty.kind.is_pointer();
494-
495-
if op.all_types_same() && neither_ptr {
496-
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
497-
Some(lhs_type_id)
498-
} else {
499-
Some(rhs_type_id)
500-
}
501-
} else if op == BinOp::ShiftLeft || op == BinOp::ShiftRight {
502-
Some(lhs_type_id)
503-
} else {
504-
return;
505-
}
506-
}
507-
CExprKind::Unary(_ty, op, e, _idk) => op.expected_result_type(
508-
self.ast_context,
509-
self.ast_context.c_exprs[&e].kind.get_qual_type().unwrap(),
510-
),
511-
CExprKind::Paren(_ty, e) => self.ast_context.c_exprs[&e].kind.get_qual_type(),
512-
CExprKind::UnaryType(_, op, _, _) => {
513-
// All of these `UnTypeOp`s should return `size_t`.
514-
let kind = match op {
515-
UnTypeOp::SizeOf => CTypeKind::Size,
516-
UnTypeOp::AlignOf => CTypeKind::Size,
517-
UnTypeOp::PreferredAlignOf => CTypeKind::Size,
518-
};
519-
let ty = self
520-
.ast_context
521-
.type_for_kind(&kind)
522-
.expect("CTypeKind::Size should be size_t");
523-
Some(CQualTypeId::new(ty))
524-
}
525-
_ => return,
526-
};
527-
let ty = self
528-
.ast_context
529-
.c_exprs
530-
.get_mut(&e)
531-
.and_then(|e| e.kind.get_qual_type_mut());
532-
if let (Some(ty), Some(new_ty)) = (ty, new_ty) {
533-
*ty = new_ty;
534-
};
535-
}
536-
}
537-
538-
for decl in self.c_decls_top.clone() {
539-
BubbleExprTypes { ast_context: self }.visit_tree(SomeId::Decl(decl));
540-
}
541-
}
542-
543438
/// Sort the top-level declarations by file and source location
544439
/// so that we preserve the ordering of all declarations in each file.
545440
/// This preserves the order when we emit the converted declarations.

c2rust-transpile/src/translator/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -724,11 +724,6 @@ pub fn translate(
724724
t.ast_context
725725
.prune_unwanted_decls(tcfg.preserve_unused_functions);
726726

727-
// Normalize AST types between Clang < 16 and later versions. Ensures that
728-
// binary and unary operators' expr types agree with their argument types
729-
// in the presence of typedefs.
730-
t.ast_context.bubble_expr_types();
731-
732727
enum Name<'a> {
733728
Var(&'a str),
734729
Type(&'a str),

0 commit comments

Comments
 (0)