Skip to content

Commit

Permalink
Change CLI argument to --derive
Browse files Browse the repository at this point in the history
  • Loading branch information
dgherzka committed Nov 28, 2023
1 parent beca631 commit 501ec52
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 25 deletions.
11 changes: 10 additions & 1 deletion c2rust-transpile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use itertools::Itertools;
use log::{info, warn};
use regex::Regex;
use serde_derive::Serialize;
use strum_macros::Display;

use crate::c_ast::Printer;
use crate::c_ast::*;
Expand Down Expand Up @@ -82,7 +83,7 @@ pub struct TranspilerConfig {
pub disable_refactoring: bool,
pub preserve_unused_functions: bool,
pub log_level: log::LevelFilter,
pub derive_debug: bool,
pub derives: HashSet<Derive>,

// Options that control build files
/// Emit `Cargo.toml` and `lib.rs`
Expand All @@ -92,6 +93,14 @@ pub struct TranspilerConfig {
pub binaries: Vec<String>,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Display)]
pub enum Derive {
Clone,
Copy,
Debug,
BitfieldStruct,
}

impl TranspilerConfig {
fn binary_name_from_path(file: &Path) -> String {
let file = Path::new(file.file_stem().unwrap());
Expand Down
50 changes: 36 additions & 14 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use dtoa;
use failure::{err_msg, format_err, Fail};
use indexmap::indexmap;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use log::{error, info, trace, warn};
use proc_macro2::{Punct, Spacing::*, Span, TokenStream, TokenTree};
use syn::spanned::Spanned as _;
Expand All @@ -27,12 +28,12 @@ use c2rust_ast_builder::{mk, properties::*, Builder};
use c2rust_ast_printer::pprust::{self};

use crate::c_ast::iterators::{DFExpr, SomeId};
use crate::c_ast::*;
use crate::cfg;
use crate::convert_type::TypeConverter;
use crate::renamer::Renamer;
use crate::with_stmts::WithStmts;
use crate::{c_ast, format_translation_err};
use crate::{c_ast::*, Derive};
use crate::{ExternCrate, ExternCrateDetails, TranspilerConfig};
use c2rust_ast_exporter::clang_ast::LRValue;

Expand Down Expand Up @@ -1640,14 +1641,6 @@ impl<'c> Translation<'c> {
can_derive_debug,
} = self.convert_struct_fields(decl_id, fields, platform_byte_size)?;

let mut derives = vec![];
if !contains_va_list {
derives.push("Copy");
derives.push("Clone");
};
if self.tcfg.derive_debug && can_derive_debug {
derives.push("Debug");
}
let has_bitfields =
fields
.iter()
Expand All @@ -1656,10 +1649,27 @@ impl<'c> Translation<'c> {
_ => unreachable!("Found non-field in record field list"),
});
if has_bitfields {
derives.push("BitfieldStruct");
self.use_crate(ExternCrate::C2RustBitfields);
}

let derives = self
.tcfg
.derives
.iter()
.flat_map(|derive| {
let can_derive = match derive {
Derive::Clone | Derive::Copy => !contains_va_list,
Derive::Debug => can_derive_debug,
Derive::BitfieldStruct => has_bitfields,
};
if can_derive {
Some(derive.to_string())
} else {
None
}
})
.collect_vec();

let mut reprs = vec![simple_metaitem("C")];
let max_field_alignment = if is_packed {
// `__attribute__((packed))` forces a max alignment of 1,
Expand Down Expand Up @@ -1710,10 +1720,22 @@ impl<'c> Translation<'c> {
let repr_attr = mk().meta_list("repr", outer_reprs);
let outer_field = mk().pub_().enum_field(mk().ident_ty(inner_name));

let mut outer_struct_derives = vec!["Copy", "Clone"];
if self.tcfg.derive_debug {
outer_struct_derives.push("Debug");
}
let outer_struct_derives = self
.tcfg
.derives
.iter()
.flat_map(|derive| {
let can_derive = match derive {
Derive::Clone | Derive::Copy | Derive::Debug => true,
Derive::BitfieldStruct => false,
};
if can_derive {
Some(derive.to_string())
} else {
None
}
})
.collect_vec();

let outer_struct = mk()
.span(span)
Expand Down
39 changes: 34 additions & 5 deletions c2rust/src/bin/c2rust-transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use log::LevelFilter;
use regex::Regex;
use std::{fs, path::PathBuf};

use c2rust_transpile::{Diagnostic, ReplaceMode, TranspilerConfig};
use c2rust_transpile::{Derive, Diagnostic, ReplaceMode, TranspilerConfig};

const DEFAULT_DERIVES: &[Derive] = &[Derive::Clone, Derive::Copy, Derive::BitfieldStruct];

#[derive(Debug, Parser)]
#[clap(
Expand Down Expand Up @@ -156,9 +158,16 @@ struct Args {
#[clap(long)]
fail_on_multiple: bool,

/// Derive `Debug` trait for any structs that allow it (i.e., do not recursively contain any unions)
#[clap(long)]
derive_debug: bool,
/// Add extra derived traits to generated structs in addition to the default
/// set of derives (Copy, Clone, BitfieldStruct). Specify multiple times to
/// add more than one derive. A struct will derive all traits in the set for
/// which it is eligible.
///
/// For example, a struct containing a union cannot derive Debug, so
/// `#[derive(Debug)]` will not be added to that struct regardless of
/// whether `--derive Debug` is specified.
#[clap(long = "derive", value_enum, value_name = "TRAIT")]
extra_derives: Vec<ExtraDerive>,
}

#[derive(Debug, PartialEq, Eq, ValueEnum, Clone)]
Expand All @@ -168,9 +177,29 @@ enum InvalidCodes {
CompileError,
}

#[derive(Clone, Copy, Debug, ValueEnum)]
#[clap(rename_all = "PascalCase")]
enum ExtraDerive {
Debug,
}

impl ExtraDerive {
fn to_transpiler_derive(&self) -> Derive {
match self {
Self::Debug => Derive::Debug,
}
}
}

fn main() {
let args = Args::parse();

let derives = DEFAULT_DERIVES
.iter()
.cloned()
.chain(args.extra_derives.iter().map(|d| d.to_transpiler_derive()))
.collect();

// Build a TranspilerConfig from the command line
let mut tcfg = TranspilerConfig {
dump_untyped_context: args.dump_untyped_clang_ast,
Expand Down Expand Up @@ -220,7 +249,7 @@ fn main() {
emit_no_std: args.emit_no_std,
enabled_warnings: args.warn.into_iter().collect(),
log_level: args.log_level,
derive_debug: args.derive_debug,
derives,
};
// binaries imply emit-build-files
if !tcfg.binaries.is_empty() {
Expand Down
12 changes: 9 additions & 3 deletions scripts/test_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ def __init__(self, log_level: str, path: str, flags: Set[str] = set()) -> None:
self.translate_const_macros = "translate_const_macros" in flags
self.reorganize_definitions = "reorganize_definitions" in flags
self.emit_build_files = "emit_build_files" in flags
self.derive_debug = "derive_debug" in flags

derive_flag_prefix = "derive:"
derives = set()
for derive_flag in filter(lambda f: f.startswith(derive_flag_prefix), flags):
derives.add(derive_flag.removeprefix(derive_flag_prefix))
self.derives = derives

def translate(self, cc_db: str, ld_lib_path: str, extra_args: List[str] = []) -> RustFile:
extensionless_file, _ = os.path.splitext(self.path)
Expand All @@ -97,8 +102,9 @@ def translate(self, cc_db: str, ld_lib_path: str, extra_args: List[str] = []) ->
args.append("--reorganize-definitions")
if self.emit_build_files:
args.append("--emit-build-files")
if self.derive_debug:
args.append("--derive-debug")

for derive in self.derives:
args.extend(["--derive", derive])

if self.log_level == 'DEBUG':
args.append("--log-level=debug")
Expand Down
2 changes: 1 addition & 1 deletion tests/structs/src/debug_derive_bad.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! derive_debug
//! derive:Debug

// A struct containing a union is not debuggable
typedef struct {
Expand Down
2 changes: 1 addition & 1 deletion tests/structs/src/debug_derive_good.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! derive_debug
//! derive:Debug

#include <stdarg.h>

Expand Down

0 comments on commit 501ec52

Please sign in to comment.