use std::collections::{HashMap, HashSet};
use std::fmt;
use crate::clang::ast::QualType;
use crate::clang::constexpr::{ConstEvalError, ConstExprEvaluator, ConstValue};
use crate::clang::coroutines_cpp::{
CoroutineFrame, CoroutineLowering, CoroutineState, PromiseTypeDesc,
};
use crate::clang::cpp_ast::{
CXXDecl, CXXExpr, CXXMemberDecl, CXXName, CXXStmt, LambdaCapture, NestedNameSpecifier,
TemplateParamDecl,
};
use crate::clang::cpp_modules::{ModuleDecl as CppModuleDecl, ModuleImport, ModuleMap, ModuleName};
use crate::clang::cpp_token::{AccessSpecifier, CppStandard};
use crate::clang::overload::{
CandidateRank, CandidateViability, OverloadCandidate, OverloadResolver,
};
use crate::clang::template::{TemplateDeductor, TemplateInstantiator};
use crate::clang::CLangStandard;
use crate::x86::x86_calling_convention::X86CallingConvention;
use crate::x86::x86_target_machine::X86TargetMachine;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum CXXStandardVersion {
CXX98,
CXX03,
CXX11,
CXX14,
CXX17,
CXX20,
CXX23,
CXX26,
}
impl CXXStandardVersion {
pub fn as_str(&self) -> &'static str {
match self {
Self::CXX98 => "c++98",
Self::CXX03 => "c++03",
Self::CXX11 => "c++11",
Self::CXX14 => "c++14",
Self::CXX17 => "c++17",
Self::CXX20 => "c++20",
Self::CXX23 => "c++23",
Self::CXX26 => "c++2c",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"c++98" | "c++03" | "gnu++98" => Some(Self::CXX98),
"c++11" | "gnu++11" => Some(Self::CXX11),
"c++14" | "gnu++14" | "c++1y" => Some(Self::CXX14),
"c++17" | "gnu++17" | "c++1z" => Some(Self::CXX17),
"c++20" | "gnu++20" | "c++2a" => Some(Self::CXX20),
"c++23" | "gnu++23" | "c++2b" => Some(Self::CXX23),
"c++26" | "gnu++26" | "c++2c" => Some(Self::CXX26),
_ => None,
}
}
pub fn is_at_least(&self, other: Self) -> bool {
*self >= other
}
pub fn has_concepts(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_modules(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_coroutines(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_ranges(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_constexpr_dtor(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_constexpr_virtual(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_template_lambdas(&self) -> bool {
self.is_at_least(Self::CXX20)
}
pub fn has_deducing_this(&self) -> bool {
self.is_at_least(Self::CXX23)
}
pub fn has_if_consteval(&self) -> bool {
self.is_at_least(Self::CXX23)
}
pub fn has_multi_dim_subscript(&self) -> bool {
self.is_at_least(Self::CXX23)
}
pub fn has_static_operator_call(&self) -> bool {
self.is_at_least(Self::CXX23)
}
pub fn has_constexpr_placement_new(&self) -> bool {
self.is_at_least(Self::CXX26)
}
pub fn has_pack_indexing(&self) -> bool {
self.is_at_least(Self::CXX26)
}
pub fn has_placeholder_vars(&self) -> bool {
self.is_at_least(Self::CXX26)
}
pub fn has_user_generated_static_assert(&self) -> bool {
self.is_at_least(Self::CXX26)
}
}
impl Default for CXXStandardVersion {
fn default() -> Self {
Self::CXX17
}
}
#[derive(Debug, Clone)]
pub struct CXXFeatureFlags {
pub concepts: bool,
pub modules: bool,
pub coroutines: bool,
pub ranges: bool,
pub three_way_comparison: bool,
pub designated_initializers: bool,
pub template_lambdas: bool,
pub constexpr_virtual: bool,
pub constexpr_dtor: bool,
pub constexpr_try_catch: bool,
pub constexpr_dynamic_cast: bool,
pub consteval: bool,
pub constinit: bool,
pub deducing_this: bool,
pub if_consteval: bool,
pub multi_dim_subscript: bool,
pub static_operator_call: bool,
pub decay_copy: bool,
pub warning_directive: bool,
pub elifdef_elifndef: bool,
pub size_t_literal: bool,
pub placeholder_vars: bool,
pub pack_indexing: bool,
pub constexpr_placement_new: bool,
pub user_generated_static_assert: bool,
pub no_unique_address: bool,
pub likely_unlikely: bool,
pub assume: bool,
pub nodiscard_with_message: bool,
pub generic_lambdas: bool,
pub constexpr_lambdas: bool,
pub lambda_capture_star_this: bool,
pub lambda_init_capture: bool,
pub lambda_template_params: bool,
pub coroutine_symmetric_transfer: bool,
}
impl Default for CXXFeatureFlags {
fn default() -> Self {
Self {
concepts: false,
modules: false,
coroutines: false,
ranges: false,
three_way_comparison: false,
designated_initializers: false,
template_lambdas: false,
constexpr_virtual: false,
constexpr_dtor: false,
constexpr_try_catch: false,
constexpr_dynamic_cast: false,
consteval: false,
constinit: false,
deducing_this: false,
if_consteval: false,
multi_dim_subscript: false,
static_operator_call: false,
decay_copy: false,
warning_directive: false,
elifdef_elifndef: false,
size_t_literal: false,
placeholder_vars: false,
pack_indexing: false,
constexpr_placement_new: false,
user_generated_static_assert: false,
no_unique_address: false,
likely_unlikely: false,
assume: false,
nodiscard_with_message: false,
generic_lambdas: false,
constexpr_lambdas: false,
lambda_capture_star_this: false,
lambda_init_capture: false,
lambda_template_params: false,
coroutine_symmetric_transfer: false,
}
}
}
impl CXXFeatureFlags {
pub fn for_standard(std: CXXStandardVersion) -> Self {
let mut flags = Self::default();
if std.is_at_least(CXXStandardVersion::CXX14) {
flags.generic_lambdas = true;
flags.constexpr_lambdas = true;
flags.lambda_init_capture = true;
}
if std.is_at_least(CXXStandardVersion::CXX17) {
flags.constexpr_lambdas = true;
flags.lambda_capture_star_this = true;
flags.three_way_comparison = true;
flags.designated_initializers = true;
flags.nodiscard_with_message = true;
}
if std.is_at_least(CXXStandardVersion::CXX20) {
flags.concepts = true;
flags.modules = true;
flags.coroutines = true;
flags.ranges = true;
flags.template_lambdas = true;
flags.constexpr_virtual = true;
flags.constexpr_dtor = true;
flags.constexpr_try_catch = true;
flags.constexpr_dynamic_cast = true;
flags.consteval = true;
flags.constinit = true;
flags.no_unique_address = true;
flags.likely_unlikely = true;
flags.lambda_template_params = true;
flags.coroutine_symmetric_transfer = true;
}
if std.is_at_least(CXXStandardVersion::CXX23) {
flags.deducing_this = true;
flags.if_consteval = true;
flags.multi_dim_subscript = true;
flags.static_operator_call = true;
flags.decay_copy = true;
flags.warning_directive = true;
flags.elifdef_elifndef = true;
flags.size_t_literal = true;
flags.assume = true;
}
if std.is_at_least(CXXStandardVersion::CXX26) {
flags.placeholder_vars = true;
flags.pack_indexing = true;
flags.constexpr_placement_new = true;
flags.user_generated_static_assert = true;
}
flags
}
pub fn enable_all_cxx20(&mut self) {
let f = Self::for_standard(CXXStandardVersion::CXX20);
self.concepts = f.concepts;
self.modules = f.modules;
self.coroutines = f.coroutines;
self.ranges = f.ranges;
self.template_lambdas = f.template_lambdas;
self.constexpr_virtual = f.constexpr_virtual;
self.constexpr_dtor = f.constexpr_dtor;
self.constexpr_try_catch = f.constexpr_try_catch;
self.constexpr_dynamic_cast = f.constexpr_dynamic_cast;
self.consteval = f.consteval;
self.constinit = f.constinit;
self.no_unique_address = f.no_unique_address;
self.likely_unlikely = f.likely_unlikely;
self.lambda_template_params = f.lambda_template_params;
self.coroutine_symmetric_transfer = f.coroutine_symmetric_transfer;
}
pub fn enable_all_cxx23(&mut self) {
self.enable_all_cxx20();
let f = Self::for_standard(CXXStandardVersion::CXX23);
self.deducing_this = f.deducing_this;
self.if_consteval = f.if_consteval;
self.multi_dim_subscript = f.multi_dim_subscript;
self.static_operator_call = f.static_operator_call;
self.decay_copy = f.decay_copy;
self.warning_directive = f.warning_directive;
self.elifdef_elifndef = f.elifdef_elifndef;
self.size_t_literal = f.size_t_literal;
self.assume = f.assume;
}
pub fn enable_all_cxx26(&mut self) {
self.enable_all_cxx23();
let f = Self::for_standard(CXXStandardVersion::CXX26);
self.placeholder_vars = f.placeholder_vars;
self.pack_indexing = f.pack_indexing;
self.constexpr_placement_new = f.constexpr_placement_new;
self.user_generated_static_assert = f.user_generated_static_assert;
}
}
#[derive(Debug)]
pub struct CXXFullFrontend {
pub standard: CXXStandardVersion,
pub features: CXXFeatureFlags,
pub concepts: Option<CXX20Concepts>,
pub modules: Option<CXX20Modules>,
pub coroutines: Option<CXX20Coroutines>,
pub ranges: Option<CXX20Ranges>,
pub cxx23: Option<CXX23Features>,
pub cxx26: Option<CXX26Preview>,
pub attributes: CXXAttributeHandler,
pub lambda_extensions: CXXLambdaExtensions,
pub constexpr_extensions: CXXConstexprExtensions,
pub x86_target: Option<X86TargetMachine>,
pub diagnostics: Vec<CXXFullDiagnostic>,
}
#[derive(Debug, Clone)]
pub struct CXXFullDiagnostic {
pub severity: DiagSeverity,
pub message: String,
pub line: u32,
pub column: u32,
pub file: Option<String>,
pub notes: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiagSeverity {
Note,
Warning,
Error,
Fatal,
}
impl fmt::Display for DiagSeverity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Note => write!(f, "note"),
Self::Warning => write!(f, "warning"),
Self::Error => write!(f, "error"),
Self::Fatal => write!(f, "fatal error"),
}
}
}
impl CXXFullDiagnostic {
pub fn error(msg: impl Into<String>) -> Self {
Self {
severity: DiagSeverity::Error,
message: msg.into(),
line: 0,
column: 0,
file: None,
notes: Vec::new(),
}
}
pub fn warning(msg: impl Into<String>) -> Self {
Self {
severity: DiagSeverity::Warning,
message: msg.into(),
line: 0,
column: 0,
file: None,
notes: Vec::new(),
}
}
pub fn at(mut self, line: u32, column: u32) -> Self {
self.line = line;
self.column = column;
self
}
pub fn in_file(mut self, file: impl Into<String>) -> Self {
self.file = Some(file.into());
self
}
pub fn with_note(mut self, note: impl Into<String>) -> Self {
self.notes.push(note.into());
self
}
}
impl CXXFullFrontend {
pub fn new(standard: CXXStandardVersion) -> Self {
let features = CXXFeatureFlags::for_standard(standard);
Self {
standard,
features: features.clone(),
concepts: if features.concepts {
Some(CXX20Concepts::new(standard))
} else {
None
},
modules: if features.modules {
Some(CXX20Modules::new())
} else {
None
},
coroutines: if features.coroutines {
Some(CXX20Coroutines::new(standard))
} else {
None
},
ranges: if features.ranges {
Some(CXX20Ranges::new())
} else {
None
},
cxx23: if standard.is_at_least(CXXStandardVersion::CXX23) {
Some(CXX23Features::new(standard))
} else {
None
},
cxx26: if standard.is_at_least(CXXStandardVersion::CXX26) {
Some(CXX26Preview::new(standard))
} else {
None
},
attributes: CXXAttributeHandler::new(standard),
lambda_extensions: CXXLambdaExtensions::new(standard),
constexpr_extensions: CXXConstexprExtensions::new(standard),
x86_target: None,
diagnostics: Vec::new(),
}
}
pub fn for_x86_64_linux(standard: CXXStandardVersion) -> Self {
let mut fe = Self::new(standard);
fe.x86_target = Some(X86TargetMachine::default());
fe
}
pub fn with_x86_target(mut self, tm: X86TargetMachine) -> Self {
self.x86_target = Some(tm);
self
}
pub fn enable_feature(&mut self, name: &str) -> bool {
match name {
"concepts" => {
self.features.concepts = true;
if self.concepts.is_none() {
self.concepts = Some(CXX20Concepts::new(self.standard));
}
true
}
"modules" => {
self.features.modules = true;
if self.modules.is_none() {
self.modules = Some(CXX20Modules::new());
}
true
}
"coroutines" => {
self.features.coroutines = true;
if self.coroutines.is_none() {
self.coroutines = Some(CXX20Coroutines::new(self.standard));
}
true
}
"ranges" => {
self.features.ranges = true;
if self.ranges.is_none() {
self.ranges = Some(CXX20Ranges::new());
}
true
}
"deducing_this" => {
self.features.deducing_this = true;
true
}
"if_consteval" => {
self.features.if_consteval = true;
true
}
"pack_indexing" => {
self.features.pack_indexing = true;
true
}
"constexpr_placement_new" => {
self.features.constexpr_placement_new = true;
true
}
_ => false,
}
}
pub fn is_enabled(&self, name: &str) -> bool {
match name {
"concepts" => self.features.concepts,
"modules" => self.features.modules,
"coroutines" => self.features.coroutines,
"ranges" => self.features.ranges,
"deducing_this" => self.features.deducing_this,
"if_consteval" => self.features.if_consteval,
"multi_dim_subscript" => self.features.multi_dim_subscript,
"static_operator_call" => self.features.static_operator_call,
"decay_copy" => self.features.decay_copy,
"pack_indexing" => self.features.pack_indexing,
"constexpr_placement_new" => self.features.constexpr_placement_new,
"placeholder_vars" => self.features.placeholder_vars,
"user_generated_static_assert" => self.features.user_generated_static_assert,
_ => false,
}
}
pub fn emit(&mut self, diag: CXXFullDiagnostic) {
self.diagnostics.push(diag);
}
pub fn get_diagnostics(&self) -> &[CXXFullDiagnostic] {
&self.diagnostics
}
pub fn has_errors(&self) -> bool {
self.diagnostics
.iter()
.any(|d| matches!(d.severity, DiagSeverity::Error | DiagSeverity::Fatal))
}
pub fn enabled_feature_count(&self) -> usize {
let mut count = 0;
if self.features.concepts {
count += 1;
}
if self.features.modules {
count += 1;
}
if self.features.coroutines {
count += 1;
}
if self.features.ranges {
count += 1;
}
if self.features.deducing_this {
count += 1;
}
if self.features.if_consteval {
count += 1;
}
if self.features.multi_dim_subscript {
count += 1;
}
if self.features.static_operator_call {
count += 1;
}
if self.features.pack_indexing {
count += 1;
}
if self.features.constexpr_placement_new {
count += 1;
}
if self.features.placeholder_vars {
count += 1;
}
if self.features.user_generated_static_assert {
count += 1;
}
count
}
pub fn validate_configuration(&mut self) -> bool {
let mut valid = true;
if self.features.concepts && !self.standard.has_concepts() {
self.emit(
CXXFullDiagnostic::warning("concepts require C++20 or later")
.with_note("concepts are a C++20 feature"),
);
valid = false;
}
if self.features.modules && !self.standard.has_modules() {
self.emit(
CXXFullDiagnostic::warning("modules require C++20 or later")
.with_note("modules are a C++20 feature"),
);
valid = false;
}
if self.features.deducing_this && !self.standard.has_deducing_this() {
self.emit(
CXXFullDiagnostic::warning("deducing this requires C++23 or later")
.with_note("deducing this is a C++23 feature"),
);
valid = false;
}
valid
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConstraintResult {
Satisfied,
NotSatisfied { reason: String },
Dependent,
}
impl ConstraintResult {
pub fn is_satisfied(&self) -> bool {
matches!(self, Self::Satisfied)
}
pub fn is_dependent(&self) -> bool {
matches!(self, Self::Dependent)
}
}
#[derive(Debug, Clone)]
pub struct AtomicConstraint {
pub expression: String,
pub parameter_mapping: Vec<(String, String)>,
pub is_normalized: bool,
}
impl AtomicConstraint {
pub fn new(expression: impl Into<String>) -> Self {
Self {
expression: expression.into(),
parameter_mapping: Vec::new(),
is_normalized: false,
}
}
pub fn with_mapping(mut self, param: impl Into<String>, arg: impl Into<String>) -> Self {
self.parameter_mapping.push((param.into(), arg.into()));
self
}
pub fn normalize(&mut self) {
if !self.is_normalized {
let mut expr = self.expression.clone();
for (param, arg) in &self.parameter_mapping {
expr = expr.replace(param, arg);
}
self.expression = expr;
self.is_normalized = true;
}
}
pub fn subsumes(&self, other: &AtomicConstraint) -> bool {
let mut a = self.clone();
let mut b = other.clone();
a.normalize();
b.normalize();
a.expression == b.expression
}
}
#[derive(Debug, Clone)]
pub enum ConstraintExpr {
Atomic(AtomicConstraint),
Conjunction(Box<ConstraintExpr>, Box<ConstraintExpr>),
Disjunction(Box<ConstraintExpr>, Box<ConstraintExpr>),
Negation(Box<ConstraintExpr>),
}
impl ConstraintExpr {
pub fn evaluate(&self, env: &ConstraintEnv) -> ConstraintResult {
match self {
Self::Atomic(a) => {
if env.is_dependent(&a.expression) {
ConstraintResult::Dependent
} else if env.check_atomic(a) {
ConstraintResult::Satisfied
} else {
ConstraintResult::NotSatisfied {
reason: format!("constraint '{}' not satisfied", a.expression),
}
}
}
Self::Conjunction(l, r) => {
let left = l.evaluate(env);
if !left.is_satisfied() {
return left;
}
r.evaluate(env)
}
Self::Disjunction(l, r) => {
let left = l.evaluate(env);
if left.is_satisfied() {
return left;
}
let right = r.evaluate(env);
if right.is_satisfied() {
return right;
}
if left.is_dependent() || right.is_dependent() {
ConstraintResult::Dependent
} else {
ConstraintResult::NotSatisfied {
reason: "neither disjunct satisfied".into(),
}
}
}
Self::Negation(inner) => match inner.evaluate(env) {
ConstraintResult::Satisfied => ConstraintResult::NotSatisfied {
reason: "negation rejected".into(),
},
ConstraintResult::NotSatisfied { .. } => ConstraintResult::Satisfied,
ConstraintResult::Dependent => ConstraintResult::Dependent,
},
}
}
pub fn subsumes(&self, other: &ConstraintExpr) -> bool {
match (self, other) {
(Self::Atomic(a), Self::Atomic(b)) => a.subsumes(b),
(Self::Conjunction(l1, r1), Self::Conjunction(l2, r2)) => {
l1.subsumes(l2) && r1.subsumes(r2)
}
(Self::Disjunction(l1, r1), _) => l1.subsumes(other) || r1.subsumes(other),
_ => false,
}
}
}
#[derive(Debug, Clone)]
pub struct ConstraintEnv {
pub concepts: HashMap<String, ConstraintExpr>,
pub bindings: HashMap<String, String>,
pub in_dependent_context: bool,
}
impl ConstraintEnv {
pub fn new() -> Self {
Self {
concepts: HashMap::new(),
bindings: HashMap::new(),
in_dependent_context: false,
}
}
pub fn register_concept(&mut self, name: impl Into<String>, expr: ConstraintExpr) {
self.concepts.insert(name.into(), expr);
}
pub fn bind(&mut self, param: impl Into<String>, arg: impl Into<String>) {
self.bindings.insert(param.into(), arg.into());
}
pub fn is_dependent(&self, _expr: &str) -> bool {
self.in_dependent_context
}
pub fn check_atomic(&self, constraint: &AtomicConstraint) -> bool {
if self.in_dependent_context {
return true;
}
!constraint.expression.is_empty()
}
}
impl Default for ConstraintEnv {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ConceptDefinition {
pub name: String,
pub template_params: Vec<TemplateParamDecl>,
pub constraint: ConstraintExpr,
pub is_defined: bool,
pub source_line: u32,
}
impl ConceptDefinition {
pub fn new(name: impl Into<String>, constraint: ConstraintExpr) -> Self {
Self {
name: name.into(),
template_params: Vec::new(),
constraint,
is_defined: true,
source_line: 0,
}
}
pub fn with_params(mut self, params: Vec<TemplateParamDecl>) -> Self {
self.template_params = params;
self
}
pub fn is_satisfied(&self, env: &ConstraintEnv) -> ConstraintResult {
self.constraint.evaluate(env)
}
pub fn subsumes(&self, other: &ConceptDefinition) -> bool {
self.constraint.subsumes(&other.constraint)
}
}
#[derive(Debug, Clone)]
pub struct RequiresClause {
pub constraint: ConstraintExpr,
pub evaluated: bool,
pub cached_result: Option<ConstraintResult>,
}
impl RequiresClause {
pub fn new(constraint: ConstraintExpr) -> Self {
Self {
constraint,
evaluated: false,
cached_result: None,
}
}
pub fn evaluate(&mut self, env: &ConstraintEnv) -> ConstraintResult {
if let Some(ref cached) = self.cached_result {
return cached.clone();
}
let result = self.constraint.evaluate(env);
self.evaluated = true;
self.cached_result = Some(result.clone());
result
}
}
#[derive(Debug, Clone)]
pub struct RequiresExpression {
pub params: Vec<(String, String)>, pub requirements: Vec<Requirement>,
pub evaluated: bool,
pub cached_result: Option<ConstraintResult>,
}
#[derive(Debug, Clone)]
pub enum Requirement {
Simple(String),
Type(String),
Compound {
expression: String,
is_noexcept: bool,
return_type_constraint: Option<String>,
},
Nested(RequiresClause),
}
impl RequiresExpression {
pub fn new() -> Self {
Self {
params: Vec::new(),
requirements: Vec::new(),
evaluated: false,
cached_result: None,
}
}
pub fn add_param(&mut self, name: impl Into<String>, ty: impl Into<String>) {
self.params.push((name.into(), ty.into()));
}
pub fn add_simple_requirement(&mut self, expr: impl Into<String>) {
self.requirements.push(Requirement::Simple(expr.into()));
}
pub fn add_type_requirement(&mut self, ty: impl Into<String>) {
self.requirements.push(Requirement::Type(ty.into()));
}
pub fn add_compound_requirement(
&mut self,
expr: impl Into<String>,
noexcept: bool,
return_type: Option<String>,
) {
self.requirements.push(Requirement::Compound {
expression: expr.into(),
is_noexcept: noexcept,
return_type_constraint: return_type,
});
}
pub fn add_nested_requirement(&mut self, clause: RequiresClause) {
self.requirements.push(Requirement::Nested(clause));
}
pub fn evaluate(&mut self, env: &ConstraintEnv) -> ConstraintResult {
if let Some(ref cached) = self.cached_result {
return cached.clone();
}
if self.params.is_empty() && self.requirements.is_empty() {
self.evaluated = true;
self.cached_result = Some(ConstraintResult::Satisfied);
return ConstraintResult::Satisfied;
}
let result = ConstraintResult::Satisfied;
self.evaluated = true;
self.cached_result = Some(result.clone());
result
}
}
#[derive(Debug)]
pub struct CXX20Concepts {
pub concept_definitions: HashMap<String, ConceptDefinition>,
pub env: ConstraintEnv,
pub standard: CXXStandardVersion,
pub overload_resolver: OverloadResolver,
pub diagnostics: Vec<String>,
}
impl CXX20Concepts {
pub fn new(standard: CXXStandardVersion) -> Self {
Self {
concept_definitions: HashMap::new(),
env: ConstraintEnv::new(),
standard,
overload_resolver: OverloadResolver::new(),
diagnostics: Vec::new(),
}
}
pub fn register_concept(&mut self, def: ConceptDefinition) {
self.concept_definitions.insert(def.name.clone(), def);
}
pub fn lookup_concept(&self, name: &str) -> Option<&ConceptDefinition> {
self.concept_definitions.get(name)
}
pub fn check_requires_clause(&mut self, clause: &mut RequiresClause) -> ConstraintResult {
clause.evaluate(&self.env)
}
pub fn check_subsumption(
&self,
constraint_a: &ConstraintExpr,
constraint_b: &ConstraintExpr,
) -> bool {
constraint_a.subsumes(constraint_b)
}
pub fn resolve_with_concepts(&mut self, candidates: &[OverloadCandidate]) -> Option<usize> {
if candidates.is_empty() {
return None;
}
if candidates.len() == 1 {
return Some(0);
}
let mut best_idx = 0;
for (i, c) in candidates.iter().enumerate().skip(1) {
if c.rank < candidates[best_idx].rank {
best_idx = i;
}
}
Some(best_idx)
}
pub fn parse_requires_clause(&self, source: &str) -> Option<RequiresClause> {
if source.trim().is_empty() {
return None;
}
let constraint = ConstraintExpr::Atomic(AtomicConstraint::new(source.trim()));
Some(RequiresClause::new(constraint))
}
pub fn atomic_constraint(&self, expr: impl Into<String>) -> AtomicConstraint {
AtomicConstraint::new(expr)
}
pub fn concept_count(&self) -> usize {
self.concept_definitions.len()
}
pub fn is_constrained_visible(&self, concept_name: &str) -> bool {
self.concept_definitions.contains_key(concept_name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExtendedModuleKind {
Interface,
Implementation,
PartitionInterface,
PartitionImplementation,
HeaderUnit,
GlobalFragment,
PrivateFragment,
}
impl fmt::Display for ExtendedModuleKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Interface => write!(f, "interface"),
Self::Implementation => write!(f, "implementation"),
Self::PartitionInterface => write!(f, "partition interface"),
Self::PartitionImplementation => write!(f, "partition implementation"),
Self::HeaderUnit => write!(f, "header unit"),
Self::GlobalFragment => write!(f, "global module fragment"),
Self::PrivateFragment => write!(f, "private module fragment"),
}
}
}
impl ExtendedModuleKind {
pub fn is_interface(&self) -> bool {
matches!(self, Self::Interface | Self::PartitionInterface)
}
pub fn is_partition(&self) -> bool {
matches!(
self,
Self::PartitionInterface | Self::PartitionImplementation
)
}
pub fn is_fragment(&self) -> bool {
matches!(self, Self::GlobalFragment | Self::PrivateFragment)
}
pub fn exports_name(&self) -> bool {
matches!(self, Self::Interface | Self::PartitionInterface)
}
}
#[derive(Debug, Clone)]
pub struct ExtendedModuleDecl {
pub name: ModuleName,
pub kind: ExtendedModuleKind,
pub partition_name: Option<String>,
pub source_loc: (u32, u32), pub attributes: Vec<CXXAttribute>,
pub is_exported: bool,
}
impl ExtendedModuleDecl {
pub fn interface(name: ModuleName) -> Self {
Self {
name,
kind: ExtendedModuleKind::Interface,
partition_name: None,
source_loc: (0, 0),
attributes: Vec::new(),
is_exported: false,
}
}
pub fn implementation(name: ModuleName) -> Self {
Self {
name,
kind: ExtendedModuleKind::Implementation,
partition_name: None,
source_loc: (0, 0),
attributes: Vec::new(),
is_exported: false,
}
}
pub fn partition(parent: ModuleName, partition: impl Into<String>) -> Self {
Self {
name: parent,
kind: ExtendedModuleKind::PartitionInterface,
partition_name: Some(partition.into()),
source_loc: (0, 0),
attributes: Vec::new(),
is_exported: false,
}
}
pub fn at(mut self, line: u32, column: u32) -> Self {
self.source_loc = (line, column);
self
}
pub fn with_attribute(mut self, attr: CXXAttribute) -> Self {
self.attributes.push(attr);
self
}
}
impl fmt::Display for ExtendedModuleDecl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "module")?;
if self.is_exported {
write!(f, " export")?;
}
match self.kind {
ExtendedModuleKind::Interface => write!(f, " {};", self.name)?,
ExtendedModuleKind::Implementation => write!(f, " {};", self.name)?,
ExtendedModuleKind::PartitionInterface => {
if let Some(ref p) = self.partition_name {
write!(f, " {}:{};", self.name, p)?;
}
}
ExtendedModuleKind::PartitionImplementation => {
if let Some(ref p) = self.partition_name {
write!(f, " {}:{};", self.name, p)?;
}
}
ExtendedModuleKind::HeaderUnit => write!(f, ";")?,
ExtendedModuleKind::GlobalFragment => write!(f, ";")?,
ExtendedModuleKind::PrivateFragment => write!(f, " :private;")?,
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct ExtendedModuleImport {
pub name: ModuleName,
pub is_exported: bool,
pub is_header_unit: bool,
pub header_name: Option<String>,
pub source_loc: (u32, u32),
}
impl ExtendedModuleImport {
pub fn new(name: ModuleName) -> Self {
Self {
name,
is_exported: false,
is_header_unit: false,
header_name: None,
source_loc: (0, 0),
}
}
pub fn exported(mut self) -> Self {
self.is_exported = true;
self
}
pub fn header_unit(mut self, header: impl Into<String>) -> Self {
self.is_header_unit = true;
self.header_name = Some(header.into());
self
}
}
#[derive(Debug, Clone)]
pub struct ModuleUnit {
pub decl: ExtendedModuleDecl,
pub imports: Vec<ExtendedModuleImport>,
pub exported_decls: Vec<String>,
pub owned_decls: Vec<String>,
pub reachable_decls: HashSet<String>,
pub is_interface: bool,
pub bmi_path: Option<String>,
pub source_path: Option<String>,
}
impl ModuleUnit {
pub fn new(decl: ExtendedModuleDecl) -> Self {
Self {
is_interface: decl.kind.is_interface(),
decl,
imports: Vec::new(),
exported_decls: Vec::new(),
owned_decls: Vec::new(),
reachable_decls: HashSet::new(),
bmi_path: None,
source_path: None,
}
}
pub fn add_import(&mut self, import: ExtendedModuleImport) {
self.imports.push(import);
}
pub fn add_export(&mut self, name: impl Into<String>) {
self.exported_decls.push(name.into());
}
pub fn add_owned(&mut self, name: impl Into<String>) {
self.owned_decls.push(name.into());
}
pub fn mark_reachable(&mut self, name: impl Into<String>) {
self.reachable_decls.insert(name.into());
}
pub fn is_reachable(&self, name: &str) -> bool {
self.reachable_decls.contains(name)
}
pub fn module_name(&self) -> String {
self.decl.name.to_string()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModuleLinkage {
Attached(String),
Global,
Private(String),
Unknown,
}
impl ModuleLinkage {
pub fn module_name(&self) -> Option<&str> {
match self {
Self::Attached(name) | Self::Private(name) => Some(name),
_ => None,
}
}
pub fn is_attached(&self) -> bool {
matches!(self, Self::Attached(_))
}
pub fn is_global(&self) -> bool {
matches!(self, Self::Global)
}
}
#[derive(Debug, Clone)]
pub struct ModuleOwnershipTracker {
pub current_module: Option<String>,
pub ownership: HashMap<String, ModuleLinkage>,
pub reachable_from: HashMap<String, HashSet<String>>,
}
impl ModuleOwnershipTracker {
pub fn new() -> Self {
Self {
current_module: None,
ownership: HashMap::new(),
reachable_from: HashMap::new(),
}
}
pub fn enter_module(&mut self, name: impl Into<String>) {
self.current_module = Some(name.into());
}
pub fn leave_module(&mut self) {
self.current_module = None;
}
pub fn record(&mut self, decl_name: impl Into<String>) {
let name = decl_name.into();
let linkage = match &self.current_module {
Some(m) => ModuleLinkage::Attached(m.clone()),
None => ModuleLinkage::Global,
};
self.ownership.insert(name, linkage);
}
pub fn linkage_of(&self, name: &str) -> ModuleLinkage {
self.ownership
.get(name)
.copied()
.unwrap_or(ModuleLinkage::Unknown)
}
pub fn mark_reachable_from(&mut self, decl: impl Into<String>, module: impl Into<String>) {
let d = decl.into();
let m = module.into();
self.reachable_from
.entry(d)
.or_insert_with(HashSet::new)
.insert(m);
}
}
impl Default for ModuleOwnershipTracker {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct GlobalModuleFragment {
pub decls: Vec<String>,
pub includes: Vec<String>,
pub preprocessor_state: Option<String>, }
impl GlobalModuleFragment {
pub fn new() -> Self {
Self {
decls: Vec::new(),
includes: Vec::new(),
preprocessor_state: None,
}
}
pub fn add_decl(&mut self, decl: impl Into<String>) {
self.decls.push(decl.into());
}
pub fn add_include(&mut self, inc: impl Into<String>) {
self.includes.push(inc.into());
}
pub fn is_empty(&self) -> bool {
self.decls.is_empty() && self.includes.is_empty()
}
}
impl Default for GlobalModuleFragment {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct PrivateModuleFragment {
pub decls: Vec<String>,
pub is_closed: bool,
}
impl PrivateModuleFragment {
pub fn new() -> Self {
Self {
decls: Vec::new(),
is_closed: false,
}
}
pub fn add_decl(&mut self, decl: impl Into<String>) {
self.decls.push(decl.into());
}
pub fn close(&mut self) {
self.is_closed = true;
}
pub fn is_empty(&self) -> bool {
self.decls.is_empty()
}
pub fn validate_placement(&self, total_decl_count: usize) -> bool {
if self.is_empty() {
return true;
}
self.is_closed
}
}
impl Default for PrivateModuleFragment {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ModuleDependencyResolver {
pub graph: HashMap<String, HashSet<String>>, pub reverse_graph: HashMap<String, HashSet<String>>,
pub resolution_errors: Vec<String>,
}
impl ModuleDependencyResolver {
pub fn new() -> Self {
Self {
graph: HashMap::new(),
reverse_graph: HashMap::new(),
resolution_errors: Vec::new(),
}
}
pub fn add_dependency(&mut self, from: impl Into<String>, to: impl Into<String>) {
let f = from.into();
let t = to.into();
self.graph
.entry(f.clone())
.or_insert_with(HashSet::new)
.insert(t.clone());
self.reverse_graph
.entry(t)
.or_insert_with(HashSet::new)
.insert(f);
}
pub fn topological_sort(&self) -> Result<Vec<String>, String> {
let mut visited = HashSet::new();
let mut temp_marks = HashSet::new();
let mut order = Vec::new();
fn visit(
node: &str,
graph: &HashMap<String, HashSet<String>>,
visited: &mut HashSet<String>,
temp_marks: &mut HashSet<String>,
order: &mut Vec<String>,
) -> Result<(), String> {
if temp_marks.contains(node) {
return Err(format!("circular dependency detected: {}", node));
}
if visited.contains(node) {
return Ok(());
}
temp_marks.insert(node.to_string());
if let Some(deps) = graph.get(node) {
for dep in deps {
visit(dep, graph, visited, temp_marks, order)?;
}
}
temp_marks.remove(node);
visited.insert(node.to_string());
order.push(node.to_string());
Ok(())
}
for node in self.graph.keys() {
if !visited.contains(node.as_str()) {
visit(node, &self.graph, &mut visited, &mut temp_marks, &mut order)?;
}
}
for node in self.reverse_graph.keys() {
if !visited.contains(node.as_str()) {
visited.insert(node.clone());
order.push(node.clone());
}
}
Ok(order)
}
pub fn has_circular_deps(&self) -> bool {
self.topological_sort().is_err()
}
pub fn transitive_deps(&self, module: &str) -> HashSet<String> {
let mut result = HashSet::new();
let mut stack: Vec<String> = self
.graph
.get(module)
.cloned()
.unwrap_or_default()
.into_iter()
.collect();
while let Some(dep) = stack.pop() {
if result.insert(dep.clone()) {
if let Some(transitive) = self.graph.get(&dep) {
stack.extend(transitive.iter().cloned());
}
}
}
result
}
pub fn module_count(&self) -> usize {
self.graph.len()
}
}
impl Default for ModuleDependencyResolver {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct CXX20Modules {
pub module_map: ModuleMap,
pub units: HashMap<String, ModuleUnit>,
pub ownership: ModuleOwnershipTracker,
pub global_fragment: GlobalModuleFragment,
pub private_fragment: PrivateModuleFragment,
pub dependency_resolver: ModuleDependencyResolver,
pub current_unit: Option<String>,
pub diagnostics: Vec<String>,
}
impl CXX20Modules {
pub fn new() -> Self {
Self {
module_map: ModuleMap::new(),
units: HashMap::new(),
ownership: ModuleOwnershipTracker::new(),
global_fragment: GlobalModuleFragment::new(),
private_fragment: PrivateModuleFragment::new(),
dependency_resolver: ModuleDependencyResolver::new(),
current_unit: None,
diagnostics: Vec::new(),
}
}
pub fn register_unit(&mut self, unit: ModuleUnit) {
let name = unit.module_name();
self.module_map.register_module(
ModuleName::from_str(&name),
unit.is_interface,
unit.bmi_path.clone(),
unit.source_path.clone(),
&unit
.imports
.iter()
.map(|i| i.name.to_string())
.collect::<Vec<_>>(),
);
for import in &unit.imports {
self.dependency_resolver
.add_dependency(&name, &import.name.to_string());
}
self.units.insert(name, unit);
}
pub fn enter_module(&mut self, name: impl Into<String>) {
let n = name.into();
self.ownership.enter_module(&n);
self.current_unit = Some(n);
}
pub fn leave_module(&mut self) {
self.ownership.leave_module();
self.current_unit = None;
}
pub fn add_export(&mut self, name: impl Into<String>) {
if let Some(ref unit_name) = self.current_unit {
if let Some(unit) = self.units.get_mut(unit_name) {
unit.add_export(name);
}
}
}
pub fn record_decl(&mut self, name: impl Into<String>) {
let n = name.into();
self.ownership.record(&n);
if let Some(ref unit_name) = self.current_unit {
if let Some(unit) = self.units.get_mut(unit_name) {
unit.add_owned(n);
}
}
}
pub fn is_visible(&self, name: &str) -> bool {
if self.current_unit.is_none() {
return true; }
if let Some(ref unit_name) = self.current_unit {
if let Some(unit) = self.units.get(unit_name) {
return unit.is_reachable(name)
|| unit.owned_decls.contains(&name.to_string())
|| unit.exported_decls.contains(&name.to_string());
}
}
false
}
pub fn build_order(&self) -> Result<Vec<String>, String> {
self.dependency_resolver.topological_sort()
}
pub fn has_circular_deps(&self) -> bool {
self.dependency_resolver.has_circular_deps()
}
pub fn unit_count(&self) -> usize {
self.units.len()
}
pub fn current_module_name(&self) -> Option<&str> {
self.current_unit.as_deref()
}
pub fn emit_metadata(&self) -> Vec<String> {
let mut meta = Vec::new();
for (name, unit) in &self.units {
meta.push(format!("!llvm.module.flags = !{{!0}} ; module {}", name));
for exp in &unit.exported_decls {
meta.push(format!(" export {}", exp));
}
}
meta
}
}
impl Default for CXX20Modules {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoroKeyword {
CoAwait,
CoYield,
CoReturn,
}
impl fmt::Display for CoroKeyword {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CoAwait => write!(f, "co_await"),
Self::CoYield => write!(f, "co_yield"),
Self::CoReturn => write!(f, "co_return"),
}
}
}
#[derive(Debug, Clone)]
pub struct CoroutineExpr {
pub keyword: CoroKeyword,
pub operand: Option<String>,
pub source_loc: (u32, u32),
pub awaitable_desc: Option<AwaitableDescriptor>,
}
#[derive(Debug, Clone)]
pub struct AwaitableDescriptor {
pub awaitable_type: String,
pub has_await_ready: bool,
pub has_await_suspend: bool,
pub has_await_resume: bool,
pub is_symmetric_transfer: bool,
}
impl AwaitableDescriptor {
pub fn new(ty: impl Into<String>) -> Self {
Self {
awaitable_type: ty.into(),
has_await_ready: true,
has_await_suspend: true,
has_await_resume: true,
is_symmetric_transfer: false,
}
}
}
impl CoroutineExpr {
pub fn co_await(operand: impl Into<String>) -> Self {
Self {
keyword: CoroKeyword::CoAwait,
operand: Some(operand.into()),
source_loc: (0, 0),
awaitable_desc: None,
}
}
pub fn co_yield(operand: impl Into<String>) -> Self {
Self {
keyword: CoroKeyword::CoYield,
operand: Some(operand.into()),
source_loc: (0, 0),
awaitable_desc: None,
}
}
pub fn co_return(operand: Option<String>) -> Self {
Self {
keyword: CoroKeyword::CoReturn,
operand,
source_loc: (0, 0),
awaitable_desc: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ExtendedPromiseTypeDesc {
pub type_name: String,
pub has_get_return_object: bool,
pub has_initial_suspend: bool,
pub has_final_suspend: bool,
pub has_unhandled_exception: bool,
pub has_return_void: bool,
pub has_return_value: bool,
pub has_yield_value: bool,
pub return_object_type: Option<String>,
pub initial_suspend_awaitable: Option<AwaitableDescriptor>,
pub final_suspend_awaitable: Option<AwaitableDescriptor>,
pub has_allocator: bool,
pub has_deallocator: bool,
pub supports_symmetric_transfer: bool,
pub transform_awaitable: bool,
}
impl ExtendedPromiseTypeDesc {
pub fn new(type_name: impl Into<String>) -> Self {
Self {
type_name: type_name.into(),
has_get_return_object: false,
has_initial_suspend: false,
has_final_suspend: false,
has_unhandled_exception: false,
has_return_void: false,
has_return_value: false,
has_yield_value: false,
return_object_type: None,
initial_suspend_awaitable: None,
final_suspend_awaitable: None,
has_allocator: false,
has_deallocator: false,
supports_symmetric_transfer: false,
transform_awaitable: false,
}
}
pub fn with_initial_suspend(mut self) -> Self {
self.has_initial_suspend = true;
self
}
pub fn with_final_suspend(mut self) -> Self {
self.has_final_suspend = true;
self
}
pub fn with_symmetric_transfer(mut self) -> Self {
self.supports_symmetric_transfer = true;
self
}
pub fn is_complete(&self) -> bool {
self.has_get_return_object
&& self.has_initial_suspend
&& self.has_final_suspend
&& self.has_unhandled_exception
}
}
#[derive(Debug, Clone)]
pub struct ExtendedCoroutineFrame {
pub promise_type: String,
pub promise_offset: u32,
pub locals: Vec<CoroutineFrameLocal>,
pub resume_fn_ptr_offset: u32,
pub destroy_fn_ptr_offset: u32,
pub state_index_offset: u32,
pub frame_size: u32,
pub frame_alignment: u32,
pub spill_slots: Vec<CoroutineSpillSlot>,
pub saved_params: Vec<CoroutineSavedParam>,
pub symmetric_transfer_enabled: bool,
}
#[derive(Debug, Clone)]
pub struct CoroutineFrameLocal {
pub name: String,
pub llvm_type: String,
pub offset: u32,
pub size: u32,
pub spans_suspend: bool,
pub needs_destruction: bool,
}
#[derive(Debug, Clone)]
pub struct CoroutineSpillSlot {
pub register: String,
pub offset: u32,
pub size: u32,
}
#[derive(Debug, Clone)]
pub struct CoroutineSavedParam {
pub name: String,
pub ty: String,
pub offset: u32,
pub spans_suspend: bool,
}
impl ExtendedCoroutineFrame {
pub fn new(promise_type: impl Into<String>) -> Self {
Self {
promise_type: promise_type.into(),
promise_offset: 0,
locals: Vec::new(),
resume_fn_ptr_offset: 0,
destroy_fn_ptr_offset: 0,
state_index_offset: 0,
frame_size: 0,
frame_alignment: 16,
spill_slots: Vec::new(),
saved_params: Vec::new(),
symmetric_transfer_enabled: false,
}
}
pub fn add_local(&mut self, local: CoroutineFrameLocal) {
self.locals.push(local);
}
pub fn add_spill_slot(&mut self, slot: CoroutineSpillSlot) {
self.spill_slots.push(slot);
}
pub fn add_saved_param(&mut self, param: CoroutineSavedParam) {
self.saved_params.push(param);
}
pub fn total_frame_size(&self) -> u32 {
self.frame_size
+ self.spill_slots.iter().map(|s| s.size).sum::<u32>()
+ self.saved_params.iter().map(|p| 8).sum::<u32>()
}
pub fn local_count(&self) -> usize {
self.locals.len()
}
}
#[derive(Debug, Clone)]
pub struct SymmetricTransferOptimizer {
pub enabled: bool,
pub can_elide_alloc: bool,
pub frame_does_not_escape: bool,
pub transfer_count: u32,
}
impl SymmetricTransferOptimizer {
pub fn new() -> Self {
Self {
enabled: true,
can_elide_alloc: false,
frame_does_not_escape: false,
transfer_count: 0,
}
}
pub fn analyze(&mut self, has_symmetric_transfer: bool) {
if has_symmetric_transfer {
self.transfer_count += 1;
if self.transfer_count > 0 {
self.can_elide_alloc = true;
}
}
}
pub fn can_perform_symmetric_transfer(&self) -> bool {
self.enabled && self.transfer_count > 0
}
}
impl Default for SymmetricTransferOptimizer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct HaloAnalyzer {
pub can_elide_heap: bool,
pub frame_does_not_escape: bool,
pub max_live_range: u32,
pub requires_heap: bool,
}
impl HaloAnalyzer {
pub fn new() -> Self {
Self {
can_elide_heap: false,
frame_does_not_escape: false,
max_live_range: 0,
requires_heap: true,
}
}
pub fn analyze(&mut self, frame_escapes: bool, live_range: u32) {
self.frame_does_not_escape = !frame_escapes;
self.max_live_range = live_range;
if !frame_escapes && live_range < 100 {
self.can_elide_heap = true;
self.requires_heap = false;
}
}
pub fn should_elide(&self) -> bool {
self.can_elide_heap && !self.requires_heap
}
}
impl Default for HaloAnalyzer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct CXX20Coroutines {
pub standard: CXXStandardVersion,
pub promises: HashMap<String, ExtendedPromiseTypeDesc>,
pub frames: HashMap<String, ExtendedCoroutineFrame>,
pub sym_transfer: SymmetricTransferOptimizer,
pub halo: HaloAnalyzer,
pub coroutine_count: u32,
pub diagnostics: Vec<String>,
}
impl CXX20Coroutines {
pub fn new(standard: CXXStandardVersion) -> Self {
Self {
standard,
promises: HashMap::new(),
frames: HashMap::new(),
sym_transfer: SymmetricTransferOptimizer::new(),
halo: HaloAnalyzer::new(),
coroutine_count: 0,
diagnostics: Vec::new(),
}
}
pub fn register_promise(
&mut self,
coroutine_name: impl Into<String>,
promise: ExtendedPromiseTypeDesc,
) {
self.promises.insert(coroutine_name.into(), promise);
}
pub fn register_frame(
&mut self,
coroutine_name: impl Into<String>,
frame: ExtendedCoroutineFrame,
) {
self.frames.insert(coroutine_name.into(), frame);
}
pub fn signal_symmetric_transfer(&mut self, source: &str, target: &str) {
self.sym_transfer.analyze(true);
self.coroutine_count += 1;
}
pub fn analyze_halo(&mut self, coroutine_name: &str) {
let frame_escapes = false;
let live_range = 10;
self.halo.analyze(frame_escapes, live_range);
}
pub fn parse_coro_expr(&self, source: &str) -> Option<CoroutineExpr> {
let trimmed = source.trim();
if trimmed.starts_with("co_await") {
let operand = trimmed[8..].trim().to_string();
Some(CoroutineExpr::co_await(operand))
} else if trimmed.starts_with("co_yield") {
let operand = trimmed[8..].trim().to_string();
Some(CoroutineExpr::co_yield(operand))
} else if trimmed.starts_with("co_return") {
let rest = trimmed[9..].trim();
if rest.is_empty() || rest == ";" {
Some(CoroutineExpr::co_return(None))
} else {
let operand = rest.trim_end_matches(';').trim().to_string();
Some(CoroutineExpr::co_return(Some(operand)))
}
} else {
None
}
}
pub fn statistics(&self) -> CoroutineStatistics {
CoroutineStatistics {
total_coroutines: self.coroutine_count,
promises_registered: self.promises.len() as u32,
frames_allocated: self.frames.len() as u32,
symmetric_transfers: self.sym_transfer.transfer_count,
halo_elisions: if self.halo.can_elide_heap { 1 } else { 0 },
}
}
}
#[derive(Debug, Clone)]
pub struct CoroutineStatistics {
pub total_coroutines: u32,
pub promises_registered: u32,
pub frames_allocated: u32,
pub symmetric_transfers: u32,
pub halo_elisions: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RangeConcept {
Range,
SizedRange,
View,
InputRange,
ForwardRange,
BidirectionalRange,
RandomAccessRange,
ContiguousRange,
CommonRange,
ViewableRange,
BorrowedRange,
OutputRange,
}
impl fmt::Display for RangeConcept {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Range => write!(f, "std::ranges::range"),
Self::SizedRange => write!(f, "std::ranges::sized_range"),
Self::View => write!(f, "std::ranges::view"),
Self::InputRange => write!(f, "std::ranges::input_range"),
Self::ForwardRange => write!(f, "std::ranges::forward_range"),
Self::BidirectionalRange => write!(f, "std::ranges::bidirectional_range"),
Self::RandomAccessRange => write!(f, "std::ranges::random_access_range"),
Self::ContiguousRange => write!(f, "std::ranges::contiguous_range"),
Self::CommonRange => write!(f, "std::ranges::common_range"),
Self::ViewableRange => write!(f, "std::ranges::viewable_range"),
Self::BorrowedRange => write!(f, "std::ranges::borrowed_range"),
Self::OutputRange => write!(f, "std::ranges::output_range"),
}
}
}
impl RangeConcept {
pub fn is_refinement_of(&self, other: RangeConcept) -> bool {
use RangeConcept::*;
if *self == other {
return true;
}
matches!(
(*self, other),
(RandomAccessRange, BidirectionalRange)
| (RandomAccessRange, ForwardRange)
| (RandomAccessRange, InputRange)
| (RandomAccessRange, Range)
| (BidirectionalRange, ForwardRange)
| (BidirectionalRange, InputRange)
| (BidirectionalRange, Range)
| (ForwardRange, InputRange)
| (ForwardRange, Range)
| (InputRange, Range)
| (ContiguousRange, RandomAccessRange)
| (ContiguousRange, Range)
| (SizedRange, Range)
| (View, Range)
| (CommonRange, Range)
| (BorrowedRange, Range)
| (ViewableRange, Range)
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RangeAdaptor {
Filter,
Transform,
Take,
TakeWhile,
Drop,
DropWhile,
Join,
Split,
Reverse,
Elements,
Keys,
Values,
Common,
Iota,
Single,
Empty,
Repeat,
Counted,
Subrange,
RefView,
OwningView,
All,
Zip,
ZipTransform,
Enumerate,
Adjacent,
AdjacentTransform,
Chunk,
ChunkBy,
Slide,
Stride,
JoinWith,
AsConst,
AsRvalue,
CartesianProduct,
Concat,
}
impl fmt::Display for RangeAdaptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Filter => write!(f, "std::views::filter"),
Self::Transform => write!(f, "std::views::transform"),
Self::Take => write!(f, "std::views::take"),
Self::TakeWhile => write!(f, "std::views::take_while"),
Self::Drop => write!(f, "std::views::drop"),
Self::DropWhile => write!(f, "std::views::drop_while"),
Self::Join => write!(f, "std::views::join"),
Self::Split => write!(f, "std::views::split"),
Self::Reverse => write!(f, "std::views::reverse"),
Self::Elements => write!(f, "std::views::elements"),
Self::Keys => write!(f, "std::views::keys"),
Self::Values => write!(f, "std::views::values"),
Self::Common => write!(f, "std::views::common"),
Self::Iota => write!(f, "std::views::iota"),
Self::Single => write!(f, "std::views::single"),
Self::Empty => write!(f, "std::views::empty"),
Self::Repeat => write!(f, "std::views::repeat"),
Self::Counted => write!(f, "std::views::counted"),
Self::Subrange => write!(f, "std::ranges::subrange"),
Self::RefView => write!(f, "std::ranges::ref_view"),
Self::OwningView => write!(f, "std::ranges::owning_view"),
Self::All => write!(f, "std::views::all"),
Self::Zip => write!(f, "std::views::zip"),
Self::ZipTransform => write!(f, "std::views::zip_transform"),
Self::Enumerate => write!(f, "std::views::enumerate"),
Self::Adjacent => write!(f, "std::views::adjacent"),
Self::AdjacentTransform => write!(f, "std::views::adjacent_transform"),
Self::Chunk => write!(f, "std::views::chunk"),
Self::ChunkBy => write!(f, "std::views::chunk_by"),
Self::Slide => write!(f, "std::views::slide"),
Self::Stride => write!(f, "std::views::stride"),
Self::JoinWith => write!(f, "std::views::join_with"),
Self::AsConst => write!(f, "std::views::as_const"),
Self::AsRvalue => write!(f, "std::views::as_rvalue"),
Self::CartesianProduct => write!(f, "std::views::cartesian_product"),
Self::Concat => write!(f, "std::views::concat"),
}
}
}
#[derive(Debug, Clone)]
pub struct RangeViewConfig {
pub adaptor: RangeAdaptor,
pub element_type: String,
pub is_const: bool,
pub is_sized: bool,
pub is_borrowed: bool,
pub is_common: bool,
}
impl RangeViewConfig {
pub fn new(adaptor: RangeAdaptor, element_type: impl Into<String>) -> Self {
let et = element_type.into();
let (sized, borrowed, common) = match adaptor {
RangeAdaptor::Filter => (false, false, false),
RangeAdaptor::Transform => (true, false, true),
RangeAdaptor::Take => (true, false, false),
RangeAdaptor::Drop => (true, false, true),
RangeAdaptor::Reverse => (true, false, true),
RangeAdaptor::Iota => (false, true, false),
RangeAdaptor::Single => (true, true, true),
RangeAdaptor::Empty => (true, true, true),
RangeAdaptor::Repeat => (false, true, false),
RangeAdaptor::All => (true, true, true),
RangeAdaptor::Common => (false, false, true),
RangeAdaptor::Zip | RangeAdaptor::Enumerate => (true, false, true),
_ => (false, false, false),
};
Self {
adaptor,
element_type: et,
is_const: true,
is_sized: sized,
is_borrowed: borrowed,
is_common: common,
}
}
}
#[derive(Debug, Clone)]
pub struct IteratorConcept {
pub range_concept: Option<RangeConcept>,
pub value_type: String,
pub reference_type: String,
pub difference_type: String,
pub iterator_category: IteratorCategory,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IteratorCategory {
Input,
Output,
Forward,
Bidirectional,
RandomAccess,
Contiguous,
}
impl fmt::Display for IteratorCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Input => write!(f, "std::input_iterator"),
Self::Output => write!(f, "std::output_iterator"),
Self::Forward => write!(f, "std::forward_iterator"),
Self::Bidirectional => write!(f, "std::bidirectional_iterator"),
Self::RandomAccess => write!(f, "std::random_access_iterator"),
Self::Contiguous => write!(f, "std::contiguous_iterator"),
}
}
}
#[derive(Debug, Clone)]
pub struct SentinelConcept {
pub iterator_type: String,
pub sentinel_type: String,
pub is_sized_sentinel: bool,
}
#[derive(Debug, Clone)]
pub struct Projection {
pub name: String,
pub source_type: String,
pub target_type: String,
pub is_identity: bool,
}
impl Projection {
pub fn identity() -> Self {
Self {
name: "std::identity".into(),
source_type: "auto".into(),
target_type: "auto".into(),
is_identity: true,
}
}
pub fn custom(
name: impl Into<String>,
source: impl Into<String>,
target: impl Into<String>,
) -> Self {
Self {
name: name.into(),
source_type: source.into(),
target_type: target.into(),
is_identity: false,
}
}
}
#[derive(Debug)]
pub struct CXX20Ranges {
pub adaptors: HashMap<RangeAdaptor, RangeViewConfig>,
pub iterator_concepts: HashMap<String, IteratorConcept>,
pub range_concepts: HashMap<String, Vec<RangeConcept>>,
pub sentinels: HashMap<String, SentinelConcept>,
pub projections: HashMap<String, Projection>,
pub enabled: bool,
}
impl CXX20Ranges {
pub fn new() -> Self {
let mut adaptors = HashMap::new();
for adaptor in &[
RangeAdaptor::Filter,
RangeAdaptor::Transform,
RangeAdaptor::Take,
RangeAdaptor::Drop,
RangeAdaptor::TakeWhile,
RangeAdaptor::DropWhile,
RangeAdaptor::Join,
RangeAdaptor::Split,
RangeAdaptor::Reverse,
RangeAdaptor::Elements,
RangeAdaptor::Iota,
RangeAdaptor::Single,
RangeAdaptor::Empty,
RangeAdaptor::Repeat,
RangeAdaptor::All,
RangeAdaptor::Common,
RangeAdaptor::Counted,
RangeAdaptor::Subrange,
] {
adaptors.insert(*adaptor, RangeViewConfig::new(*adaptor, "T"));
}
Self {
adaptors,
iterator_concepts: HashMap::new(),
range_concepts: HashMap::new(),
sentinels: HashMap::new(),
projections: HashMap::new(),
enabled: true,
}
}
pub fn register_iterator(&mut self, type_name: impl Into<String>, concept: IteratorConcept) {
self.iterator_concepts.insert(type_name.into(), concept);
}
pub fn satisfies_range_concept(&self, type_name: &str, concept: RangeConcept) -> bool {
if let Some(concepts) = self.range_concepts.get(type_name) {
concepts
.iter()
.any(|c| c == &concept || concept.is_refinement_of(*c))
} else {
false
}
}
pub fn register_range_concepts(
&mut self,
type_name: impl Into<String>,
concepts: Vec<RangeConcept>,
) {
self.range_concepts.insert(type_name.into(), concepts);
}
pub fn register_sentinel(&mut self, sentinel: SentinelConcept) {
self.sentinels
.insert(sentinel.iterator_type.clone(), sentinel);
}
pub fn register_projection(&mut self, proj: Projection) {
self.projections.insert(proj.name.clone(), proj);
}
pub fn lookup_adaptor(&self, adaptor: RangeAdaptor) -> Option<&RangeViewConfig> {
self.adaptors.get(&adaptor)
}
pub fn has_adaptor(&self, name: &str) -> bool {
self.adaptors.iter().any(|(a, _)| a.to_string() == name)
}
pub fn adaptor_names(&self) -> Vec<String> {
self.adaptors.keys().map(|a| a.to_string()).collect()
}
pub fn adaptor_count(&self) -> usize {
self.adaptors.len()
}
pub fn get_iterator_concept(&self, type_name: &str) -> Option<&IteratorConcept> {
self.iterator_concepts.get(type_name)
}
}
impl Default for CXX20Ranges {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExplicitObjectKind {
DeducedRef,
DeducedLvalueRef,
DeducedByValue,
DeducedConstLvalueRef,
DeducedConstRvalueRef,
}
impl fmt::Display for ExplicitObjectKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DeducedRef => write!(f, "auto&&"),
Self::DeducedLvalueRef => write!(f, "auto&"),
Self::DeducedByValue => write!(f, "auto"),
Self::DeducedConstLvalueRef => write!(f, "const auto&"),
Self::DeducedConstRvalueRef => write!(f, "const auto&&"),
}
}
}
impl ExplicitObjectKind {
pub fn from_param_str(s: &str) -> Option<Self> {
match s.trim() {
"auto&&" => Some(Self::DeducedRef),
"auto&" => Some(Self::DeducedLvalueRef),
"auto" => Some(Self::DeducedByValue),
"const auto&" => Some(Self::DeducedConstLvalueRef),
"const auto&&" => Some(Self::DeducedConstRvalueRef),
_ => None,
}
}
pub fn is_reference(&self) -> bool {
matches!(
self,
Self::DeducedRef
| Self::DeducedLvalueRef
| Self::DeducedConstLvalueRef
| Self::DeducedConstRvalueRef
)
}
}
#[derive(Debug, Clone)]
pub struct ExplicitObjectFunction {
pub name: String,
pub explicit_kind: ExplicitObjectKind,
pub explicit_param_name: String,
pub regular_params: Vec<(String, String)>,
pub return_type: String,
pub is_static: bool,
pub is_constexpr: bool,
pub is_noexcept: bool,
pub class_name: Option<String>,
}
impl ExplicitObjectFunction {
pub fn new(
name: impl Into<String>,
kind: ExplicitObjectKind,
param_name: impl Into<String>,
) -> Self {
Self {
name: name.into(),
explicit_kind: kind,
explicit_param_name: param_name.into(),
regular_params: Vec::new(),
return_type: "auto".into(),
is_static: true,
is_constexpr: false,
is_noexcept: false,
class_name: None,
}
}
pub fn add_param(&mut self, name: impl Into<String>, ty: impl Into<String>) {
self.regular_params.push((name.into(), ty.into()));
}
pub fn signature(&self) -> String {
let mut sig = format!("{}(", self.name);
sig.push_str(&self.explicit_kind.to_string());
sig.push_str(" ");
sig.push_str(&self.explicit_param_name);
for (n, t) in &self.regular_params {
sig.push_str(&format!(", {} {}", t, n));
}
sig.push_str(")");
if self.is_constexpr {
sig.insert_str(0, "constexpr ");
}
sig
}
pub fn can_bind_lvalue(&self) -> bool {
matches!(
self.explicit_kind,
ExplicitObjectKind::DeducedRef
| ExplicitObjectKind::DeducedLvalueRef
| ExplicitObjectKind::DeducedConstLvalueRef
)
}
pub fn can_bind_rvalue(&self) -> bool {
matches!(
self.explicit_kind,
ExplicitObjectKind::DeducedRef
| ExplicitObjectKind::DeducedByValue
| ExplicitObjectKind::DeducedConstRvalueRef
)
}
}
#[derive(Debug, Clone)]
pub struct IfConsteval {
pub is_consteval_block: bool,
pub else_block: bool,
pub in_immediate_context: bool,
}
impl IfConsteval {
pub fn new() -> Self {
Self {
is_consteval_block: false,
else_block: false,
in_immediate_context: false,
}
}
pub fn evaluate(&self) -> IfConstevalResult {
if self.in_immediate_context {
IfConstevalResult::ImmediateContext
} else {
IfConstevalResult::NonImmediateContext
}
}
}
impl Default for IfConsteval {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IfConstevalResult {
ImmediateContext,
NonImmediateContext,
}
#[derive(Debug, Clone)]
pub struct MultiDimSubscript {
pub index_count: usize,
pub index_types: Vec<String>,
pub return_type: String,
pub is_const: bool,
}
impl MultiDimSubscript {
pub fn new(index_types: Vec<String>, return_type: impl Into<String>) -> Self {
Self {
index_count: index_types.len(),
index_types,
return_type: return_type.into(),
is_const: false,
}
}
pub fn validate(&self) -> Result<(), String> {
if self.index_count == 0 {
return Err("multidimensional subscript requires at least 1 index".into());
}
if self.index_types.len() != self.index_count {
return Err("index count mismatch with index types".into());
}
Ok(())
}
pub fn call_syntax(&self, object: &str) -> String {
let mut s = format!("{}.operator[](", object);
for (i, ty) in self.index_types.iter().enumerate() {
if i > 0 {
s.push_str(", ");
}
s.push_str(&format!("{} i{}", ty, i));
}
s.push(')');
s
}
}
#[derive(Debug, Clone)]
pub struct StaticOperatorCall {
pub class_name: String,
pub params: Vec<(String, String)>,
pub return_type: String,
pub is_lambda: bool,
pub has_captures: bool,
}
impl StaticOperatorCall {
pub fn new(class_name: impl Into<String>) -> Self {
Self {
class_name: class_name.into(),
params: Vec::new(),
return_type: "auto".into(),
is_lambda: false,
has_captures: false,
}
}
pub fn validate(&self) -> Result<(), String> {
if self.is_lambda && self.has_captures {
return Err("a lambda with captures cannot have a static operator()".into());
}
Ok(())
}
pub fn mangled_name(&self) -> String {
format!("_ZN{}clE", self.class_name)
}
}
#[derive(Debug, Clone)]
pub struct DecayCopyExpr {
pub kind: DecayCopyKind,
pub inner_expr: String,
pub deduced_type: String,
pub is_prvalue: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecayCopyKind {
DecayCopyParen,
DecayCopyBrace,
}
impl fmt::Display for DecayCopyKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DecayCopyParen => write!(f, "auto(x)"),
Self::DecayCopyBrace => write!(f, "auto{{x}}"),
}
}
}
impl DecayCopyExpr {
pub fn new(kind: DecayCopyKind, inner: impl Into<String>) -> Self {
Self {
kind,
inner_expr: inner.into(),
deduced_type: "auto".into(),
is_prvalue: true,
}
}
pub fn emit(&self) -> String {
match self.kind {
DecayCopyKind::DecayCopyParen => format!("auto({})", self.inner_expr),
DecayCopyKind::DecayCopyBrace => format!("auto{{{}}}", self.inner_expr),
}
}
pub fn apply_decay(&self, ty: &str) -> String {
let stripped = ty.trim_end_matches('&').trim_end_matches("&&");
if stripped.ends_with("const") {
let idx = stripped.rfind("const").unwrap();
stripped[..idx].trim().to_string()
} else if stripped.starts_with("const ") {
stripped[6..].to_string()
} else {
stripped.to_string()
}
}
}
#[derive(Debug, Clone)]
pub struct WarningDirective {
pub message: String,
pub line: u32,
pub file: Option<String>,
}
impl WarningDirective {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
line: 0,
file: None,
}
}
pub fn format_diagnostic(&self) -> String {
format!("#warning: {}", self.message)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElifConditional {
Elif,
Elifdef,
Elifndef,
}
impl ElifConditional {
pub fn from_directive(d: &str) -> Option<Self> {
match d {
"elif" => Some(Self::Elif),
"elifdef" => Some(Self::Elifdef),
"elifndef" => Some(Self::Elifndef),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Elif => "#elif",
Self::Elifdef => "#elifdef",
Self::Elifndef => "#elifndef",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CXX23Feature {
DeducingThis,
IfConsteval,
StaticOperatorCall,
MultiDimSubscript,
DecayCopy,
WarningDirective,
ElifdefElifndef,
SizeTLiteral,
ConstexprVirtual,
ConstexprTryCatch,
ConstexprDynamicCast,
ConstexprUnion,
Unreachable,
ZipView,
EnumerateView,
AdjacentView,
CartesianProductView,
ChunkView,
SlideView,
StrideView,
JoinWithView,
AsConstView,
AsRvalueView,
ConcatView,
Expected,
OptionalMonadic,
}
impl CXX23Feature {
pub fn name(&self) -> &'static str {
match self {
Self::DeducingThis => "deducing this",
Self::IfConsteval => "if consteval",
Self::StaticOperatorCall => "static operator()",
Self::MultiDimSubscript => "multidimensional subscript",
Self::DecayCopy => "auto(x) / auto{x}",
Self::WarningDirective => "#warning",
Self::ElifdefElifndef => "#elifdef / #elifndef",
Self::SizeTLiteral => "size_t literals",
Self::ConstexprVirtual => "constexpr virtual",
Self::ConstexprTryCatch => "constexpr try-catch",
Self::ConstexprDynamicCast => "constexpr dynamic_cast",
Self::ConstexprUnion => "constexpr union",
Self::Unreachable => "std::unreachable",
Self::ZipView => "std::views::zip",
Self::EnumerateView => "std::views::enumerate",
Self::AdjacentView => "std::views::adjacent",
Self::CartesianProductView => "std::views::cartesian_product",
Self::ChunkView => "std::views::chunk",
Self::SlideView => "std::views::slide",
Self::StrideView => "std::views::stride",
Self::JoinWithView => "std::views::join_with",
Self::AsConstView => "std::views::as_const",
Self::AsRvalueView => "std::views::as_rvalue",
Self::ConcatView => "std::views::concat",
Self::Expected => "std::expected",
Self::OptionalMonadic => "std::optional monadic",
}
}
}
#[derive(Debug)]
pub struct CXX23Features {
pub standard: CXXStandardVersion,
pub explicit_object_functions: Vec<ExplicitObjectFunction>,
pub if_consteval: IfConsteval,
pub static_operators: Vec<StaticOperatorCall>,
pub multi_dim_subscripts: Vec<MultiDimSubscript>,
pub decay_copies: Vec<DecayCopyExpr>,
pub warning_directives: Vec<WarningDirective>,
pub elif_conditionals: Vec<ElifConditional>,
pub enabled_features: HashSet<CXX23Feature>,
pub diagnostics: Vec<String>,
}
impl CXX23Features {
pub fn new(standard: CXXStandardVersion) -> Self {
let mut enabled = HashSet::new();
if standard.is_at_least(CXXStandardVersion::CXX23) {
enabled.insert(CXX23Feature::DeducingThis);
enabled.insert(CXX23Feature::IfConsteval);
enabled.insert(CXX23Feature::StaticOperatorCall);
enabled.insert(CXX23Feature::MultiDimSubscript);
enabled.insert(CXX23Feature::DecayCopy);
enabled.insert(CXX23Feature::WarningDirective);
enabled.insert(CXX23Feature::ElifdefElifndef);
enabled.insert(CXX23Feature::SizeTLiteral);
enabled.insert(CXX23Feature::ZipView);
enabled.insert(CXX23Feature::EnumerateView);
enabled.insert(CXX23Feature::ChunkView);
}
Self {
standard,
explicit_object_functions: Vec::new(),
if_consteval: IfConsteval::new(),
static_operators: Vec::new(),
multi_dim_subscripts: Vec::new(),
decay_copies: Vec::new(),
warning_directives: Vec::new(),
elif_conditionals: Vec::new(),
enabled_features: enabled,
diagnostics: Vec::new(),
}
}
pub fn is_enabled(&self, feature: CXX23Feature) -> bool {
self.enabled_features.contains(&feature)
}
pub fn enable(&mut self, feature: CXX23Feature) {
self.enabled_features.insert(feature);
}
pub fn disable(&mut self, feature: CXX23Feature) {
self.enabled_features.remove(&feature);
}
pub fn register_explicit_object_fn(&mut self, func: ExplicitObjectFunction) {
self.explicit_object_functions.push(func);
}
pub fn register_multi_dim_subscript(&mut self, sub: MultiDimSubscript) {
self.multi_dim_subscripts.push(sub);
}
pub fn register_static_operator(&mut self, op: StaticOperatorCall) {
self.static_operators.push(op);
}
pub fn register_decay_copy(&mut self, dc: DecayCopyExpr) {
self.decay_copies.push(dc);
}
pub fn handle_elif_conditional(&mut self, cond: ElifConditional) {
self.elif_conditionals.push(cond);
}
pub fn add_warning(&mut self, warning: WarningDirective) {
self.warning_directives.push(warning);
}
pub fn enabled_count(&self) -> usize {
self.enabled_features.len()
}
pub fn find_explicit_object_fn(&self, name: &str) -> Option<&ExplicitObjectFunction> {
self.explicit_object_functions
.iter()
.find(|f| f.name == name)
}
}
#[derive(Debug, Clone)]
pub struct PlaceholderVariable {
pub scope: String,
pub ty: String,
pub is_structured_binding: bool,
pub index: u32,
}
impl PlaceholderVariable {
pub fn new(scope: impl Into<String>, ty: impl Into<String>) -> Self {
Self {
scope: scope.into(),
ty: ty.into(),
is_structured_binding: false,
index: 0,
}
}
pub fn anonymous() -> Self {
Self {
scope: "__anonymous".into(),
ty: "auto".into(),
is_structured_binding: false,
index: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct PackIndexing {
pub pack_name: String,
pub index_expr: String,
pub element_type: String,
pub is_constant_index: bool,
}
impl PackIndexing {
pub fn new(pack_name: impl Into<String>, index: impl Into<String>) -> Self {
Self {
pack_name: pack_name.into(),
index_expr: index.into(),
element_type: "auto".into(),
is_constant_index: true,
}
}
pub fn to_source(&self) -> String {
format!("{}...[{}]", self.pack_name, self.index_expr)
}
pub fn validate(&self) -> Result<(), String> {
if !self.is_constant_index {
return Err("pack index must be a constant expression".into());
}
if self.index_expr.is_empty() {
return Err("pack index must not be empty".into());
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct ConstexprPlacementNew {
pub placement_address: String,
pub constructed_type: String,
pub constructor_args: Vec<String>,
pub alignment: u32,
}
impl ConstexprPlacementNew {
pub fn new(address: impl Into<String>, ty: impl Into<String>) -> Self {
Self {
placement_address: address.into(),
constructed_type: ty.into(),
constructor_args: Vec::new(),
alignment: 0,
}
}
pub fn with_args(mut self, args: Vec<String>) -> Self {
self.constructor_args = args;
self
}
pub fn with_alignment(mut self, align: u32) -> Self {
self.alignment = align;
self
}
pub fn validate(&self) -> Result<(), String> {
if !self.placement_address.starts_with('&') && self.placement_address != "nullptr" {
return Err("constexpr placement new requires a valid storage address".into());
}
Ok(())
}
pub fn to_source(&self) -> String {
let mut s = format!(
"::new ({}) {}",
self.placement_address, self.constructed_type
);
if !self.constructor_args.is_empty() {
s.push('(');
s.push_str(&self.constructor_args.join(", "));
s.push(')');
}
s
}
}
#[derive(Debug, Clone)]
pub struct ConstexprAllocationTracker {
pub allocations: Vec<ConstexprAllocRecord>,
pub total_allocated: u64,
pub total_deallocated: u64,
pub leak_detected: bool,
}
#[derive(Debug, Clone)]
pub struct ConstexprAllocRecord {
pub address: String,
pub size: u64,
pub alignment: u32,
pub deallocated: bool,
pub constructed_type: Option<String>,
}
impl ConstexprAllocationTracker {
pub fn new() -> Self {
Self {
allocations: Vec::new(),
total_allocated: 0,
total_deallocated: 0,
leak_detected: false,
}
}
pub fn allocate(&mut self, size: u64, align: u32) -> String {
let addr = format!("%alloc{}", self.allocations.len());
self.allocations.push(ConstexprAllocRecord {
address: addr.clone(),
size,
alignment: align,
deallocated: false,
constructed_type: None,
});
self.total_allocated += size;
addr
}
pub fn deallocate(&mut self, address: &str) -> bool {
for alloc in &mut self.allocations {
if alloc.address == address && !alloc.deallocated {
alloc.deallocated = true;
self.total_deallocated += alloc.size;
return true;
}
}
false
}
pub fn check_leaks(&mut self) -> bool {
let leaked = self.allocations.iter().any(|a| !a.deallocated);
self.leak_detected = leaked;
leaked
}
pub fn is_sound(&self) -> bool {
!self.leak_detected && self.total_allocated == self.total_deallocated
}
}
impl Default for ConstexprAllocationTracker {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct UserGeneratedStaticAssert {
pub condition: String,
pub message_source: String,
pub evaluated_message: Option<String>,
pub is_constant_evaluated: bool,
}
impl UserGeneratedStaticAssert {
pub fn new(condition: impl Into<String>, message_source: impl Into<String>) -> Self {
Self {
condition: condition.into(),
message_source: message_source.into(),
evaluated_message: None,
is_constant_evaluated: false,
}
}
pub fn evaluate_message(&mut self, env: &HashMap<String, String>) {
if self.is_constant_evaluated {
return;
}
let mut msg = self.message_source.clone();
for (key, val) in env {
msg = msg.replace(key, val);
}
self.evaluated_message = Some(msg);
self.is_constant_evaluated = true;
}
pub fn formatted(&self) -> String {
match &self.evaluated_message {
Some(m) => format!("static_assert({}, \"{}\");", self.condition, m),
None => format!("static_assert({});", self.condition),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CXX26Feature {
PlaceholderVars,
PackIndexing,
ConstexprPlacementNew,
UserGeneratedStaticAssert,
Contracts,
Reflection,
PatternMatching,
SendersReceivers,
HazardPointers,
ReadCopyUpdate,
Submdspan,
SimdExtensions,
LinearAlgebra,
InplaceVector,
Hive,
DebuggingSupport,
TextEncoding,
PacksOutsideTemplates,
ConstevalPropagation,
}
impl CXX26Feature {
pub fn name(&self) -> &'static str {
match self {
Self::PlaceholderVars => "placeholder variables",
Self::PackIndexing => "pack indexing",
Self::ConstexprPlacementNew => "constexpr placement new",
Self::UserGeneratedStaticAssert => "user-generated static_assert messages",
Self::Contracts => "contracts",
Self::Reflection => "static reflection",
Self::PatternMatching => "pattern matching",
Self::SendersReceivers => "senders/receivers",
Self::HazardPointers => "hazard pointers",
Self::ReadCopyUpdate => "RCU",
Self::Submdspan => "submdspan",
Self::SimdExtensions => "SIMD extensions",
Self::LinearAlgebra => "linear algebra",
Self::InplaceVector => "inplace_vector",
Self::Hive => "hive",
Self::DebuggingSupport => "debugging support",
Self::TextEncoding => "text encoding",
Self::PacksOutsideTemplates => "packs outside templates",
Self::ConstevalPropagation => "consteval propagation",
}
}
}
#[derive(Debug)]
pub struct CXX26Preview {
pub standard: CXXStandardVersion,
pub placeholders: Vec<PlaceholderVariable>,
pub pack_indexings: Vec<PackIndexing>,
pub placement_news: Vec<ConstexprPlacementNew>,
pub static_asserts: Vec<UserGeneratedStaticAssert>,
pub alloc_tracker: ConstexprAllocationTracker,
pub enabled_features: HashSet<CXX26Feature>,
pub diagnostics: Vec<String>,
}
impl CXX26Preview {
pub fn new(standard: CXXStandardVersion) -> Self {
let mut enabled = HashSet::new();
if standard.is_at_least(CXXStandardVersion::CXX26) {
enabled.insert(CXX26Feature::PlaceholderVars);
enabled.insert(CXX26Feature::PackIndexing);
enabled.insert(CXX26Feature::ConstexprPlacementNew);
enabled.insert(CXX26Feature::UserGeneratedStaticAssert);
enabled.insert(CXX26Feature::ConstevalPropagation);
}
Self {
standard,
placeholders: Vec::new(),
pack_indexings: Vec::new(),
placement_news: Vec::new(),
static_asserts: Vec::new(),
alloc_tracker: ConstexprAllocationTracker::new(),
enabled_features: enabled,
diagnostics: Vec::new(),
}
}
pub fn is_enabled(&self, feature: CXX26Feature) -> bool {
self.enabled_features.contains(&feature)
}
pub fn enable(&mut self, feature: CXX26Feature) {
self.enabled_features.insert(feature);
}
pub fn disable(&mut self, feature: CXX26Feature) {
self.enabled_features.remove(&feature);
}
pub fn register_placeholder(&mut self, var: PlaceholderVariable) {
self.placeholders.push(var);
}
pub fn register_pack_indexing(&mut self, pi: PackIndexing) {
self.pack_indexings.push(pi);
}
pub fn register_placement_new(&mut self, pn: ConstexprPlacementNew) {
self.placement_news.push(pn);
}
pub fn register_static_assert(&mut self, sa: UserGeneratedStaticAssert) {
self.static_asserts.push(sa);
}
pub fn track_allocation(&mut self, size: u64, align: u32) -> String {
self.alloc_tracker.allocate(size, align)
}
pub fn track_deallocation(&mut self, addr: &str) -> bool {
self.alloc_tracker.deallocate(addr)
}
pub fn check_leaks(&mut self) -> bool {
self.alloc_tracker.check_leaks()
}
pub fn enabled_count(&self) -> usize {
self.enabled_features.len()
}
pub fn feature_count(&self) -> usize {
20
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CXXAttribute {
Noreturn,
CarriesDependency,
Deprecated(Option<String>),
Fallthrough,
Nodiscard(Option<String>),
MaybeUnused,
NoUniqueAddress,
Likely,
Unlikely,
NoUniqueAddress20,
Assume(String),
GnuNoreturn,
GnuConst,
GnuPure,
GnuAlwaysInline,
GnuNoinline,
GnuHot,
GnuCold,
GnuPacked,
GnuAligned(u32),
GnuUnused,
GnuVisibility(String),
DllExport,
DllImport,
NoReturn,
Unknown(String),
}
impl fmt::Display for CXXAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Noreturn => write!(f, "[[noreturn]]"),
Self::CarriesDependency => write!(f, "[[carries_dependency]]"),
Self::Deprecated(None) => write!(f, "[[deprecated]]"),
Self::Deprecated(Some(msg)) => write!(f, "[[deprecated(\"{}\")]]", msg),
Self::Fallthrough => write!(f, "[[fallthrough]]"),
Self::Nodiscard(None) => write!(f, "[[nodiscard]]"),
Self::Nodiscard(Some(msg)) => write!(f, "[[nodiscard(\"{}\")]]", msg),
Self::MaybeUnused => write!(f, "[[maybe_unused]]"),
Self::NoUniqueAddress => write!(f, "[[no_unique_address]]"),
Self::Likely => write!(f, "[[likely]]"),
Self::Unlikely => write!(f, "[[unlikely]]"),
Self::NoUniqueAddress20 => write!(f, "[[no_unique_address]]"),
Self::Assume(expr) => write!(f, "[[assume({})]]", expr),
Self::GnuNoreturn => write!(f, "__attribute__((noreturn))"),
Self::GnuConst => write!(f, "__attribute__((const))"),
Self::GnuPure => write!(f, "__attribute__((pure))"),
Self::GnuAlwaysInline => write!(f, "__attribute__((always_inline))"),
Self::GnuNoinline => write!(f, "__attribute__((noinline))"),
Self::GnuHot => write!(f, "__attribute__((hot))"),
Self::GnuCold => write!(f, "__attribute__((cold))"),
Self::GnuPacked => write!(f, "__attribute__((packed))"),
Self::GnuAligned(n) => write!(f, "__attribute__((aligned({})))", n),
Self::GnuUnused => write!(f, "__attribute__((unused))"),
Self::GnuVisibility(v) => write!(f, "__attribute__((visibility(\"{}\")))", v),
Self::DllExport => write!(f, "__declspec(dllexport)"),
Self::DllImport => write!(f, "__declspec(dllimport)"),
Self::NoReturn => write!(f, "__declspec(noreturn)"),
Self::Unknown(s) => write!(f, "[[{}]]", s),
}
}
}
impl CXXAttribute {
pub fn parse(source: &str) -> Option<Self> {
let trimmed = source.trim();
if !trimmed.starts_with("[[") || !trimmed.ends_with("]]") {
return None;
}
let inner = &trimmed[2..trimmed.len() - 2].trim();
if let Some(msg_start) = inner.find('(') {
let name = inner[..msg_start].trim();
let msg = &inner[msg_start + 1..inner.len() - 1].trim();
let msg = msg.trim_matches('"');
match name {
"deprecated" => return Some(Self::Deprecated(Some(msg.to_string()))),
"nodiscard" => return Some(Self::Nodiscard(Some(msg.to_string()))),
"assume" => return Some(Self::Assume(msg.to_string())),
_ => return Some(Self::Unknown(name.to_string())),
}
}
match inner {
"noreturn" => Some(Self::Noreturn),
"carries_dependency" => Some(Self::CarriesDependency),
"deprecated" => Some(Self::Deprecated(None)),
"fallthrough" => Some(Self::Fallthrough),
"nodiscard" => Some(Self::Nodiscard(None)),
"maybe_unused" => Some(Self::MaybeUnused),
"no_unique_address" => Some(Self::NoUniqueAddress),
"likely" => Some(Self::Likely),
"unlikely" => Some(Self::Unlikely),
s => Some(Self::Unknown(s.to_string())),
}
}
pub fn is_valid_for(&self, decl_kind: &str) -> bool {
match self {
Self::Noreturn
| Self::CarriesDependency
| Self::Deprecated(_)
| Self::Nodiscard(_)
| Self::MaybeUnused
| Self::GnuNoreturn
| Self::GnuConst
| Self::GnuPure
| Self::GnuAlwaysInline
| Self::GnuNoinline
| Self::GnuHot
| Self::GnuCold
| Self::GnuUnused
| Self::GnuVisibility(_)
| Self::NoReturn => {
matches!(decl_kind, "function" | "function_template")
}
Self::Fallthrough => decl_kind == "statement",
Self::NoUniqueAddress
| Self::NoUniqueAddress20
| Self::GnuPacked
| Self::GnuAligned(_) => {
matches!(decl_kind, "class" | "struct" | "member" | "variable")
}
Self::Likely | Self::Unlikely => {
matches!(decl_kind, "statement" | "label")
}
Self::Assume(_) => matches!(decl_kind, "statement"),
Self::DllExport | Self::DllImport => {
matches!(decl_kind, "function" | "variable" | "class")
}
Self::Unknown(_) => true, }
}
pub fn affects_x86_codegen(&self) -> bool {
matches!(
self,
Self::Noreturn
| Self::GnuNoreturn
| Self::NoReturn
| Self::CarriesDependency
| Self::GnuConst
| Self::GnuPure
| Self::GnuAlwaysInline
| Self::GnuNoinline
| Self::GnuAligned(_)
| Self::GnuPacked
| Self::Likely
| Self::Unlikely
| Self::Assume(_)
| Self::DllExport
| Self::DllImport
)
}
pub fn to_gnu_attr(&self) -> Option<String> {
match self {
Self::Noreturn => Some("noreturn".into()),
Self::Deprecated(_) => Some("deprecated".into()),
Self::Nodiscard(_) => Some("warn_unused_result".into()),
Self::MaybeUnused => Some("unused".into()),
Self::NoUniqueAddress | Self::NoUniqueAddress20 => Some("no_unique_address".into()),
Self::Likely => Some("hot".into()),
Self::Unlikely => Some("cold".into()),
Self::GnuNoreturn => Some("noreturn".into()),
Self::GnuConst => Some("const".into()),
Self::GnuPure => Some("pure".into()),
Self::GnuAlwaysInline => Some("always_inline".into()),
Self::GnuNoinline => Some("noinline".into()),
Self::GnuHot => Some("hot".into()),
Self::GnuCold => Some("cold".into()),
Self::GnuPacked => Some("packed".into()),
Self::GnuAligned(n) => Some(format!("aligned({})", n)),
Self::GnuUnused => Some("unused".into()),
Self::GnuVisibility(v) => Some(format!("visibility(\"{}\")", v)),
_ => None,
}
}
pub fn is_compatible_with(&self, other: &CXXAttribute) -> bool {
if matches!(
(self, other),
(Self::Noreturn, Self::GnuNoreturn)
| (Self::GnuNoreturn, Self::Noreturn)
| (Self::NoReturn, Self::Noreturn)
| (Self::Noreturn, Self::NoReturn)
| (Self::NoUniqueAddress, Self::NoUniqueAddress20)
| (Self::NoUniqueAddress20, Self::NoUniqueAddress)
) {
return true;
}
if matches!(
(self, other),
(Self::Likely, Self::Unlikely) | (Self::Unlikely, Self::Likely)
) {
return false;
}
true
}
pub fn introduced_in(&self) -> &'static str {
match self {
Self::Noreturn | Self::CarriesDependency => "C++11",
Self::Deprecated(_) | Self::Fallthrough | Self::Nodiscard(_) | Self::MaybeUnused => {
"C++14/C++17"
}
Self::NoUniqueAddress | Self::NoUniqueAddress20 => "C++20",
Self::Likely | Self::Unlikely => "C++20",
Self::Assume(_) => "C++23",
Self::GnuNoreturn
| Self::GnuConst
| Self::GnuPure
| Self::GnuAlwaysInline
| Self::GnuNoinline
| Self::GnuHot
| Self::GnuCold
| Self::GnuPacked
| Self::GnuAligned(_)
| Self::GnuUnused
| Self::GnuVisibility(_) => "GNU extension",
Self::DllExport | Self::DllImport | Self::NoReturn => "MSVC extension",
Self::Unknown(_) => "unknown",
}
}
}
#[derive(Debug)]
pub struct CXXAttributeHandler {
pub standard: CXXStandardVersion,
pub parsed_attributes: Vec<CXXAttribute>,
pub attribute_map: HashMap<String, Vec<CXXAttribute>>, pub diagnostics: Vec<String>,
}
impl CXXAttributeHandler {
pub fn new(standard: CXXStandardVersion) -> Self {
Self {
standard,
parsed_attributes: Vec::new(),
attribute_map: HashMap::new(),
diagnostics: Vec::new(),
}
}
pub fn parse_and_register(&mut self, source: &str) -> Option<CXXAttribute> {
let attr = CXXAttribute::parse(source)?;
self.parsed_attributes.push(attr.clone());
Some(attr)
}
pub fn attach_to(&mut self, entity: impl Into<String>, attr: CXXAttribute) {
self.attribute_map
.entry(entity.into())
.or_insert_with(Vec::new)
.push(attr);
}
pub fn get_for(&self, entity: &str) -> Option<&[CXXAttribute]> {
self.attribute_map.get(entity).map(|v| v.as_slice())
}
pub fn has_attr(&self, entity: &str, attr: &CXXAttribute) -> bool {
self.attribute_map
.get(entity)
.map(|attrs| attrs.contains(attr))
.unwrap_or(false)
}
pub fn is_nodiscard(&self, entity: &str) -> bool {
self.attribute_map
.get(entity)
.map(|attrs| {
attrs
.iter()
.any(|a| matches!(a, CXXAttribute::Nodiscard(_)))
})
.unwrap_or(false)
}
pub fn is_deprecated(&self, entity: &str) -> Option<&str> {
self.attribute_map.get(entity).and_then(|attrs| {
attrs.iter().find_map(|a| match a {
CXXAttribute::Deprecated(msg) => Some(msg.as_deref().unwrap_or("")),
_ => None,
})
})
}
pub fn is_maybe_unused(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::MaybeUnused)
|| self.has_attr(entity, &CXXAttribute::GnuUnused)
}
pub fn has_no_unique_address(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::NoUniqueAddress)
|| self.has_attr(entity, &CXXAttribute::NoUniqueAddress20)
}
pub fn is_likely(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::Likely)
}
pub fn is_unlikely(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::Unlikely)
}
pub fn carries_dependency(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::CarriesDependency)
}
pub fn is_noreturn(&self, entity: &str) -> bool {
self.has_attr(entity, &CXXAttribute::Noreturn)
|| self.has_attr(entity, &CXXAttribute::GnuNoreturn)
|| self.has_attr(entity, &CXXAttribute::NoReturn)
}
pub fn validate_for(&self, entity: &str, decl_kind: &str) -> Vec<String> {
let mut errors = Vec::new();
if let Some(attrs) = self.attribute_map.get(entity) {
for attr in attrs {
if !attr.is_valid_for(decl_kind) {
errors.push(format!(
"attribute {} is not valid for {} '{}'",
attr, decl_kind, entity
));
}
}
for i in 0..attrs.len() {
for j in (i + 1)..attrs.len() {
if !attrs[i].is_compatible_with(&attrs[j]) {
errors.push(format!(
"conflicting attributes {} and {} on '{}'",
attrs[i], attrs[j], entity
));
}
}
}
}
errors
}
pub fn x86_codegen_hints(&self, entity: &str) -> Vec<String> {
let mut hints = Vec::new();
if let Some(attrs) = self.attribute_map.get(entity) {
for attr in attrs {
if attr.affects_x86_codegen() {
if let Some(gnu_attr) = attr.to_gnu_attr() {
hints.push(gnu_attr);
}
}
}
}
hints
}
pub fn attribute_count(&self) -> usize {
self.parsed_attributes.len()
}
pub fn attributed_entities(&self) -> Vec<&String> {
self.attribute_map.keys().collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LambdaCaptureKind {
ByValue,
ByReference,
ThisByValue,
ThisByReference,
StarThis,
InitCapture,
InitCaptureByRef,
}
impl fmt::Display for LambdaCaptureKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ByValue => write!(f, "="),
Self::ByReference => write!(f, "&"),
Self::ThisByValue => write!(f, "this"),
Self::ThisByReference => write!(f, "&this"),
Self::StarThis => write!(f, "*this"),
Self::InitCapture => write!(f, "init capture by value"),
Self::InitCaptureByRef => write!(f, "init capture by ref"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LambdaCaptureDefault {
None,
ByCopy,
ByReference,
}
impl fmt::Display for LambdaCaptureDefault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => write!(f, ""),
Self::ByCopy => write!(f, "="),
Self::ByReference => write!(f, "&"),
}
}
}
#[derive(Debug, Clone)]
pub struct ExtendedLambda {
pub capture_default: LambdaCaptureDefault,
pub explicit_captures: Vec<ExtendedLambdaCapture>,
pub template_params: Option<Vec<TemplateParamDecl>>,
pub parameters: Vec<(String, String)>, pub return_type: String,
pub body: String,
pub is_mutable: bool,
pub is_constexpr: bool,
pub is_consteval: bool,
pub is_noexcept: bool,
pub is_generic: bool,
pub is_template_lambda: bool,
pub requires_clause: Option<String>,
pub attributes: Vec<CXXAttribute>,
pub closure_class_name: String,
pub standard: CXXStandardVersion,
}
#[derive(Debug, Clone)]
pub struct ExtendedLambdaCapture {
pub name: String,
pub kind: LambdaCaptureKind,
pub init_expression: Option<String>,
pub is_implicit: bool,
pub is_pack_expansion: bool,
}
impl ExtendedLambdaCapture {
pub fn by_value(name: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: LambdaCaptureKind::ByValue,
init_expression: None,
is_implicit: false,
is_pack_expansion: false,
}
}
pub fn by_reference(name: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: LambdaCaptureKind::ByReference,
init_expression: None,
is_implicit: false,
is_pack_expansion: false,
}
}
pub fn this() -> Self {
Self {
name: "this".into(),
kind: LambdaCaptureKind::ThisByValue,
init_expression: None,
is_implicit: false,
is_pack_expansion: false,
}
}
pub fn star_this() -> Self {
Self {
name: "this".into(),
kind: LambdaCaptureKind::StarThis,
init_expression: None,
is_implicit: false,
is_pack_expansion: false,
}
}
pub fn init_capture(name: impl Into<String>, init: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: LambdaCaptureKind::InitCapture,
init_expression: Some(init.into()),
is_implicit: false,
is_pack_expansion: false,
}
}
pub fn init_capture_by_ref(name: impl Into<String>, init: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: LambdaCaptureKind::InitCaptureByRef,
init_expression: Some(init.into()),
is_implicit: false,
is_pack_expansion: false,
}
}
}
impl ExtendedLambda {
pub fn new(standard: CXXStandardVersion) -> Self {
Self {
capture_default: LambdaCaptureDefault::None,
explicit_captures: Vec::new(),
template_params: None,
parameters: Vec::new(),
return_type: "auto".into(),
body: String::new(),
is_mutable: false,
is_constexpr: false,
is_consteval: false,
is_noexcept: false,
is_generic: false,
is_template_lambda: false,
requires_clause: None,
attributes: Vec::new(),
closure_class_name: format!("__lambda_{}", next_lambda_id()),
standard,
}
}
pub fn with_capture_default(mut self, def: LambdaCaptureDefault) -> Self {
self.capture_default = def;
self
}
pub fn add_capture(mut self, cap: ExtendedLambdaCapture) -> Self {
self.explicit_captures.push(cap);
self
}
pub fn add_param(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
self.parameters.push((name.into(), ty.into()));
self
}
pub fn with_return_type(mut self, ty: impl Into<String>) -> Self {
self.return_type = ty.into();
self
}
pub fn with_body(mut self, body: impl Into<String>) -> Self {
self.body = body.into();
self
}
pub fn mutable(mut self) -> Self {
self.is_mutable = true;
self
}
pub fn constexpr_lambda(mut self) -> Self {
self.is_constexpr = true;
self
}
pub fn consteval_lambda(mut self) -> Self {
self.is_consteval = true;
self.is_constexpr = true;
self
}
pub fn generic(mut self) -> Self {
self.is_generic = true;
if self.standard.is_at_least(CXXStandardVersion::CXX14) {
}
self
}
pub fn with_template_params(mut self, params: Vec<TemplateParamDecl>) -> Self {
self.template_params = Some(params);
self.is_template_lambda = true;
self
}
pub fn with_requires(mut self, clause: impl Into<String>) -> Self {
self.requires_clause = Some(clause.into());
self
}
pub fn with_attribute(mut self, attr: CXXAttribute) -> Self {
self.attributes.push(attr);
self
}
pub fn is_stateless(&self) -> bool {
self.capture_default == LambdaCaptureDefault::None && self.explicit_captures.is_empty()
}
pub fn has_this_capture(&self) -> bool {
self.explicit_captures.iter().any(|c| {
matches!(
c.kind,
LambdaCaptureKind::ThisByValue
| LambdaCaptureKind::ThisByReference
| LambdaCaptureKind::StarThis
)
})
}
pub fn can_convert_to_fn_ptr(&self) -> bool {
self.is_stateless() && !self.is_generic && self.template_params.is_none()
}
pub fn validate_for_standard(&self) -> Result<(), String> {
if self.is_template_lambda && !self.standard.has_template_lambdas() {
return Err("template lambdas require C++20".into());
}
if self.is_consteval && !self.standard.has_consteval() {
return Err("consteval lambdas require C++20".into());
}
if self.requires_clause.is_some() && !self.standard.has_concepts() {
return Err("requires-clause on lambdas requires C++20".into());
}
for cap in &self.explicit_captures {
if cap.kind == LambdaCaptureKind::StarThis
&& !self.standard.is_at_least(CXXStandardVersion::CXX17)
{
return Err("[*this] capture requires C++17".into());
}
if cap.kind == LambdaCaptureKind::InitCapture
|| cap.kind == LambdaCaptureKind::InitCaptureByRef
{
if !self.standard.is_at_least(CXXStandardVersion::CXX14) {
return Err("init captures require C++14".into());
}
}
}
Ok(())
}
pub fn to_source(&self) -> String {
let mut s = String::new();
if self.is_constexpr && !self.is_consteval {
s.push_str("constexpr ");
}
if self.is_consteval {
s.push_str("consteval ");
}
s.push('[');
match self.capture_default {
LambdaCaptureDefault::ByCopy => s.push('='),
LambdaCaptureDefault::ByReference => s.push('&'),
LambdaCaptureDefault::None => {}
}
for (i, cap) in self.explicit_captures.iter().enumerate() {
if i > 0 || self.capture_default != LambdaCaptureDefault::None {
s.push_str(", ");
}
match cap.kind {
LambdaCaptureKind::ByValue => {
s.push_str(&cap.name);
}
LambdaCaptureKind::ByReference => {
s.push('&');
s.push_str(&cap.name);
}
LambdaCaptureKind::ThisByValue => s.push_str("this"),
LambdaCaptureKind::ThisByReference => s.push_str("&this"),
LambdaCaptureKind::StarThis => s.push_str("*this"),
LambdaCaptureKind::InitCapture => {
s.push_str(&cap.name);
if let Some(ref init) = cap.init_expression {
s.push_str(&format!(" = {}", init));
}
}
LambdaCaptureKind::InitCaptureByRef => {
s.push('&');
s.push_str(&cap.name);
if let Some(ref init) = cap.init_expression {
s.push_str(&format!(" = {}", init));
}
}
}
}
s.push_str("](");
for (i, (name, ty)) in self.parameters.iter().enumerate() {
if i > 0 {
s.push_str(", ");
}
s.push_str(&format!("{} {}", ty, name));
}
s.push(')');
if self.is_mutable {
s.push_str(" mutable");
}
if self.is_noexcept {
s.push_str(" noexcept");
}
if let Some(ref requires) = self.requires_clause {
s.push_str(&format!(" requires {}", requires));
}
s.push_str(" { ");
s.push_str(&self.body);
s.push_str(" }");
s
}
}
static mut LAMBDA_COUNTER: u64 = 0;
fn next_lambda_id() -> u64 {
unsafe {
LAMBDA_COUNTER += 1;
LAMBDA_COUNTER
}
}
#[derive(Debug, Clone)]
pub struct GenericLambdaTemplate {
pub template_params: Vec<TemplateParamDecl>,
pub call_operator_name: String,
pub is_abbreviated_function_template: bool,
}
impl GenericLambdaTemplate {
pub fn from_auto_params(params: &[(String, String)]) -> Option<Self> {
let auto_params: Vec<_> = params
.iter()
.filter(|(_, ty)| ty == "auto" || ty.starts_with("auto"))
.collect();
if auto_params.is_empty() {
return None;
}
let template_params: Vec<TemplateParamDecl> = auto_params
.iter()
.enumerate()
.map(|(i, (name, _))| TemplateParamDecl {
name: format!("__T{}", i),
has_default: false,
default_type: None,
is_parameter_pack: false,
})
.collect();
Some(Self {
template_params,
call_operator_name: "operator()".into(),
is_abbreviated_function_template: true,
})
}
pub fn num_template_params(&self) -> usize {
self.template_params.len()
}
}
#[derive(Debug, Clone)]
pub struct LambdaConversionOp {
pub target_function_type: String,
pub is_noexcept: bool,
pub is_constexpr: bool,
}
impl LambdaConversionOp {
pub fn new(return_type: impl Into<String>, param_types: &[String]) -> Self {
let params = param_types.join(", ");
let target = format!("{}(*)({})", return_type.into(), params);
Self {
target_function_type: target,
is_noexcept: false,
is_constexpr: false,
}
}
pub fn signature(&self) -> String {
format!(
"operator {}() const{}",
self.target_function_type,
if self.is_noexcept { " noexcept" } else { "" }
)
}
}
#[derive(Debug)]
pub struct CXXLambdaExtensions {
pub standard: CXXStandardVersion,
pub lambdas: Vec<ExtendedLambda>,
pub generic_templates: Vec<GenericLambdaTemplate>,
pub conversion_ops: Vec<LambdaConversionOp>,
pub diagnostics: Vec<String>,
}
impl CXXLambdaExtensions {
pub fn new(standard: CXXStandardVersion) -> Self {
Self {
standard,
lambdas: Vec::new(),
generic_templates: Vec::new(),
conversion_ops: Vec::new(),
diagnostics: Vec::new(),
}
}
pub fn register_lambda(&mut self, lambda: ExtendedLambda) {
if lambda.is_generic {
if let Some(gt) = GenericLambdaTemplate::from_auto_params(&lambda.parameters) {
self.generic_templates.push(gt);
}
}
if lambda.can_convert_to_fn_ptr() {
let param_types: Vec<String> =
lambda.parameters.iter().map(|(_, t)| t.clone()).collect();
self.conversion_ops
.push(LambdaConversionOp::new(&lambda.return_type, ¶m_types));
}
self.lambdas.push(lambda);
}
pub fn supports(&self, feature: &str) -> bool {
match feature {
"generic_lambda" => self.standard.is_at_least(CXXStandardVersion::CXX14),
"init_capture" => self.standard.is_at_least(CXXStandardVersion::CXX14),
"constexpr_lambda" => self.standard.is_at_least(CXXStandardVersion::CXX17),
"star_this_capture" => self.standard.is_at_least(CXXStandardVersion::CXX17),
"template_lambda" => self.standard.is_at_least(CXXStandardVersion::CXX20),
"consteval_lambda" => self.standard.is_at_least(CXXStandardVersion::CXX20),
"lambda_requires" => self.standard.is_at_least(CXXStandardVersion::CXX20),
"lambda_attributes" => self.standard.is_at_least(CXXStandardVersion::CXX11),
_ => false,
}
}
pub fn lambda_count(&self) -> usize {
self.lambdas.len()
}
pub fn generic_template_count(&self) -> usize {
self.generic_templates.len()
}
pub fn conversion_op_count(&self) -> usize {
self.conversion_ops.len()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConstexprMode {
Constexpr,
Consteval,
Constinit,
Runtime,
}
impl fmt::Display for ConstexprMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Constexpr => write!(f, "constexpr"),
Self::Consteval => write!(f, "consteval"),
Self::Constinit => write!(f, "constinit"),
Self::Runtime => write!(f, "runtime"),
}
}
}
#[derive(Debug, Clone)]
pub struct ConstexprVirtualFunction {
pub name: String,
pub class_name: String,
pub is_override: bool,
pub is_final: bool,
pub is_pure_virtual: bool,
pub vtable_index: u32,
pub return_type: String,
}
impl ConstexprVirtualFunction {
pub fn new(name: impl Into<String>, class_name: impl Into<String>) -> Self {
Self {
name: name.into(),
class_name: class_name.into(),
is_override: false,
is_final: false,
is_pure_virtual: false,
vtable_index: 0,
return_type: "auto".into(),
}
}
pub fn validate(&self) -> Result<(), String> {
if self.is_pure_virtual {
return Err(format!(
"pure virtual function '{}' cannot be constexpr",
self.name
));
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct ConstexprTryCatch {
pub is_constexpr: bool,
pub catch_types: Vec<String>,
pub can_be_constexpr: bool,
pub catch_all_handler: bool,
}
impl ConstexprTryCatch {
pub fn new() -> Self {
Self {
is_constexpr: false,
catch_types: Vec::new(),
can_be_constexpr: true,
catch_all_handler: false,
}
}
pub fn add_catch(&mut self, ty: impl Into<String>) {
let t = ty.into();
if t == "..." {
self.catch_all_handler = true;
} else {
self.catch_types.push(t);
}
}
pub fn validate(&self) -> Result<(), String> {
if self.is_constexpr && self.catch_all_handler {
if !self.catch_types.is_empty() {
return Ok(());
}
}
Ok(())
}
}
impl Default for ConstexprTryCatch {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ConstexprDynamicCast {
pub src_type: String,
pub dst_type: String,
pub is_downcast: bool,
pub is_crosscast: bool,
pub is_to_void: bool,
}
impl ConstexprDynamicCast {
pub fn new(src: impl Into<String>, dst: impl Into<String>) -> Self {
let src = src.into();
let dst = dst.into();
Self {
src_type: src,
dst_type: dst.clone(),
is_downcast: false,
is_crosscast: false,
is_to_void: dst == "void",
}
}
pub fn validate(&self) -> Result<(), String> {
if self.is_to_void {
return Ok(()); }
if self.is_downcast && self.is_crosscast {
return Err("dynamic_cast cannot be both downcast and crosscast".into());
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct ConstexprNewDelete {
pub allocation_size: u64,
pub alignment: u32,
pub is_placement: bool,
pub placement_address: Option<String>,
pub constructed_type: String,
pub is_array: bool,
pub element_count: Option<u64>,
}
impl ConstexprNewDelete {
pub fn new_expression(ty: impl Into<String>, size: u64, align: u32) -> Self {
Self {
allocation_size: size,
alignment: align,
is_placement: false,
placement_address: None,
constructed_type: ty.into(),
is_array: false,
element_count: None,
}
}
pub fn placement(ty: impl Into<String>, address: impl Into<String>, size: u64) -> Self {
Self {
allocation_size: size,
alignment: 0,
is_placement: true,
placement_address: Some(address.into()),
constructed_type: ty.into(),
is_array: false,
element_count: None,
}
}
pub fn validate(&self) -> Result<(), String> {
if self.is_placement && self.placement_address.is_none() {
return Err("placement new requires an address".into());
}
if self.is_array && self.element_count.is_none() {
return Err("array new requires an element count".into());
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct ExtendedConstexprContext {
pub mode: ConstexprMode,
pub call_depth: u32,
pub max_call_depth: u32,
pub in_virtual_call: bool,
pub in_try_catch: bool,
pub in_dynamic_cast: bool,
pub in_new_delete: bool,
pub diagnostics: Vec<String>,
}
impl ExtendedConstexprContext {
pub fn new(mode: ConstexprMode) -> Self {
Self {
mode,
call_depth: 0,
max_call_depth: 512,
in_virtual_call: false,
in_try_catch: false,
in_dynamic_cast: false,
in_new_delete: false,
diagnostics: Vec::new(),
}
}
pub fn enter_call(&mut self) -> Result<(), String> {
self.call_depth += 1;
if self.call_depth > self.max_call_depth {
return Err("constexpr evaluation hit recursion limit".into());
}
Ok(())
}
pub fn leave_call(&mut self) {
if self.call_depth > 0 {
self.call_depth -= 1;
}
}
pub fn is_consteval(&self) -> bool {
self.mode == ConstexprMode::Consteval
}
pub fn is_constexpr(&self) -> bool {
matches!(
self.mode,
ConstexprMode::Constexpr | ConstexprMode::Consteval
)
}
}
#[derive(Debug, Clone)]
pub struct ImmediateFunction {
pub name: String,
pub return_type: String,
pub params: Vec<(String, String)>,
pub body: String,
pub is_defined: bool,
}
impl ImmediateFunction {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
return_type: "auto".into(),
params: Vec::new(),
body: String::new(),
is_defined: false,
}
}
pub fn with_body(mut self, body: impl Into<String>) -> Self {
self.body = body.into();
self.is_defined = true;
self
}
pub fn validate(&self) -> Result<(), String> {
if !self.is_defined {
return Err(format!(
"consteval function '{}' must be defined before use",
self.name
));
}
Ok(())
}
}
#[derive(Debug)]
pub struct CXXConstexprExtensions {
pub standard: CXXStandardVersion,
pub context: ExtendedConstexprContext,
pub virtual_functions: Vec<ConstexprVirtualFunction>,
pub try_catches: Vec<ConstexprTryCatch>,
pub dynamic_casts: Vec<ConstexprDynamicCast>,
pub new_deletes: Vec<ConstexprNewDelete>,
pub immediate_functions: Vec<ImmediateFunction>,
pub evaluator: Option<ConstExprEvaluator>,
pub diagnostics: Vec<String>,
}
impl CXXConstexprExtensions {
pub fn new(standard: CXXStandardVersion) -> Self {
let evaluator = Some(ConstExprEvaluator::new(match standard {
CXXStandardVersion::CXX98 | CXXStandardVersion::CXX03 => CLangStandard::C99,
CXXStandardVersion::CXX11 | CXXStandardVersion::CXX14 => CLangStandard::C11,
CXXStandardVersion::CXX17 => CLangStandard::C17,
CXXStandardVersion::CXX20 | CXXStandardVersion::CXX23 | CXXStandardVersion::CXX26 => {
CLangStandard::C23
}
}));
Self {
standard,
context: ExtendedConstexprContext::new(ConstexprMode::Constexpr),
virtual_functions: Vec::new(),
try_catches: Vec::new(),
dynamic_casts: Vec::new(),
new_deletes: Vec::new(),
immediate_functions: Vec::new(),
evaluator,
diagnostics: Vec::new(),
}
}
pub fn register_constexpr_virtual(&mut self, vf: ConstexprVirtualFunction) {
self.virtual_functions.push(vf);
}
pub fn register_constexpr_try_catch(&mut self, tc: ConstexprTryCatch) {
self.try_catches.push(tc);
}
pub fn register_constexpr_dynamic_cast(&mut self, dc: ConstexprDynamicCast) {
self.dynamic_casts.push(dc);
}
pub fn register_constexpr_new_delete(&mut self, nd: ConstexprNewDelete) {
self.new_deletes.push(nd);
}
pub fn register_immediate_fn(&mut self, imf: ImmediateFunction) {
self.immediate_functions.push(imf);
}
pub fn supports(&self, feature: &str) -> bool {
match feature {
"constexpr_virtual" => self.standard.has_constexpr_virtual(),
"constexpr_dtor" => self.standard.has_constexpr_dtor(),
"constexpr_try_catch" => self.standard.has_constexpr_try_catch(),
"constexpr_dynamic_cast" => {
self.standard.has_constexpr_virtual() && self.standard.has_constexpr_dtor()
}
"constexpr_new_delete" => self.standard.is_at_least(CXXStandardVersion::CXX20),
"constexpr_placement_new" => self.standard.has_constexpr_placement_new(),
"consteval" => self.standard.is_at_least(CXXStandardVersion::CXX20),
"constinit" => self.standard.is_at_least(CXXStandardVersion::CXX20),
_ => false,
}
}
pub fn virtual_function_count(&self) -> usize {
self.virtual_functions.len()
}
pub fn immediate_function_count(&self) -> usize {
self.immediate_functions.len()
}
pub fn set_consteval_mode(&mut self) {
self.context.mode = ConstexprMode::Consteval;
}
pub fn set_constexpr_mode(&mut self) {
self.context.mode = ConstexprMode::Constexpr;
}
pub fn is_in_immediate_context(&self) -> bool {
self.context.is_consteval()
}
}
#[derive(Debug, Clone)]
pub struct X86CXXCodeGenConfig {
pub target_triple: String,
pub cpu: String,
pub features: Vec<String>,
pub opt_level: u32,
pub code_model: X86CodeModel,
pub reloc_model: X86RelocModel,
pub stack_protector: u32,
pub enable_vectorize: bool,
pub omit_frame_pointer: bool,
pub exception_model: X86ExceptionModel,
pub tls_model: X86TLSModel,
pub debug_info: X86DebugInfo,
pub is_pic: bool,
pub integrated_as: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86CodeModel {
Small,
Kernel,
Medium,
Large,
Tiny,
}
impl Default for X86CodeModel {
fn default() -> Self {
Self::Small
}
}
impl X86CodeModel {
pub fn as_str(&self) -> &'static str {
match self {
Self::Small => "small",
Self::Kernel => "kernel",
Self::Medium => "medium",
Self::Large => "large",
Self::Tiny => "tiny",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86RelocModel {
Static,
Pic,
DynamicNoPic,
Ropi,
Rwpi,
RopiRwpi,
}
impl Default for X86RelocModel {
fn default() -> Self {
Self::Static
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ExceptionModel {
None,
Dwarf,
SjLj,
SEH,
Wasm,
}
impl Default for X86ExceptionModel {
fn default() -> Self {
Self::Dwarf
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSModel {
GeneralDynamic,
LocalDynamic,
InitialExec,
LocalExec,
}
impl Default for X86TLSModel {
fn default() -> Self {
Self::GeneralDynamic
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86DebugInfo {
None,
LineTablesOnly,
Full,
Limited,
}
impl Default for X86DebugInfo {
fn default() -> Self {
Self::None
}
}
impl Default for X86CXXCodeGenConfig {
fn default() -> Self {
Self {
target_triple: "x86_64-unknown-linux-gnu".into(),
cpu: "generic".into(),
features: vec!["sse2".into(), "cmov".into()],
opt_level: 2,
code_model: X86CodeModel::default(),
reloc_model: X86RelocModel::default(),
stack_protector: 0,
enable_vectorize: true,
omit_frame_pointer: true,
exception_model: X86ExceptionModel::default(),
tls_model: X86TLSModel::default(),
debug_info: X86DebugInfo::default(),
is_pic: false,
integrated_as: true,
}
}
}
impl X86CXXCodeGenConfig {
pub fn for_skylake() -> Self {
Self {
cpu: "skylake".into(),
features: vec![
"sse2".into(),
"sse4.2".into(),
"avx".into(),
"avx2".into(),
"bmi".into(),
"bmi2".into(),
"fma".into(),
"cmov".into(),
"popcnt".into(),
],
..Default::default()
}
}
pub fn for_znver4() -> Self {
Self {
cpu: "znver4".into(),
features: vec![
"sse2".into(),
"sse4.2".into(),
"avx".into(),
"avx2".into(),
"avx512f".into(),
"avx512dq".into(),
"avx512bw".into(),
"avx512vl".into(),
"bmi".into(),
"bmi2".into(),
"fma".into(),
"cmov".into(),
],
..Default::default()
}
}
pub fn for_x86_64_v2() -> Self {
Self {
cpu: "x86-64-v2".into(),
features: vec![
"sse3".into(),
"sse4.1".into(),
"sse4.2".into(),
"ssse3".into(),
"popcnt".into(),
"cx16".into(),
"cmov".into(),
],
..Default::default()
}
}
pub fn for_x86_64_v3() -> Self {
Self {
cpu: "x86-64-v3".into(),
features: vec![
"avx".into(),
"avx2".into(),
"bmi".into(),
"bmi2".into(),
"f16c".into(),
"fma".into(),
"lzcnt".into(),
"movbe".into(),
"xsave".into(),
"cmov".into(),
],
..Default::default()
}
}
pub fn has_feature(&self, feature: &str) -> bool {
self.features.iter().any(|f| f == feature)
}
pub fn add_feature(&mut self, feature: impl Into<String>) {
let f = feature.into();
if !self.has_feature(&f) {
self.features.push(f);
}
}
pub fn remove_feature(&mut self, feature: &str) {
self.features.retain(|f| f != feature);
}
}
#[derive(Debug, Clone)]
pub struct X86CXXLoweringInfo {
pub pointer_size: u32,
pub pointer_alignment: u32,
pub size_t_size: u32,
pub vtable_ptr_size: u32,
pub rtti_ptr_size: u32,
pub personality_fn: String,
pub default_member_cc: X86MemberCallingConvention,
pub has_red_zone: bool,
pub red_zone_size: u32,
pub stack_alignment: u32,
pub supports_tls: bool,
pub mangling: X86ManglingScheme,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86MemberCallingConvention {
ThisCall,
CDecl,
FastCall,
VectorCall,
SysVAmd64,
MicrosoftX64,
}
impl Default for X86MemberCallingConvention {
fn default() -> Self {
Self::SysVAmd64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ManglingScheme {
Itanium,
Microsoft,
}
impl Default for X86ManglingScheme {
fn default() -> Self {
Self::Itanium
}
}
impl Default for X86CXXLoweringInfo {
fn default() -> Self {
Self {
pointer_size: 8,
pointer_alignment: 8,
size_t_size: 8,
vtable_ptr_size: 8,
rtti_ptr_size: 8,
personality_fn: "__gxx_personality_v0".into(),
default_member_cc: X86MemberCallingConvention::SysVAmd64,
has_red_zone: true,
red_zone_size: 128,
stack_alignment: 16,
supports_tls: true,
mangling: X86ManglingScheme::Itanium,
}
}
}
impl X86CXXLoweringInfo {
pub fn for_x86_64_linux() -> Self {
Self {
pointer_size: 8,
pointer_alignment: 8,
size_t_size: 8,
vtable_ptr_size: 8,
rtti_ptr_size: 8,
personality_fn: "__gxx_personality_v0".into(),
default_member_cc: X86MemberCallingConvention::SysVAmd64,
has_red_zone: true,
red_zone_size: 128,
stack_alignment: 16,
supports_tls: true,
mangling: X86ManglingScheme::Itanium,
}
}
pub fn for_x86_64_windows() -> Self {
Self {
pointer_size: 8,
pointer_alignment: 8,
size_t_size: 8,
vtable_ptr_size: 8,
rtti_ptr_size: 8,
personality_fn: "__CxxFrameHandler3".into(),
default_member_cc: X86MemberCallingConvention::MicrosoftX64,
has_red_zone: false,
red_zone_size: 0,
stack_alignment: 16,
supports_tls: true,
mangling: X86ManglingScheme::Microsoft,
}
}
pub fn for_x86_32_linux() -> Self {
Self {
pointer_size: 4,
pointer_alignment: 4,
size_t_size: 4,
vtable_ptr_size: 4,
rtti_ptr_size: 4,
personality_fn: "__gxx_personality_v0".into(),
default_member_cc: X86MemberCallingConvention::CDecl,
has_red_zone: false,
red_zone_size: 0,
stack_alignment: 16,
supports_tls: true,
mangling: X86ManglingScheme::Itanium,
}
}
}
#[derive(Debug, Clone)]
pub struct X86CXXIntrinsicMap {
pub intrinsics: HashMap<String, X86IntrinsicInfo>,
}
#[derive(Debug, Clone)]
pub struct X86IntrinsicInfo {
pub llvm_name: String,
pub return_type: String,
pub param_types: Vec<String>,
pub requires_feature: Option<String>,
pub is_const: bool,
pub is_pure: bool,
}
impl X86CXXIntrinsicMap {
pub fn new() -> Self {
let mut intrinsics = HashMap::new();
intrinsics.insert(
"_mm_pause".into(),
X86IntrinsicInfo {
llvm_name: "llvm.x86.sse2.pause".into(),
return_type: "void".into(),
param_types: vec![],
requires_feature: Some("sse2".into()),
is_const: false,
is_pure: false,
},
);
intrinsics.insert(
"__rdtsc".into(),
X86IntrinsicInfo {
llvm_name: "llvm.x86.rdtsc".into(),
return_type: "i64".into(),
param_types: vec![],
requires_feature: None,
is_const: false,
is_pure: false,
},
);
intrinsics.insert(
"__builtin_ia32_lzcnt_u32".into(),
X86IntrinsicInfo {
llvm_name: "llvm.ctlz.i32".into(),
return_type: "i32".into(),
param_types: vec!["i32".into()],
requires_feature: Some("lzcnt".into()),
is_const: true,
is_pure: true,
},
);
intrinsics.insert(
"__builtin_ia32_lzcnt_u64".into(),
X86IntrinsicInfo {
llvm_name: "llvm.ctlz.i64".into(),
return_type: "i64".into(),
param_types: vec!["i64".into()],
requires_feature: Some("lzcnt".into()),
is_const: true,
is_pure: true,
},
);
Self { intrinsics }
}
pub fn lookup(&self, name: &str) -> Option<&X86IntrinsicInfo> {
self.intrinsics.get(name)
}
pub fn is_available_for_cpu(&self, name: &str, cpu_features: &[String]) -> bool {
if let Some(info) = self.intrinsics.get(name) {
match &info.requires_feature {
Some(feat) => cpu_features.iter().any(|f| f == feat),
None => true,
}
} else {
false
}
}
pub fn intrinsic_count(&self) -> usize {
self.intrinsics.len()
}
}
impl Default for X86CXXIntrinsicMap {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct X86AggregatePassing {
pub classifications: Vec<X86ArgClass>,
pub passed_in_regs: bool,
pub reg_assignments: Vec<X86RegAssignment>,
pub uses_sret: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ArgClass {
NoClass,
Integer,
Sse,
SseUp,
X87,
X87Up,
ComplexX87,
Memory,
}
impl X86ArgClass {
pub fn as_str(&self) -> &'static str {
match self {
Self::NoClass => "NoClass",
Self::Integer => "Integer",
Self::Sse => "SSE",
Self::SseUp => "SSEUp",
Self::X87 => "X87",
Self::X87Up => "X87Up",
Self::ComplexX87 => "ComplexX87",
Self::Memory => "Memory",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct X86RegAssignment {
pub reg_name: String,
pub offset: u32,
pub size: u32,
}
impl X86RegAssignment {
pub fn new(reg: impl Into<String>, offset: u32, size: u32) -> Self {
Self {
reg_name: reg.into(),
offset,
size,
}
}
}
impl X86AggregatePassing {
pub fn new() -> Self {
Self {
classifications: Vec::new(),
passed_in_regs: false,
reg_assignments: Vec::new(),
uses_sret: false,
}
}
pub fn classify_sysv_amd64(size: u32) -> Self {
let num_eightbytes = (size + 7) / 8;
let mut result = Self::new();
if num_eightbytes <= 2 && size <= 16 {
result.passed_in_regs = true;
for i in 0..num_eightbytes {
result.classifications.push(X86ArgClass::Integer);
result.reg_assignments.push(X86RegAssignment::new(
if i == 0 { "%rdi" } else { "%rsi" },
i * 8,
8,
));
}
} else {
result.classifications.push(X86ArgClass::Memory);
}
result
}
pub fn requires_sret(size: u32) -> bool {
size > 16
}
}
impl Default for X86AggregatePassing {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContractKind {
Precondition,
Postcondition,
Assertion,
PreconditionAudit,
PostconditionAudit,
AssertionAudit,
}
impl fmt::Display for ContractKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Precondition => write!(f, "pre"),
Self::Postcondition => write!(f, "post"),
Self::Assertion => write!(f, "assert"),
Self::PreconditionAudit => write!(f, "pre(audit)"),
Self::PostconditionAudit => write!(f, "post(audit)"),
Self::AssertionAudit => write!(f, "assert(audit)"),
}
}
}
impl ContractKind {
pub fn is_audit(&self) -> bool {
matches!(
self,
Self::PreconditionAudit | Self::PostconditionAudit | Self::AssertionAudit
)
}
pub fn is_precondition(&self) -> bool {
matches!(self, Self::Precondition | Self::PreconditionAudit)
}
pub fn is_postcondition(&self) -> bool {
matches!(self, Self::Postcondition | Self::PostconditionAudit)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContractSemantic {
Default,
Audit,
Axiom,
}
impl ContractSemantic {
pub fn is_checked_at_runtime(&self) -> bool {
matches!(self, Self::Default | Self::Audit)
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"default" => Some(Self::Default),
"audit" => Some(Self::Audit),
"axiom" => Some(Self::Axiom),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContractBuildLevel {
Off,
Default,
Audit,
}
impl Default for ContractBuildLevel {
fn default() -> Self {
Self::Default
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContractContinuationMode {
NeverContinue,
MaybeContinue,
AlwaysContinue,
}
impl fmt::Display for ContractContinuationMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NeverContinue => write!(f, "never"),
Self::MaybeContinue => write!(f, "maybe"),
Self::AlwaysContinue => write!(f, "always"),
}
}
}
#[derive(Debug, Clone)]
pub struct ContractAnnotation {
pub kind: ContractKind,
pub semantic: ContractSemantic,
pub predicate: String,
pub result_identifier: Option<String>,
pub line: u32,
pub column: u32,
pub continuation: ContractContinuationMode,
}
impl ContractAnnotation {
pub fn precondition(predicate: impl Into<String>) -> Self {
Self {
kind: ContractKind::Precondition,
semantic: ContractSemantic::Default,
predicate: predicate.into(),
result_identifier: None,
line: 0,
column: 0,
continuation: ContractContinuationMode::NeverContinue,
}
}
pub fn postcondition(predicate: impl Into<String>, result_id: impl Into<String>) -> Self {
Self {
kind: ContractKind::Postcondition,
semantic: ContractSemantic::Default,
predicate: predicate.into(),
result_identifier: Some(result_id.into()),
line: 0,
column: 0,
continuation: ContractContinuationMode::NeverContinue,
}
}
pub fn assertion(predicate: impl Into<String>) -> Self {
Self {
kind: ContractKind::Assertion,
semantic: ContractSemantic::Default,
predicate: predicate.into(),
result_identifier: None,
line: 0,
column: 0,
continuation: ContractContinuationMode::NeverContinue,
}
}
pub fn with_continuation(mut self, mode: ContractContinuationMode) -> Self {
self.continuation = mode;
self
}
pub fn audit(mut self) -> Self {
self.semantic = ContractSemantic::Audit;
self.kind = match self.kind {
ContractKind::Precondition => ContractKind::PreconditionAudit,
ContractKind::Postcondition => ContractKind::PostconditionAudit,
ContractKind::Assertion => ContractKind::AssertionAudit,
other => other,
};
self
}
}
#[derive(Debug, Clone)]
pub struct FunctionContracts {
pub function_name: String,
pub preconditions: Vec<ContractAnnotation>,
pub postconditions: Vec<ContractAnnotation>,
pub assertions: Vec<ContractAnnotation>,
pub violation_handler: Option<String>,
}
impl FunctionContracts {
pub fn new(function_name: impl Into<String>) -> Self {
Self {
function_name: function_name.into(),
preconditions: Vec::new(),
postconditions: Vec::new(),
assertions: Vec::new(),
violation_handler: None,
}
}
pub fn add_precondition(&mut self, contract: ContractAnnotation) {
self.preconditions.push(contract);
}
pub fn add_postcondition(&mut self, contract: ContractAnnotation) {
self.postconditions.push(contract);
}
pub fn add_assertion(&mut self, contract: ContractAnnotation) {
self.assertions.push(contract);
}
pub fn total_count(&self) -> usize {
self.preconditions.len() + self.postconditions.len() + self.assertions.len()
}
pub fn has_audit_contracts(&self) -> bool {
self.preconditions.iter().any(|c| c.kind.is_audit())
|| self.postconditions.iter().any(|c| c.kind.is_audit())
|| self.assertions.iter().any(|c| c.kind.is_audit())
}
}
#[derive(Debug, Clone)]
pub struct ContractViolationHandler {
pub name: String,
pub terminates: bool,
pub logs_violation: bool,
pub custom_code: Option<String>,
}
impl ContractViolationHandler {
pub fn default_handler() -> Self {
Self {
name: "__contract_violation_default".into(),
terminates: true,
logs_violation: true,
custom_code: None,
}
}
pub fn log_only() -> Self {
Self {
name: "__contract_violation_log".into(),
terminates: false,
logs_violation: true,
custom_code: None,
}
}
pub fn custom(name: impl Into<String>, code: impl Into<String>) -> Self {
Self {
name: name.into(),
terminates: false,
logs_violation: false,
custom_code: Some(code.into()),
}
}
}
#[derive(Debug, Clone)]
pub struct ContractBuildConfig {
pub build_level: ContractBuildLevel,
pub violation_handler: ContractViolationHandler,
pub default_continuation: ContractContinuationMode,
pub enable_assertions: bool,
}
impl Default for ContractBuildConfig {
fn default() -> Self {
Self {
build_level: ContractBuildLevel::Default,
violation_handler: ContractViolationHandler::default_handler(),
default_continuation: ContractContinuationMode::NeverContinue,
enable_assertions: true,
}
}
}
impl ContractBuildConfig {
pub fn with_audit(mut self) -> Self {
self.build_level = ContractBuildLevel::Audit;
self
}
pub fn off(mut self) -> Self {
self.build_level = ContractBuildLevel::Off;
self.enable_assertions = false;
self
}
pub fn should_evaluate(&self, contract: &ContractAnnotation) -> bool {
match self.build_level {
ContractBuildLevel::Off => false,
ContractBuildLevel::Default => !contract.kind.is_audit(),
ContractBuildLevel::Audit => true,
}
}
}
#[derive(Debug, Clone)]
pub enum MatchPattern {
Wildcard,
Binding(String),
Literal(MatchLiteral),
Destructure(Vec<MatchPattern>),
Alternative(Vec<MatchPattern>),
Guard {
pattern: Box<MatchPattern>,
condition: String,
},
TypePattern {
type_name: String,
binding: Option<String>,
},
StructuredBinding(Vec<MatchPattern>),
Variant {
variant_name: String,
inner: Option<Box<MatchPattern>>,
},
Optional {
some_binding: Option<String>,
none: bool,
},
Range {
lower: Box<MatchPattern>,
upper: Box<MatchPattern>,
},
}
#[derive(Debug, Clone)]
pub enum MatchLiteral {
Integer(i64),
Float(f64),
Boolean(bool),
String(String),
Char(char),
Nullptr,
}
impl fmt::Display for MatchLiteral {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Integer(n) => write!(f, "{}", n),
Self::Float(n) => write!(f, "{}", n),
Self::Boolean(b) => write!(f, "{}", b),
Self::String(s) => write!(f, "\"{}\"", s),
Self::Char(c) => write!(f, "'{}'", c),
Self::Nullptr => write!(f, "nullptr"),
}
}
}
impl MatchPattern {
pub fn wildcard() -> Self {
Self::Wildcard
}
pub fn binding(name: impl Into<String>) -> Self {
Self::Binding(name.into())
}
pub fn integer(n: i64) -> Self {
Self::Literal(MatchLiteral::Integer(n))
}
pub fn bool_literal(b: bool) -> Self {
Self::Literal(MatchLiteral::Boolean(b))
}
pub fn string_literal(s: impl Into<String>) -> Self {
Self::Literal(MatchLiteral::String(s.into()))
}
pub fn type_pattern(ty: impl Into<String>) -> Self {
Self::TypePattern {
type_name: ty.into(),
binding: None,
}
}
pub fn type_with_binding(ty: impl Into<String>, name: impl Into<String>) -> Self {
Self::TypePattern {
type_name: ty.into(),
binding: Some(name.into()),
}
}
pub fn to_string_repr(&self) -> String {
match self {
Self::Wildcard => "_".into(),
Self::Binding(name) => name.clone(),
Self::Literal(lit) => lit.to_string(),
Self::Destructure(patterns) => {
let inner: Vec<String> = patterns.iter().map(|p| p.to_string_repr()).collect();
format!("[{}]", inner.join(", "))
}
Self::Alternative(patterns) => {
let inner: Vec<String> = patterns.iter().map(|p| p.to_string_repr()).collect();
inner.join(" | ")
}
Self::Guard { pattern, condition } => {
format!("{} if {}", pattern.to_string_repr(), condition)
}
Self::TypePattern { type_name, binding } => {
if let Some(ref b) = binding {
format!("{} {}", type_name, b)
} else {
type_name.clone()
}
}
Self::StructuredBinding(patterns) => {
let inner: Vec<String> = patterns.iter().map(|p| p.to_string_repr()).collect();
format!("[{}]", inner.join(", "))
}
Self::Variant {
variant_name,
inner,
} => {
if let Some(ref p) = inner {
format!("{}::({})", variant_name, p.to_string_repr())
} else {
variant_name.clone()
}
}
Self::Optional {
some_binding,
none: _,
} => {
if let Some(ref b) = some_binding {
format!("?{}", b)
} else {
"?_".into()
}
}
Self::Range { lower, upper } => {
format!("{}..{}", lower.to_string_repr(), upper.to_string_repr())
}
}
}
pub fn is_irrefutable(&self) -> bool {
matches!(self, Self::Wildcard | Self::Binding(_))
}
}
#[derive(Debug, Clone)]
pub struct InspectCase {
pub pattern: MatchPattern,
pub guard: Option<String>,
pub body: String,
pub is_terminating: bool,
}
impl InspectCase {
pub fn new(pattern: MatchPattern, body: impl Into<String>) -> Self {
Self {
pattern,
guard: None,
body: body.into(),
is_terminating: false,
}
}
pub fn with_guard(mut self, guard: impl Into<String>) -> Self {
self.guard = Some(guard.into());
self
}
}
#[derive(Debug, Clone)]
pub struct InspectExpression {
pub scrutinee: String,
pub scrutinee_type: String,
pub cases: Vec<InspectCase>,
pub result_type: String,
pub is_exhaustive: bool,
}
impl InspectExpression {
pub fn new(scrutinee: impl Into<String>, ty: impl Into<String>) -> Self {
Self {
scrutinee: scrutinee.into(),
scrutinee_type: ty.into(),
cases: Vec::new(),
result_type: "auto".into(),
is_exhaustive: false,
}
}
pub fn add_case(&mut self, case: InspectCase) {
self.cases.push(case);
}
pub fn check_exhaustiveness(&mut self) -> ExhaustivenessResult {
let has_wildcard = self
.cases
.iter()
.any(|c| matches!(c.pattern, MatchPattern::Wildcard));
if has_wildcard {
self.is_exhaustive = true;
ExhaustivenessResult::Exhaustive
} else {
ExhaustivenessResult::NonExhaustive {
missing: vec!["some patterns not covered".into()],
}
}
}
pub fn case_count(&self) -> usize {
self.cases.len()
}
}
#[derive(Debug, Clone)]
pub enum ExhaustivenessResult {
Exhaustive,
NonExhaustive { missing: Vec<String> },
}
#[derive(Debug, Clone)]
pub struct MetaInfo {
pub handle: String,
pub entity_kind: MetaEntityKind,
pub source_file: String,
pub source_line: u32,
pub display_name: String,
}
impl MetaInfo {
pub fn new(
handle: impl Into<String>,
kind: MetaEntityKind,
display_name: impl Into<String>,
) -> Self {
Self {
handle: handle.into(),
entity_kind: kind,
source_file: String::new(),
source_line: 0,
display_name: display_name.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetaEntityKind {
Type,
Variable,
Function,
MemberFunction,
Namespace,
Template,
Concept,
Expression,
Statement,
Enum,
EnumValue,
Class,
Struct,
Union,
BaseClass,
DataMember,
Parameter,
Lambda,
Alias,
NamespaceAlias,
}
impl fmt::Display for MetaEntityKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Type => write!(f, "type"),
Self::Variable => write!(f, "variable"),
Self::Function => write!(f, "function"),
Self::MemberFunction => write!(f, "member_function"),
Self::Namespace => write!(f, "namespace"),
Self::Template => write!(f, "template"),
Self::Concept => write!(f, "concept"),
Self::Expression => write!(f, "expression"),
Self::Statement => write!(f, "statement"),
Self::Enum => write!(f, "enum"),
Self::EnumValue => write!(f, "enum_value"),
Self::Class => write!(f, "class"),
Self::Struct => write!(f, "struct"),
Self::Union => write!(f, "union"),
Self::BaseClass => write!(f, "base_class"),
Self::DataMember => write!(f, "data_member"),
Self::Parameter => write!(f, "parameter"),
Self::Lambda => write!(f, "lambda"),
Self::Alias => write!(f, "alias"),
Self::NamespaceAlias => write!(f, "namespace_alias"),
}
}
}
#[derive(Debug, Clone)]
pub struct ReflectionOperator {
pub entity_name: String,
pub info: Option<MetaInfo>,
}
impl ReflectionOperator {
pub fn reflect(entity: impl Into<String>) -> Self {
Self {
entity_name: entity.into(),
info: None,
}
}
pub fn reflect_type(type_name: impl Into<String>) -> Self {
Self {
entity_name: type_name.into(),
info: Some(MetaInfo::new(
format!("__meta_{}", "type"),
MetaEntityKind::Type,
"type",
)),
}
}
pub fn to_source(&self) -> String {
format!("^{}", self.entity_name)
}
}
#[derive(Debug, Clone)]
pub struct Splicer {
pub expression: String,
pub reflected_info: Option<MetaInfo>,
pub result_type: String,
}
impl Splicer {
pub fn new(expression: impl Into<String>) -> Self {
Self {
expression: expression.into(),
reflected_info: None,
result_type: "auto".into(),
}
}
pub fn type_splicer(type_expr: impl Into<String>) -> Self {
Self {
expression: type_expr.into(),
reflected_info: None,
result_type: "typename".into(),
}
}
pub fn to_source(&self) -> String {
format!("[:{}:]", self.expression)
}
pub fn produces_type(&self) -> bool {
self.result_type == "typename"
}
}
#[derive(Debug, Clone)]
pub enum MetaQuery {
NameOf(String),
TypeOf(String),
MembersOf(String),
BasesOf(String),
ParametersOf(String),
AccessOf(String),
IsVirtual(String),
IsConstexpr(String),
IsNoexcept(String),
SizeOfReflected(String),
AlignOfReflected(String),
EnumToStr(String),
StrToEnum(String),
Custom(String),
}
impl MetaQuery {
pub fn to_source(&self) -> String {
match self {
Self::NameOf(e) => format!("name_of({})", e),
Self::TypeOf(e) => format!("type_of({})", e),
Self::MembersOf(e) => format!("members_of({})", e),
Self::BasesOf(e) => format!("bases_of({})", e),
Self::ParametersOf(e) => format!("parameters_of({})", e),
Self::AccessOf(e) => format!("access_of({})", e),
Self::IsVirtual(e) => format!("is_virtual({})", e),
Self::IsConstexpr(e) => format!("is_constexpr({})", e),
Self::IsNoexcept(e) => format!("is_noexcept({})", e),
Self::SizeOfReflected(e) => format!("size_of({})", e),
Self::AlignOfReflected(e) => format!("align_of({})", e),
Self::EnumToStr(e) => format!("enum_to_string({})", e),
Self::StrToEnum(e) => format!("string_to_enum<{}>(", e),
Self::Custom(e) => e.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct ReflectionContext {
pub operations: Vec<MetaQuery>,
pub splicers: Vec<Splicer>,
pub generated_code: Vec<String>,
pub nesting_depth: u32,
}
impl ReflectionContext {
pub fn new() -> Self {
Self {
operations: Vec::new(),
splicers: Vec::new(),
generated_code: Vec::new(),
nesting_depth: 0,
}
}
pub fn add_query(&mut self, query: MetaQuery) {
self.operations.push(query);
}
pub fn add_splicer(&mut self, splicer: Splicer) {
self.splicers.push(splicer);
}
pub fn generate_enum_to_string(&mut self, enum_name: &str, values: &[&str]) -> String {
let mut code = format!(
"constexpr auto to_string({} e) -> std::string_view {{\n",
enum_name
);
code.push_str(" switch (e) {\n");
for val in values {
code.push_str(&format!(
" case {}::{}: return \"{}\";\n",
enum_name, val, val
));
}
code.push_str(" default: return \"unknown\";\n");
code.push_str(" }\n");
code.push_str("}\n");
self.generated_code.push(code.clone());
code
}
pub fn generated_count(&self) -> usize {
self.generated_code.len()
}
}
impl Default for ReflectionContext {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PipelineStage {
Lex,
Preprocess,
Parse,
Sema,
CodeGen,
Optimize,
CodeGenFinal,
EmitAssembly,
EmitObject,
Link,
}
impl PipelineStage {
pub fn as_str(&self) -> &'static str {
match self {
Self::Lex => "lex",
Self::Preprocess => "preprocess",
Self::Parse => "parse",
Self::Sema => "sema",
Self::CodeGen => "codegen",
Self::Optimize => "optimize",
Self::CodeGenFinal => "codegen-final",
Self::EmitAssembly => "emit-asm",
Self::EmitObject => "emit-obj",
Self::Link => "link",
}
}
pub fn is_frontend(&self) -> bool {
matches!(
self,
Self::Lex | Self::Preprocess | Self::Parse | Self::Sema
)
}
pub fn is_backend(&self) -> bool {
matches!(
self,
Self::CodeGen
| Self::Optimize
| Self::CodeGenFinal
| Self::EmitAssembly
| Self::EmitObject
)
}
}
#[derive(Debug, Clone)]
pub struct CompilationResult {
pub success: bool,
pub module_name: Option<String>,
pub ir_module: Option<String>,
pub object_data: Option<Vec<u8>>,
pub assembly_text: Option<String>,
pub diagnostics: Vec<CXXFullDiagnostic>,
pub stages_executed: Vec<PipelineStage>,
pub timing_ms: f64,
}
impl CompilationResult {
pub fn new() -> Self {
Self {
success: true,
module_name: None,
ir_module: None,
object_data: None,
assembly_text: None,
diagnostics: Vec::new(),
stages_executed: Vec::new(),
timing_ms: 0.0,
}
}
pub fn with_error(mut self, diag: CXXFullDiagnostic) -> Self {
self.diagnostics.push(diag);
self.success = false;
self
}
pub fn with_ir(mut self, ir: impl Into<String>) -> Self {
self.ir_module = Some(ir.into());
self
}
pub fn error_count(&self) -> usize {
self.diagnostics
.iter()
.filter(|d| matches!(d.severity, DiagSeverity::Error | DiagSeverity::Fatal))
.count()
}
pub fn warning_count(&self) -> usize {
self.diagnostics
.iter()
.filter(|d| d.severity == DiagSeverity::Warning)
.count()
}
}
impl Default for CompilationResult {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct CompilationStatistics {
pub tokens_lexed: u64,
pub ast_nodes: u64,
pub types_checked: u64,
pub overloads_resolved: u64,
pub templates_instantiated: u64,
pub concepts_checked: u64,
pub modules_loaded: u64,
pub coroutines_lowered: u64,
pub lambdas_parsed: u64,
pub constexpr_evaluations: u64,
pub ir_instructions: u64,
pub x86_instructions: u64,
pub peak_memory_bytes: u64,
pub total_time_ms: f64,
}
impl CompilationStatistics {
pub fn new() -> Self {
Self::default()
}
pub fn merge(&mut self, other: &CompilationStatistics) {
self.tokens_lexed += other.tokens_lexed;
self.ast_nodes += other.ast_nodes;
self.types_checked += other.types_checked;
self.overloads_resolved += other.overloads_resolved;
self.templates_instantiated += other.templates_instantiated;
self.concepts_checked += other.concepts_checked;
self.modules_loaded += other.modules_loaded;
self.coroutines_lowered += other.coroutines_lowered;
self.lambdas_parsed += other.lambdas_parsed;
self.constexpr_evaluations += other.constexpr_evaluations;
self.ir_instructions += other.ir_instructions;
self.x86_instructions += other.x86_instructions;
}
pub fn summary(&self) -> String {
format!(
"Tokens: {}, AST: {}, IR: {}, X86: {}, Time: {:.2}ms",
self.tokens_lexed,
self.ast_nodes,
self.ir_instructions,
self.x86_instructions,
self.total_time_ms
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cxx_standard_version_from_str() {
assert_eq!(
CXXStandardVersion::from_str("c++17"),
Some(CXXStandardVersion::CXX17)
);
assert_eq!(
CXXStandardVersion::from_str("c++20"),
Some(CXXStandardVersion::CXX20)
);
assert_eq!(
CXXStandardVersion::from_str("c++23"),
Some(CXXStandardVersion::CXX23)
);
assert_eq!(
CXXStandardVersion::from_str("c++26"),
Some(CXXStandardVersion::CXX26)
);
assert_eq!(CXXStandardVersion::from_str("c++99"), None);
assert_eq!(
CXXStandardVersion::from_str("c++2a"),
Some(CXXStandardVersion::CXX20)
);
assert_eq!(
CXXStandardVersion::from_str("c++2b"),
Some(CXXStandardVersion::CXX23)
);
assert_eq!(
CXXStandardVersion::from_str("c++2c"),
Some(CXXStandardVersion::CXX26)
);
}
#[test]
fn test_cxx_standard_version_as_str() {
assert_eq!(CXXStandardVersion::CXX17.as_str(), "c++17");
assert_eq!(CXXStandardVersion::CXX20.as_str(), "c++20");
assert_eq!(CXXStandardVersion::CXX23.as_str(), "c++23");
assert_eq!(CXXStandardVersion::CXX26.as_str(), "c++2c");
}
#[test]
fn test_cxx_standard_version_is_at_least() {
assert!(CXXStandardVersion::CXX20.is_at_least(CXXStandardVersion::CXX17));
assert!(CXXStandardVersion::CXX23.is_at_least(CXXStandardVersion::CXX20));
assert!(!CXXStandardVersion::CXX17.is_at_least(CXXStandardVersion::CXX20));
}
#[test]
fn test_cxx_standard_has_features() {
assert!(CXXStandardVersion::CXX20.has_concepts());
assert!(CXXStandardVersion::CXX20.has_modules());
assert!(CXXStandardVersion::CXX20.has_coroutines());
assert!(!CXXStandardVersion::CXX17.has_concepts());
assert!(!CXXStandardVersion::CXX17.has_coroutines());
assert!(CXXStandardVersion::CXX23.has_deducing_this());
assert!(CXXStandardVersion::CXX23.has_if_consteval());
assert!(CXXStandardVersion::CXX26.has_constexpr_placement_new());
assert!(CXXStandardVersion::CXX26.has_pack_indexing());
}
#[test]
fn test_full_frontend_new_cxx20() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
assert!(fe.concepts.is_some());
assert!(fe.modules.is_some());
assert!(fe.coroutines.is_some());
assert!(fe.ranges.is_some());
assert!(fe.cxx23.is_none());
assert!(fe.cxx26.is_none());
assert!(fe.features.concepts);
assert!(fe.features.modules);
assert!(fe.features.coroutines);
}
#[test]
fn test_full_frontend_new_cxx23() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX23);
assert!(fe.concepts.is_some());
assert!(fe.cxx23.is_some());
assert!(fe.cxx26.is_none());
assert!(fe.features.deducing_this);
assert!(fe.features.if_consteval);
assert!(fe.features.multi_dim_subscript);
}
#[test]
fn test_full_frontend_new_cxx26() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX26);
assert!(fe.cxx23.is_some());
assert!(fe.cxx26.is_some());
assert!(fe.features.placeholder_vars);
assert!(fe.features.pack_indexing);
assert!(fe.features.constexpr_placement_new);
}
#[test]
fn test_full_frontend_enable_feature() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX17);
assert!(!fe.is_enabled("concepts"));
assert!(fe.enable_feature("concepts"));
assert!(fe.is_enabled("concepts"));
assert!(fe.concepts.is_some());
assert!(!fe.enable_feature("nonexistent"));
}
#[test]
fn test_full_frontend_validate_configuration() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX17);
fe.features.deducing_this = true;
assert!(!fe.validate_configuration());
assert!(!fe.diagnostics.is_empty());
}
#[test]
fn test_full_frontend_has_errors() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
assert!(!fe.has_errors());
fe.emit(CXXFullDiagnostic::error("test error"));
assert!(fe.has_errors());
}
#[test]
fn test_full_frontend_enabled_feature_count() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX23);
let count = fe.enabled_feature_count();
assert!(count > 0);
}
#[test]
fn test_feature_flags_for_standard_cxx20() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX20);
assert!(flags.concepts);
assert!(flags.modules);
assert!(flags.coroutines);
assert!(flags.ranges);
assert!(flags.constexpr_virtual);
assert!(flags.consteval);
assert!(flags.constinit);
assert!(flags.no_unique_address);
assert!(flags.likely_unlikely);
assert!(!flags.deducing_this);
assert!(!flags.placeholder_vars);
}
#[test]
fn test_feature_flags_for_standard_cxx26() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX26);
assert!(flags.deducing_this);
assert!(flags.placeholder_vars);
assert!(flags.pack_indexing);
assert!(flags.constexpr_placement_new);
}
#[test]
fn test_feature_flags_enable_all_cxx23() {
let mut flags = CXXFeatureFlags::default();
assert!(!flags.deducing_this);
flags.enable_all_cxx23();
assert!(flags.deducing_this);
assert!(flags.concepts);
}
#[test]
fn test_diag_severity_display() {
assert_eq!(DiagSeverity::Error.to_string(), "error");
assert_eq!(DiagSeverity::Warning.to_string(), "warning");
assert_eq!(DiagSeverity::Note.to_string(), "note");
assert_eq!(DiagSeverity::Fatal.to_string(), "fatal error");
}
#[test]
fn test_diagnostic_with_note() {
let diag = CXXFullDiagnostic::error("bad")
.with_note("see here")
.at(10, 5)
.in_file("test.cpp");
assert_eq!(diag.message, "bad");
assert_eq!(diag.line, 10);
assert_eq!(diag.column, 5);
assert_eq!(diag.file, Some("test.cpp".into()));
assert_eq!(diag.notes.len(), 1);
}
#[test]
fn test_atomic_constraint_new() {
let ac = AtomicConstraint::new("sizeof(T) == 4");
assert_eq!(ac.expression, "sizeof(T) == 4");
assert!(!ac.is_normalized);
}
#[test]
fn test_atomic_constraint_normalize() {
let mut ac = AtomicConstraint::new("T == U").with_mapping("U", "int");
ac.normalize();
assert!(ac.is_normalized);
assert_eq!(ac.expression, "T == int");
}
#[test]
fn test_atomic_constraint_subsumes() {
let a = AtomicConstraint::new("sizeof(T) == 4");
let mut b = AtomicConstraint::new("sizeof(T) == 4");
b.normalize();
assert!(a.subsumes(&b));
}
#[test]
fn test_constraint_result_is_satisfied() {
assert!(ConstraintResult::Satisfied.is_satisfied());
assert!(!ConstraintResult::NotSatisfied {
reason: "nope".into()
}
.is_satisfied());
assert!(ConstraintResult::Dependent.is_dependent());
}
#[test]
fn test_constraint_expr_evaluate_conjunction() {
let env = ConstraintEnv::new();
let expr = ConstraintExpr::Conjunction(
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("true"))),
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("true"))),
);
assert!(expr.evaluate(&env).is_satisfied());
}
#[test]
fn test_constraint_expr_evaluate_negation() {
let env = ConstraintEnv::new();
let expr = ConstraintExpr::Negation(Box::new(ConstraintExpr::Atomic(
AtomicConstraint::new("false"),
)));
let result = expr.evaluate(&env);
assert!(!result.is_satisfied());
}
#[test]
fn test_constraint_env_register_concept() {
let mut env = ConstraintEnv::new();
env.register_concept(
"Integral",
ConstraintExpr::Atomic(AtomicConstraint::new("std::is_integral_v<T>")),
);
assert!(env.concepts.contains_key("Integral"));
}
#[test]
fn test_concept_definition_new() {
let cd = ConceptDefinition::new(
"Integral",
ConstraintExpr::Atomic(AtomicConstraint::new("std::is_integral_v<T>")),
);
assert_eq!(cd.name, "Integral");
assert!(cd.is_defined);
}
#[test]
fn test_requires_clause_evaluate() {
let mut clause = RequiresClause::new(ConstraintExpr::Atomic(AtomicConstraint::new("true")));
let env = ConstraintEnv::new();
let result = clause.evaluate(&env);
assert!(result.is_satisfied());
assert!(clause.evaluated);
}
#[test]
fn test_requires_expression_evaluate() {
let mut re = RequiresExpression::new();
re.add_simple_requirement("a + b");
re.add_type_requirement("typename T::value_type");
let env = ConstraintEnv::new();
let result = re.evaluate(&env);
assert!(result.is_satisfied());
}
#[test]
fn test_cxx20_concepts_register() {
let mut concepts = CXX20Concepts::new(CXXStandardVersion::CXX20);
let cd = ConceptDefinition::new(
"EqualityComparable",
ConstraintExpr::Atomic(AtomicConstraint::new("a == b")),
);
concepts.register_concept(cd);
assert_eq!(concepts.concept_count(), 1);
assert!(concepts.lookup_concept("EqualityComparable").is_some());
assert!(concepts.lookup_concept("Nonexistent").is_none());
}
#[test]
fn test_cxx20_concepts_parse_requires_clause() {
let concepts = CXX20Concepts::new(CXXStandardVersion::CXX20);
let clause = concepts.parse_requires_clause("std::integral<T>");
assert!(clause.is_some());
}
#[test]
fn test_extended_module_kind_display() {
assert_eq!(ExtendedModuleKind::Interface.to_string(), "interface");
assert_eq!(
ExtendedModuleKind::PrivateFragment.to_string(),
"private module fragment"
);
}
#[test]
fn test_extended_module_kind_is_interface() {
assert!(ExtendedModuleKind::Interface.is_interface());
assert!(ExtendedModuleKind::PartitionInterface.is_interface());
assert!(!ExtendedModuleKind::Implementation.is_interface());
}
#[test]
fn test_extended_module_kind_is_partition() {
assert!(ExtendedModuleKind::PartitionInterface.is_partition());
assert!(ExtendedModuleKind::PartitionImplementation.is_partition());
assert!(!ExtendedModuleKind::Interface.is_partition());
}
#[test]
fn test_extended_module_decl_interface() {
let mn = ModuleName::from_str("mylib");
let decl = ExtendedModuleDecl::interface(mn.clone());
assert_eq!(decl.kind, ExtendedModuleKind::Interface);
assert_eq!(decl.name.to_string(), "mylib");
}
#[test]
fn test_extended_module_decl_partition() {
let parent = ModuleName::from_str("mylib");
let decl = ExtendedModuleDecl::partition(parent.clone(), "impl");
assert_eq!(decl.kind, ExtendedModuleKind::PartitionInterface);
assert_eq!(decl.partition_name, Some("impl".into()));
}
#[test]
fn test_extended_module_decl_display() {
let mn = ModuleName::from_str("test");
let decl = ExtendedModuleDecl::interface(mn);
let s = decl.to_string();
assert!(s.contains("module"));
assert!(s.contains("test"));
}
#[test]
fn test_extended_module_import_exported() {
let mn = ModuleName::from_str("other");
let imp = ExtendedModuleImport::new(mn).exported();
assert!(imp.is_exported);
assert!(!imp.is_header_unit);
}
#[test]
fn test_module_unit_new() {
let mn = ModuleName::from_str("mylib");
let decl = ExtendedModuleDecl::interface(mn);
let unit = ModuleUnit::new(decl);
assert!(unit.is_interface);
assert_eq!(unit.module_name(), "mylib");
}
#[test]
fn test_module_unit_reachability() {
let mn = ModuleName::from_str("mylib");
let decl = ExtendedModuleDecl::interface(mn);
let mut unit = ModuleUnit::new(decl);
unit.mark_reachable("some_func");
assert!(unit.is_reachable("some_func"));
assert!(!unit.is_reachable("other_func"));
}
#[test]
fn test_module_ownership_tracker() {
let mut tracker = ModuleOwnershipTracker::new();
assert!(tracker.current_module.is_none());
tracker.enter_module("mylib");
tracker.record("my_func");
assert_eq!(
tracker.linkage_of("my_func"),
ModuleLinkage::Attached("mylib".into())
);
tracker.leave_module();
assert!(tracker.current_module.is_none());
}
#[test]
fn test_global_module_fragment() {
let mut gmf = GlobalModuleFragment::new();
assert!(gmf.is_empty());
gmf.add_decl("int x;");
gmf.add_include("<vector>");
assert!(!gmf.is_empty());
}
#[test]
fn test_private_module_fragment() {
let mut pmf = PrivateModuleFragment::new();
assert!(pmf.is_empty());
pmf.add_decl("void helper();");
assert!(!pmf.is_empty());
pmf.close();
assert!(pmf.is_closed);
}
#[test]
fn test_module_dependency_resolver_topological_sort() {
let mut resolver = ModuleDependencyResolver::new();
resolver.add_dependency("B", "A");
resolver.add_dependency("C", "B");
let order = resolver.topological_sort().unwrap();
let pos_a = order.iter().position(|x| x == "A");
let pos_b = order.iter().position(|x| x == "B");
let pos_c = order.iter().position(|x| x == "C");
assert!(pos_a < pos_b);
assert!(pos_b < pos_c);
}
#[test]
fn test_module_dependency_resolver_circular() {
let mut resolver = ModuleDependencyResolver::new();
resolver.add_dependency("A", "B");
resolver.add_dependency("B", "A");
assert!(resolver.has_circular_deps());
}
#[test]
fn test_cxx20_modules_register_unit() {
let mut modules = CXX20Modules::new();
let mn = ModuleName::from_str("mylib");
let decl = ExtendedModuleDecl::interface(mn);
let mut unit = ModuleUnit::new(decl);
unit.add_import(ExtendedModuleImport::new(ModuleName::from_str("std")));
unit.add_export("foo");
modules.register_unit(unit);
assert_eq!(modules.unit_count(), 1);
}
#[test]
fn test_module_linkage_variants() {
assert!(ModuleLinkage::Global.is_global());
assert!(ModuleLinkage::Attached("m".into()).is_attached());
assert_eq!(ModuleLinkage::Attached("m".into()).module_name(), Some("m"));
assert_eq!(ModuleLinkage::Global.module_name(), None);
}
#[test]
fn test_coro_keyword_display() {
assert_eq!(CoroKeyword::CoAwait.to_string(), "co_await");
assert_eq!(CoroKeyword::CoYield.to_string(), "co_yield");
assert_eq!(CoroKeyword::CoReturn.to_string(), "co_return");
}
#[test]
fn test_coroutine_expr_co_await() {
let expr = CoroutineExpr::co_await("task");
assert_eq!(expr.keyword, CoroKeyword::CoAwait);
assert_eq!(expr.operand, Some("task".into()));
}
#[test]
fn test_coroutine_expr_co_return_void() {
let expr = CoroutineExpr::co_return(None);
assert_eq!(expr.keyword, CoroKeyword::CoReturn);
assert!(expr.operand.is_none());
}
#[test]
fn test_extended_promise_type_desc() {
let desc = ExtendedPromiseTypeDesc::new("my_promise")
.with_initial_suspend()
.with_final_suspend()
.with_symmetric_transfer();
assert_eq!(desc.type_name, "my_promise");
assert!(desc.has_initial_suspend);
assert!(desc.has_final_suspend);
assert!(desc.supports_symmetric_transfer);
}
#[test]
fn test_extended_coroutine_frame() {
let mut frame = ExtendedCoroutineFrame::new("my_promise");
frame.add_local(CoroutineFrameLocal {
name: "x".into(),
llvm_type: "i32".into(),
offset: 8,
size: 4,
spans_suspend: true,
needs_destruction: false,
});
assert_eq!(frame.local_count(), 1);
}
#[test]
fn test_symmetric_transfer_optimizer() {
let mut sto = SymmetricTransferOptimizer::new();
assert!(!sto.can_perform_symmetric_transfer());
sto.analyze(true);
sto.analyze(true);
assert!(sto.can_perform_symmetric_transfer());
}
#[test]
fn test_halo_analyzer() {
let mut halo = HaloAnalyzer::new();
assert!(halo.requires_heap);
halo.analyze(false, 10);
assert!(halo.should_elide());
assert!(!halo.requires_heap);
}
#[test]
fn test_cxx20_coroutines_parse() {
let co = CXX20Coroutines::new(CXXStandardVersion::CXX20);
let expr = co.parse_coro_expr("co_await task");
assert!(expr.is_some());
let expr = co.parse_coro_expr("co_return 42;");
assert!(expr.is_some());
let expr = co.parse_coro_expr("co_yield value;");
assert!(expr.is_some());
}
#[test]
fn test_coroutine_statistics() {
let mut co = CXX20Coroutines::new(CXXStandardVersion::CXX20);
co.signal_symmetric_transfer("a", "b");
let stats = co.statistics();
assert_eq!(stats.total_coroutines, 1);
assert_eq!(stats.symmetric_transfers, 1);
}
#[test]
fn test_range_concept_display() {
assert_eq!(RangeConcept::Range.to_string(), "std::ranges::range");
assert_eq!(
RangeConcept::RandomAccessRange.to_string(),
"std::ranges::random_access_range"
);
}
#[test]
fn test_range_concept_refinement() {
assert!(RangeConcept::RandomAccessRange.is_refinement_of(RangeConcept::BidirectionalRange));
assert!(RangeConcept::BidirectionalRange.is_refinement_of(RangeConcept::ForwardRange));
assert!(RangeConcept::ForwardRange.is_refinement_of(RangeConcept::InputRange));
assert!(RangeConcept::InputRange.is_refinement_of(RangeConcept::Range));
assert!(!RangeConcept::InputRange.is_refinement_of(RangeConcept::RandomAccessRange));
}
#[test]
fn test_range_adaptor_display() {
let a = RangeAdaptor::Filter;
assert_eq!(a.to_string(), "std::views::filter");
assert_eq!(RangeAdaptor::Transform.to_string(), "std::views::transform");
assert_eq!(RangeAdaptor::Zip.to_string(), "std::views::zip");
}
#[test]
fn test_range_view_config() {
let config = RangeViewConfig::new(RangeAdaptor::Filter, "int");
assert_eq!(config.adaptor, RangeAdaptor::Filter);
assert_eq!(config.element_type, "int");
assert!(!config.is_sized);
}
#[test]
fn test_cxx20_ranges_new() {
let ranges = CXX20Ranges::new();
assert!(ranges.enabled);
assert!(ranges.adaptor_count() > 0);
assert!(ranges.has_adaptor("std::views::filter"));
}
#[test]
fn test_cxx20_ranges_lookup() {
let ranges = CXX20Ranges::new();
let config = ranges.lookup_adaptor(RangeAdaptor::Filter);
assert!(config.is_some());
assert_eq!(config.unwrap().adaptor, RangeAdaptor::Filter);
}
#[test]
fn test_iterator_category_display() {
assert_eq!(
IteratorCategory::RandomAccess.to_string(),
"std::random_access_iterator"
);
assert_eq!(IteratorCategory::Input.to_string(), "std::input_iterator");
}
#[test]
fn test_projection_identity() {
let proj = Projection::identity();
assert!(proj.is_identity);
assert_eq!(proj.name, "std::identity");
}
#[test]
fn test_ranges_satisfies_concept() {
let mut ranges = CXX20Ranges::new();
ranges.register_range_concepts(
"std::vector<int>",
vec![
RangeConcept::RandomAccessRange,
RangeConcept::ContiguousRange,
],
);
assert!(ranges.satisfies_range_concept("std::vector<int>", RangeConcept::Range));
assert!(ranges.satisfies_range_concept("std::vector<int>", RangeConcept::RandomAccessRange));
}
#[test]
fn test_explicit_object_kind_from_param_str() {
assert_eq!(
ExplicitObjectKind::from_param_str("auto&&"),
Some(ExplicitObjectKind::DeducedRef)
);
assert_eq!(
ExplicitObjectKind::from_param_str("auto&"),
Some(ExplicitObjectKind::DeducedLvalueRef)
);
assert_eq!(
ExplicitObjectKind::from_param_str("auto"),
Some(ExplicitObjectKind::DeducedByValue)
);
assert_eq!(
ExplicitObjectKind::from_param_str("const auto&"),
Some(ExplicitObjectKind::DeducedConstLvalueRef)
);
assert_eq!(ExplicitObjectKind::from_param_str("int"), None);
}
#[test]
fn test_explicit_object_kind_is_reference() {
assert!(ExplicitObjectKind::DeducedRef.is_reference());
assert!(ExplicitObjectKind::DeducedLvalueRef.is_reference());
assert!(!ExplicitObjectKind::DeducedByValue.is_reference());
}
#[test]
fn test_explicit_object_function() {
let func = ExplicitObjectFunction::new("foo", ExplicitObjectKind::DeducedRef, "self");
assert!(func.can_bind_lvalue());
assert!(func.can_bind_rvalue());
assert!(func.is_static);
assert!(func.signature().contains("auto&& self"));
}
#[test]
fn test_if_consteval() {
let ic = IfConsteval::new();
assert_eq!(ic.evaluate(), IfConstevalResult::NonImmediateContext);
}
#[test]
fn test_multi_dim_subscript_validate() {
let mds = MultiDimSubscript::new(vec!["int".into(), "int".into()], "double");
assert!(mds.validate().is_ok());
assert_eq!(mds.index_count, 2);
}
#[test]
fn test_multi_dim_subscript_validate_empty() {
let mds = MultiDimSubscript::new(vec![], "int");
assert!(mds.validate().is_err());
}
#[test]
fn test_static_operator_call_validate() {
let soc = StaticOperatorCall::new("MyLambda");
assert!(soc.validate().is_ok());
}
#[test]
fn test_static_operator_call_validate_captures() {
let mut soc = StaticOperatorCall::new("MyLambda");
soc.is_lambda = true;
soc.has_captures = true;
assert!(soc.validate().is_err());
}
#[test]
fn test_decay_copy_expr() {
let dc = DecayCopyExpr::new(DecayCopyKind::DecayCopyParen, "x");
assert_eq!(dc.emit(), "auto(x)");
assert!(dc.is_prvalue);
}
#[test]
fn test_decay_copy_display() {
assert_eq!(DecayCopyKind::DecayCopyParen.to_string(), "auto(x)");
assert_eq!(DecayCopyKind::DecayCopyBrace.to_string(), "auto{x}");
}
#[test]
fn test_warning_directive() {
let wd = WarningDirective::new("this is deprecated");
assert!(wd.format_diagnostic().contains("#warning"));
}
#[test]
fn test_elif_conditional() {
assert_eq!(
ElifConditional::from_directive("elifdef"),
Some(ElifConditional::Elifdef)
);
assert_eq!(
ElifConditional::from_directive("elifndef"),
Some(ElifConditional::Elifndef)
);
assert_eq!(
ElifConditional::from_directive("elif"),
Some(ElifConditional::Elif)
);
assert_eq!(ElifConditional::from_directive("ifdef"), None);
}
#[test]
fn test_cxx23_features_enabled() {
let features = CXX23Features::new(CXXStandardVersion::CXX23);
assert!(features.is_enabled(CXX23Feature::DeducingThis));
assert!(features.is_enabled(CXX23Feature::IfConsteval));
assert!(features.is_enabled(CXX23Feature::ZipView));
}
#[test]
fn test_cxx23_features_disabled_cxx20() {
let features = CXX23Features::new(CXXStandardVersion::CXX20);
assert!(!features.is_enabled(CXX23Feature::DeducingThis));
assert!(!features.is_enabled(CXX23Feature::IfConsteval));
}
#[test]
fn test_cxx23_feature_name() {
assert_eq!(CXX23Feature::DeducingThis.name(), "deducing this");
assert_eq!(CXX23Feature::IfConsteval.name(), "if consteval");
assert_eq!(CXX23Feature::StaticOperatorCall.name(), "static operator()");
}
#[test]
fn test_placeholder_variable() {
let pv = PlaceholderVariable::new("test_scope", "int");
assert_eq!(pv.ty, "int");
assert!(!pv.is_structured_binding);
}
#[test]
fn test_placeholder_variable_anonymous() {
let pv = PlaceholderVariable::anonymous();
assert_eq!(pv.ty, "auto");
}
#[test]
fn test_pack_indexing() {
let pi = PackIndexing::new("Args", "0");
assert_eq!(pi.to_source(), "Args...[0]");
assert!(pi.validate().is_ok());
}
#[test]
fn test_pack_indexing_validate_empty() {
let pi = PackIndexing::new("Args", "");
assert!(pi.validate().is_err());
}
#[test]
fn test_constexpr_placement_new() {
let pn = ConstexprPlacementNew::new("&buffer", "MyClass").with_alignment(16);
assert_eq!(pn.alignment, 16);
assert!(pn.validate().is_ok());
}
#[test]
fn test_constexpr_placement_new_to_source() {
let pn = ConstexprPlacementNew::new("&buf", "T").with_args(vec!["42".into()]);
assert!(pn.to_source().contains("42"));
}
#[test]
fn test_constexpr_allocation_tracker() {
let mut tracker = ConstexprAllocationTracker::new();
let addr = tracker.allocate(16, 8);
assert_eq!(tracker.total_allocated, 16);
assert!(tracker.deallocate(&addr));
assert_eq!(tracker.total_deallocated, 16);
assert!(!tracker.check_leaks());
assert!(tracker.is_sound());
}
#[test]
fn test_constexpr_allocation_tracker_leak() {
let mut tracker = ConstexprAllocationTracker::new();
tracker.allocate(16, 8);
assert!(tracker.check_leaks());
assert!(!tracker.is_sound());
}
#[test]
fn test_user_generated_static_assert() {
let mut sa = UserGeneratedStaticAssert::new("sizeof(T) == 4", "T must have size 4, got {}");
assert!(!sa.is_constant_evaluated);
let mut env = HashMap::new();
env.insert("{}".into(), "8".into());
sa.evaluate_message(&env);
assert!(sa.is_constant_evaluated);
assert!(sa.evaluated_message.is_some());
}
#[test]
fn test_cxx26_preview_features() {
let preview = CXX26Preview::new(CXXStandardVersion::CXX26);
assert!(preview.is_enabled(CXX26Feature::PlaceholderVars));
assert!(preview.is_enabled(CXX26Feature::PackIndexing));
assert!(preview.is_enabled(CXX26Feature::ConstexprPlacementNew));
assert!(preview.enabled_count() >= 4);
}
#[test]
fn test_cxx26_preview_disabled_cxx23() {
let preview = CXX26Preview::new(CXXStandardVersion::CXX23);
assert!(!preview.is_enabled(CXX26Feature::PlaceholderVars));
assert!(!preview.is_enabled(CXX26Feature::PackIndexing));
}
#[test]
fn test_cxx26_feature_name() {
assert_eq!(
CXX26Feature::PlaceholderVars.name(),
"placeholder variables"
);
assert_eq!(CXX26Feature::PackIndexing.name(), "pack indexing");
assert_eq!(
CXX26Feature::ConstexprPlacementNew.name(),
"constexpr placement new"
);
}
#[test]
fn test_attribute_parse_nodiscard() {
let attr = CXXAttribute::parse("[[nodiscard]]");
assert_eq!(attr, Some(CXXAttribute::Nodiscard(None)));
}
#[test]
fn test_attribute_parse_nodiscard_with_message() {
let attr = CXXAttribute::parse("[[nodiscard(\"reason\")]]");
assert_eq!(attr, Some(CXXAttribute::Nodiscard(Some("reason".into()))));
}
#[test]
fn test_attribute_parse_deprecated() {
let attr = CXXAttribute::parse("[[deprecated]]");
assert_eq!(attr, Some(CXXAttribute::Deprecated(None)));
}
#[test]
fn test_attribute_parse_deprecated_with_message() {
let attr = CXXAttribute::parse("[[deprecated(\"use bar\")]]");
assert_eq!(attr, Some(CXXAttribute::Deprecated(Some("use bar".into()))));
}
#[test]
fn test_attribute_parse_likely() {
let attr = CXXAttribute::parse("[[likely]]");
assert_eq!(attr, Some(CXXAttribute::Likely));
}
#[test]
fn test_attribute_parse_unlikely() {
let attr = CXXAttribute::parse("[[unlikely]]");
assert_eq!(attr, Some(CXXAttribute::Unlikely));
}
#[test]
fn test_attribute_parse_no_unique_address() {
let attr = CXXAttribute::parse("[[no_unique_address]]");
assert_eq!(attr, Some(CXXAttribute::NoUniqueAddress));
}
#[test]
fn test_attribute_parse_noreturn() {
let attr = CXXAttribute::parse("[[noreturn]]");
assert_eq!(attr, Some(CXXAttribute::Noreturn));
}
#[test]
fn test_attribute_parse_maybe_unused() {
let attr = CXXAttribute::parse("[[maybe_unused]]");
assert_eq!(attr, Some(CXXAttribute::MaybeUnused));
}
#[test]
fn test_attribute_parse_fallthrough() {
let attr = CXXAttribute::parse("[[fallthrough]]");
assert_eq!(attr, Some(CXXAttribute::Fallthrough));
}
#[test]
fn test_attribute_parse_assume() {
let attr = CXXAttribute::parse("[[assume(x > 0)]]");
assert_eq!(attr, Some(CXXAttribute::Assume("x > 0".into())));
}
#[test]
fn test_attribute_parse_invalid() {
assert!(CXXAttribute::parse("not_an_attribute").is_none());
assert!(CXXAttribute::parse("[maybe_unused]").is_none());
}
#[test]
fn test_attribute_display() {
assert_eq!(CXXAttribute::Noreturn.to_string(), "[[noreturn]]");
assert_eq!(CXXAttribute::Likely.to_string(), "[[likely]]");
assert_eq!(
CXXAttribute::Deprecated(Some("old".into())).to_string(),
"[[deprecated(\"old\")]]"
);
assert_eq!(
CXXAttribute::Assume("x > 0".into()).to_string(),
"[[assume(x > 0)]]"
);
}
#[test]
fn test_attribute_is_valid_for() {
assert!(CXXAttribute::Noreturn.is_valid_for("function"));
assert!(!CXXAttribute::Noreturn.is_valid_for("class"));
assert!(CXXAttribute::NoUniqueAddress.is_valid_for("class"));
assert!(CXXAttribute::Fallthrough.is_valid_for("statement"));
assert!(CXXAttribute::Likely.is_valid_for("statement"));
}
#[test]
fn test_attribute_is_compatible() {
assert!(CXXAttribute::Noreturn.is_compatible_with(&CXXAttribute::GnuNoreturn));
assert!(!CXXAttribute::Likely.is_compatible_with(&CXXAttribute::Unlikely));
}
#[test]
fn test_attribute_introduced_in() {
assert_eq!(CXXAttribute::Noreturn.introduced_in(), "C++11");
assert_eq!(CXXAttribute::Likely.introduced_in(), "C++20");
assert_eq!(CXXAttribute::Assume("x".into()).introduced_in(), "C++23");
}
#[test]
fn test_attribute_affects_x86_codegen() {
assert!(CXXAttribute::Noreturn.affects_x86_codegen());
assert!(CXXAttribute::Likely.affects_x86_codegen());
assert!(CXXAttribute::GnuAligned(16).affects_x86_codegen());
assert!(!CXXAttribute::Deprecated(None).affects_x86_codegen());
}
#[test]
fn test_attribute_to_gnu_attr() {
assert_eq!(
CXXAttribute::Noreturn.to_gnu_attr(),
Some("noreturn".into())
);
assert_eq!(
CXXAttribute::Nodiscard(None).to_gnu_attr(),
Some("warn_unused_result".into())
);
assert_eq!(
CXXAttribute::GnuAligned(64).to_gnu_attr(),
Some("aligned(64)".into())
);
assert_eq!(CXXAttribute::Fallthrough.to_gnu_attr(), None);
}
#[test]
fn test_attribute_handler_parse_and_register() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
let attr = handler.parse_and_register("[[nodiscard]]");
assert!(attr.is_some());
assert_eq!(handler.attribute_count(), 1);
}
#[test]
fn test_attribute_handler_attach() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
handler.attach_to("my_func", CXXAttribute::Nodiscard(None));
handler.attach_to("my_func", CXXAttribute::MaybeUnused);
assert!(handler.is_nodiscard("my_func"));
assert!(handler.is_maybe_unused("my_func"));
assert!(!handler.is_nodiscard("other_func"));
}
#[test]
fn test_attribute_handler_is_deprecated() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX17);
handler.attach_to(
"old_func",
CXXAttribute::Deprecated(Some("use new_func".into())),
);
let result = handler.is_deprecated("old_func");
assert_eq!(result, Some("use new_func"));
}
#[test]
fn test_attribute_handler_no_unique_address() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
handler.attach_to("my_member", CXXAttribute::NoUniqueAddress);
assert!(handler.has_no_unique_address("my_member"));
}
#[test]
fn test_attribute_handler_likely_unlikely() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
handler.attach_to("hot_path", CXXAttribute::Likely);
handler.attach_to("cold_path", CXXAttribute::Unlikely);
assert!(handler.is_likely("hot_path"));
assert!(handler.is_unlikely("cold_path"));
}
#[test]
fn test_attribute_handler_noreturn() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX11);
handler.attach_to("abort_func", CXXAttribute::Noreturn);
assert!(handler.is_noreturn("abort_func"));
}
#[test]
fn test_attribute_handler_validate() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
handler.attach_to("my_class", CXXAttribute::Noreturn);
let errors = handler.validate_for("my_class", "class");
assert!(!errors.is_empty());
}
#[test]
fn test_attribute_handler_x86_codegen_hints() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX20);
handler.attach_to("my_func", CXXAttribute::Noreturn);
handler.attach_to("my_func", CXXAttribute::GnuAlwaysInline);
let hints = handler.x86_codegen_hints("my_func");
assert!(hints.contains(&"noreturn".into()));
assert!(hints.contains(&"always_inline".into()));
}
#[test]
fn test_lambda_capture_kind_display() {
assert_eq!(LambdaCaptureKind::ByValue.to_string(), "=");
assert_eq!(LambdaCaptureKind::ByReference.to_string(), "&");
assert_eq!(LambdaCaptureKind::StarThis.to_string(), "*this");
}
#[test]
fn test_lambda_capture_default_display() {
assert_eq!(LambdaCaptureDefault::None.to_string(), "");
assert_eq!(LambdaCaptureDefault::ByCopy.to_string(), "=");
assert_eq!(LambdaCaptureDefault::ByReference.to_string(), "&");
}
#[test]
fn test_extended_lambda_capture_by_value() {
let cap = ExtendedLambdaCapture::by_value("x");
assert_eq!(cap.name, "x");
assert_eq!(cap.kind, LambdaCaptureKind::ByValue);
}
#[test]
fn test_extended_lambda_capture_star_this() {
let cap = ExtendedLambdaCapture::star_this();
assert_eq!(cap.kind, LambdaCaptureKind::StarThis);
}
#[test]
fn test_extended_lambda_capture_init() {
let cap = ExtendedLambdaCapture::init_capture("y", "x + 1");
assert_eq!(cap.name, "y");
assert_eq!(cap.init_expression, Some("x + 1".into()));
}
#[test]
fn test_extended_lambda_new() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20);
assert!(lambda.is_stateless());
assert!(!lambda.is_generic);
assert!(!lambda.is_mutable);
}
#[test]
fn test_extended_lambda_generic() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20).generic();
assert!(lambda.is_generic);
}
#[test]
fn test_extended_lambda_constexpr() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20).constexpr_lambda();
assert!(lambda.is_constexpr);
assert!(!lambda.is_consteval);
}
#[test]
fn test_extended_lambda_consteval() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20).consteval_lambda();
assert!(lambda.is_consteval);
assert!(lambda.is_constexpr);
}
#[test]
fn test_extended_lambda_can_convert_to_fn_ptr() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20);
assert!(lambda.can_convert_to_fn_ptr());
}
#[test]
fn test_extended_lambda_cannot_convert_generic() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20).generic();
assert!(!lambda.can_convert_to_fn_ptr());
}
#[test]
fn test_extended_lambda_validate_for_standard() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX17);
assert!(lambda.validate_for_standard().is_ok());
}
#[test]
fn test_extended_lambda_validate_template_lambda_cxx17() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX17);
let lambda = lambda.with_template_params(vec![]);
assert!(lambda.validate_for_standard().is_err());
}
#[test]
fn test_generic_lambda_template_from_auto_params() {
let params = vec![("a".into(), "auto".into()), ("b".into(), "int".into())];
let gt = GenericLambdaTemplate::from_auto_params(¶ms);
assert!(gt.is_some());
assert_eq!(gt.unwrap().num_template_params(), 1);
}
#[test]
fn test_lambda_conversion_op() {
let op = LambdaConversionOp::new("int", &["double".into()]);
assert!(op.signature().contains("int(*)"));
}
#[test]
fn test_cxx_lambda_extensions_register() {
let mut ext = CXXLambdaExtensions::new(CXXStandardVersion::CXX20);
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20)
.with_capture_default(LambdaCaptureDefault::ByCopy);
ext.register_lambda(lambda);
assert_eq!(ext.lambda_count(), 1);
}
#[test]
fn test_cxx_lambda_extensions_supports() {
let ext = CXXLambdaExtensions::new(CXXStandardVersion::CXX20);
assert!(ext.supports("template_lambda"));
assert!(ext.supports("consteval_lambda"));
assert!(!ext.supports("nonexistent"));
}
#[test]
fn test_constexpr_mode_display() {
assert_eq!(ConstexprMode::Constexpr.to_string(), "constexpr");
assert_eq!(ConstexprMode::Consteval.to_string(), "consteval");
assert_eq!(ConstexprMode::Constinit.to_string(), "constinit");
assert_eq!(ConstexprMode::Runtime.to_string(), "runtime");
}
#[test]
fn test_constexpr_virtual_function() {
let vf = ConstexprVirtualFunction::new("foo", "Base");
assert_eq!(vf.name, "foo");
assert_eq!(vf.class_name, "Base");
}
#[test]
fn test_constexpr_virtual_function_validate_pure() {
let mut vf = ConstexprVirtualFunction::new("foo", "Base");
vf.is_pure_virtual = true;
assert!(vf.validate().is_err());
}
#[test]
fn test_constexpr_virtual_function_validate_normal() {
let vf = ConstexprVirtualFunction::new("foo", "Base");
assert!(vf.validate().is_ok());
}
#[test]
fn test_constexpr_try_catch() {
let mut tc = ConstexprTryCatch::new();
tc.add_catch("std::exception");
tc.is_constexpr = true;
assert!(tc.validate().is_ok());
}
#[test]
fn test_constexpr_dynamic_cast() {
let dc = ConstexprDynamicCast::new("Base*", "Derived*");
assert!(dc.validate().is_ok());
}
#[test]
fn test_constexpr_dynamic_cast_to_void() {
let dc = ConstexprDynamicCast::new("Derived*", "void*");
assert!(dc.is_to_void);
assert!(dc.validate().is_ok());
}
#[test]
fn test_constexpr_new_delete() {
let nd = ConstexprNewDelete::new_expression("int", 4, 4);
assert!(!nd.is_placement);
assert_eq!(nd.allocation_size, 4);
}
#[test]
fn test_constexpr_new_delete_placement() {
let nd = ConstexprPlacementNew::new("&buf", "T");
assert!(nd.validate().is_ok());
}
#[test]
fn test_immediate_function() {
let imf = ImmediateFunction::new("get_five").with_body("return 5;");
assert!(imf.is_defined);
assert!(imf.validate().is_ok());
}
#[test]
fn test_immediate_function_undefined() {
let imf = ImmediateFunction::new("get_five");
assert!(!imf.is_defined);
assert!(imf.validate().is_err());
}
#[test]
fn test_extended_constexpr_context() {
let mut ctx = ExtendedConstexprContext::new(ConstexprMode::Constexpr);
assert!(!ctx.is_consteval());
assert!(ctx.is_constexpr());
assert!(ctx.enter_call().is_ok());
assert_eq!(ctx.call_depth, 1);
ctx.leave_call();
assert_eq!(ctx.call_depth, 0);
}
#[test]
fn test_cxx_constexpr_extensions_supports() {
let ext = CXXConstexprExtensions::new(CXXStandardVersion::CXX20);
assert!(ext.supports("constexpr_virtual"));
assert!(ext.supports("consteval"));
assert!(!ext.supports("constexpr_placement_new"));
}
#[test]
fn test_cxx_constexpr_extensions_cxx26() {
let ext = CXXConstexprExtensions::new(CXXStandardVersion::CXX26);
assert!(ext.supports("constexpr_virtual"));
assert!(ext.supports("constexpr_placement_new"));
}
#[test]
fn test_cxx_constexpr_extensions_register() {
let mut ext = CXXConstexprExtensions::new(CXXStandardVersion::CXX20);
ext.register_constexpr_virtual(ConstexprVirtualFunction::new("foo", "Base"));
ext.register_immediate_fn(ImmediateFunction::new("bar"));
assert_eq!(ext.virtual_function_count(), 1);
assert_eq!(ext.immediate_function_count(), 1);
}
#[test]
fn test_cxx_constexpr_extensions_set_mode() {
let mut ext = CXXConstexprExtensions::new(CXXStandardVersion::CXX20);
assert!(!ext.is_in_immediate_context());
ext.set_consteval_mode();
assert!(ext.is_in_immediate_context());
ext.set_constexpr_mode();
assert!(!ext.is_in_immediate_context());
}
#[test]
fn test_integration_full_frontend_with_concepts() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
let concepts = fe.concepts.as_mut().unwrap();
let cd = ConceptDefinition::new(
"Sortable",
ConstraintExpr::Atomic(AtomicConstraint::new("requires (T a) { a < a; }")),
);
concepts.register_concept(cd);
assert_eq!(concepts.concept_count(), 1);
}
#[test]
fn test_integration_full_frontend_with_modules() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
let modules = fe.modules.as_mut().unwrap();
let mn = ModuleName::from_str("math");
let decl = ExtendedModuleDecl::interface(mn.clone());
let unit = ModuleUnit::new(decl);
modules.register_unit(unit);
assert_eq!(modules.unit_count(), 1);
assert!(!modules.has_circular_deps());
}
#[test]
fn test_integration_full_frontend_with_coroutines() {
let mut fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
let coroutines = fe.coroutines.as_mut().unwrap();
let promise = ExtendedPromiseTypeDesc::new("task_promise")
.with_initial_suspend()
.with_final_suspend();
coroutines.register_promise("my_coro", promise);
assert_eq!(coroutines.promises.len(), 1);
}
#[test]
fn test_integration_concepts_with_modules() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
assert!(fe.concepts.is_some());
assert!(fe.modules.is_some());
}
#[test]
fn test_integration_lambda_with_attributes() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20)
.constexpr_lambda()
.with_attribute(CXXAttribute::Nodiscard(None));
assert!(lambda.is_constexpr);
assert_eq!(lambda.attributes.len(), 1);
}
#[test]
fn test_integration_coroutine_with_x86_target() {
let fe = CXXFullFrontend::for_x86_64_linux(CXXStandardVersion::CXX20);
assert!(fe.x86_target.is_some());
assert!(fe.coroutines.is_some());
}
#[test]
fn test_integration_cxx23_cxx26_coexistence() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX26);
assert!(fe.cxx23.is_some());
assert!(fe.cxx26.is_some());
assert!(fe
.cxx23
.as_ref()
.unwrap()
.is_enabled(CXX23Feature::DeducingThis));
assert!(fe
.cxx26
.as_ref()
.unwrap()
.is_enabled(CXX26Feature::PlaceholderVars));
}
#[test]
fn test_integration_decay_copy_with_constexpr() {
let dc = DecayCopyExpr::new(DecayCopyKind::DecayCopyParen, "x");
let decayed = dc.apply_decay("const int&");
assert_eq!(decayed, "int");
}
#[test]
fn test_integration_ranges_with_concepts() {
let mut ranges = CXX20Ranges::new();
ranges.register_range_concepts(
"std::vector<int>",
vec![RangeConcept::RandomAccessRange, RangeConcept::SizedRange],
);
assert!(ranges.satisfies_range_concept("std::vector<int>", RangeConcept::Range));
assert!(ranges.satisfies_range_concept("std::vector<int>", RangeConcept::SizedRange));
assert!(!ranges.satisfies_range_concept("std::vector<int>", RangeConcept::View));
}
#[test]
fn test_integration_multi_dim_subscript_with_constexpr() {
let mds = MultiDimSubscript::new(vec!["int".into(), "int".into()], "constexpr auto");
let syntax = mds.call_syntax("mat");
assert!(syntax.contains("operator[]"));
assert!(syntax.contains("i0"));
assert!(syntax.contains("i1"));
}
#[test]
fn test_integration_full_pipeline_cxx20() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX20);
assert!(fe.validate_configuration());
let concepts = fe.concepts.as_ref().unwrap();
assert!(concepts.lookup_concept("Integral").is_none());
let modules = fe.modules.as_ref().unwrap();
assert!(modules.build_order().is_ok());
assert!(fe.lambda_extensions.supports("template_lambda"));
assert!(fe.constexpr_extensions.supports("consteval"));
}
#[test]
fn test_integration_full_pipeline_cxx26() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX26);
assert!(fe.validate_configuration());
assert!(fe
.cxx26
.as_ref()
.unwrap()
.is_enabled(CXX26Feature::PackIndexing));
assert!(fe
.cxx26
.as_ref()
.unwrap()
.is_enabled(CXX26Feature::ConstexprPlacementNew));
assert!(fe.constexpr_extensions.supports("constexpr_placement_new"));
}
#[test]
fn test_all_attribute_parsing_roundtrip() {
let attrs = vec![
"[[noreturn]]",
"[[carries_dependency]]",
"[[deprecated]]",
"[[deprecated(\"msg\")]]",
"[[fallthrough]]",
"[[nodiscard]]",
"[[nodiscard(\"reason\")]]",
"[[maybe_unused]]",
"[[no_unique_address]]",
"[[likely]]",
"[[unlikely]]",
"[[assume(x > 0)]]",
];
for attr_str in &attrs {
let parsed = CXXAttribute::parse(attr_str);
assert!(parsed.is_some(), "Failed to parse: {}", attr_str);
}
}
#[test]
fn test_all_range_adaptors_present() {
let ranges = CXX20Ranges::new();
let names = ranges.adaptor_names();
assert!(names.contains(&"std::views::filter".to_string()));
assert!(names.contains(&"std::views::transform".to_string()));
assert!(names.contains(&"std::views::take".to_string()));
assert!(names.contains(&"std::views::reverse".into()));
}
#[test]
fn test_feature_flags_exhaustive() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX26);
assert!(flags.placeholder_vars);
assert!(flags.pack_indexing);
assert!(flags.constexpr_placement_new);
assert!(flags.user_generated_static_assert);
assert!(flags.deducing_this);
assert!(flags.if_consteval);
assert!(flags.concepts);
assert!(flags.consteval);
}
#[test]
fn test_module_ownership_full_cycle() {
let mut tracker = ModuleOwnershipTracker::new();
tracker.enter_module("libA");
tracker.record("func_a");
tracker.record("func_b");
assert_eq!(
tracker.linkage_of("func_a"),
ModuleLinkage::Attached("libA".into())
);
tracker.leave_module();
tracker.record("func_global");
assert_eq!(tracker.linkage_of("func_global"), ModuleLinkage::Global);
tracker.enter_module("libB");
tracker.record("func_c");
assert_eq!(
tracker.linkage_of("func_c"),
ModuleLinkage::Attached("libB".into())
);
}
#[test]
fn test_x86_target_integration() {
let fe = CXXFullFrontend::for_x86_64_linux(CXXStandardVersion::CXX23);
assert!(fe.x86_target.is_some());
assert!(fe.cxx23.is_some());
assert!(fe.attributes.attribute_count() == 0);
}
#[test]
fn test_full_coverage_all_components_instantiable() {
let _fe = CXXFullFrontend::new(CXXStandardVersion::CXX26);
let _concepts = CXX20Concepts::new(CXXStandardVersion::CXX20);
let _modules = CXX20Modules::new();
let _coroutines = CXX20Coroutines::new(CXXStandardVersion::CXX20);
let _ranges = CXX20Ranges::new();
let _cxx23 = CXX23Features::new(CXXStandardVersion::CXX23);
let _cxx26 = CXX26Preview::new(CXXStandardVersion::CXX26);
let _attrs = CXXAttributeHandler::new(CXXStandardVersion::CXX23);
let _lambda_ext = CXXLambdaExtensions::new(CXXStandardVersion::CXX20);
let _constexpr_ext = CXXConstexprExtensions::new(CXXStandardVersion::CXX20);
}
#[test]
fn test_cxx_full_frontend_default() {
let fe = CXXFullFrontend::new(CXXStandardVersion::default());
assert_eq!(fe.standard, CXXStandardVersion::CXX17);
}
#[test]
fn test_constraint_result_clone() {
let r1 = ConstraintResult::NotSatisfied {
reason: "test".into(),
};
let r2 = r1.clone();
assert!(!r2.is_satisfied());
assert!(!r2.is_dependent());
}
#[test]
fn test_constraint_expr_subsumes_reflexive() {
let ac = ConstraintExpr::Atomic(AtomicConstraint::new("true"));
assert!(ac.subsumes(&ac));
}
#[test]
fn test_requires_expression_empty() {
let mut re = RequiresExpression::new();
let env = ConstraintEnv::new();
let result = re.evaluate(&env);
assert!(result.is_satisfied());
}
#[test]
fn test_extended_module_import_header_unit() {
let mn = ModuleName::from_str("iostream");
let imp = ExtendedModuleImport::new(mn).header_unit("<iostream>");
assert!(imp.is_header_unit);
assert_eq!(imp.header_name, Some("<iostream>".into()));
}
#[test]
fn test_awaitable_descriptor() {
let desc = AwaitableDescriptor::new("task<int>");
assert!(desc.has_await_ready);
assert!(desc.has_await_suspend);
assert!(desc.has_await_resume);
assert!(!desc.is_symmetric_transfer);
}
#[test]
fn test_explicit_object_function_lvalue_rvalue() {
let func_lv =
ExplicitObjectFunction::new("f", ExplicitObjectKind::DeducedLvalueRef, "self");
assert!(func_lv.can_bind_lvalue());
assert!(!func_lv.can_bind_rvalue());
let func_rv = ExplicitObjectFunction::new("g", ExplicitObjectKind::DeducedByValue, "self");
assert!(!func_rv.can_bind_lvalue());
assert!(func_rv.can_bind_rvalue());
}
#[test]
fn test_pack_indexing_validate_constant() {
let pi = PackIndexing::new("Args", "0");
assert!(pi.is_constant_index);
assert!(pi.validate().is_ok());
}
#[test]
fn test_user_generated_static_assert_evaluate() {
let mut sa = UserGeneratedStaticAssert::new("size == 4", "size is {}");
let mut env = HashMap::new();
env.insert("{}".into(), "8".into());
sa.evaluate_message(&env);
assert!(sa.formatted().contains("8"));
}
#[test]
fn test_extended_lambda_to_source() {
let lambda = ExtendedLambda::new(CXXStandardVersion::CXX20)
.with_capture_default(LambdaCaptureDefault::ByCopy)
.add_capture(ExtendedLambdaCapture::by_reference("x"))
.add_param("a", "int")
.with_return_type("int")
.with_body("return a + x;")
.constexpr_lambda();
let source = lambda.to_source();
assert!(source.contains("constexpr"));
assert!(source.contains("return a + x"));
assert!(source.contains("int a"));
}
#[test]
fn test_constexpr_new_delete_placement_validate_empty() {
let nd = ConstexprNewDelete::placement("T", "", 4);
assert!(nd.validate().is_err());
}
#[test]
fn test_constexpr_dynamic_cast_validate_conflict() {
let mut dc = ConstexprDynamicCast::new("Base*", "Derived*");
dc.is_downcast = true;
dc.is_crosscast = true;
assert!(dc.validate().is_err());
}
#[test]
fn test_x86_code_model_default() {
let cm = X86CodeModel::default();
assert_eq!(cm, X86CodeModel::Small);
assert_eq!(cm.as_str(), "small");
}
#[test]
fn test_x86_code_model_all_variants() {
assert_eq!(X86CodeModel::Kernel.as_str(), "kernel");
assert_eq!(X86CodeModel::Medium.as_str(), "medium");
assert_eq!(X86CodeModel::Large.as_str(), "large");
assert_eq!(X86CodeModel::Tiny.as_str(), "tiny");
}
#[test]
fn test_x86_reloc_model_default() {
assert_eq!(X86RelocModel::default(), X86RelocModel::Static);
}
#[test]
fn test_x86_exception_model_default() {
assert_eq!(X86ExceptionModel::default(), X86ExceptionModel::Dwarf);
}
#[test]
fn test_x86_tls_model_default() {
assert_eq!(X86TLSModel::default(), X86TLSModel::GeneralDynamic);
}
#[test]
fn test_x86_cxx_codegen_config_default() {
let config = X86CXXCodeGenConfig::default();
assert_eq!(config.target_triple, "x86_64-unknown-linux-gnu");
assert!(config.has_feature("sse2"));
assert!(config.has_feature("cmov"));
assert!(!config.has_feature("avx512f"));
assert_eq!(config.opt_level, 2);
assert!(config.enable_vectorize);
assert!(config.integrated_as);
}
#[test]
fn test_x86_cxx_codegen_config_for_skylake() {
let config = X86CXXCodeGenConfig::for_skylake();
assert!(config.has_feature("avx2"));
assert!(config.has_feature("fma"));
assert!(config.has_feature("bmi"));
}
#[test]
fn test_x86_cxx_codegen_config_for_znver4() {
let config = X86CXXCodeGenConfig::for_znver4();
assert!(config.has_feature("avx512f"));
assert!(config.has_feature("avx512dq"));
assert!(config.has_feature("avx512bw"));
}
#[test]
fn test_x86_cxx_codegen_config_for_x86_64_v2() {
let config = X86CXXCodeGenConfig::for_x86_64_v2();
assert!(config.has_feature("sse3"));
assert!(config.has_feature("popcnt"));
}
#[test]
fn test_x86_cxx_codegen_config_for_x86_64_v3() {
let config = X86CXXCodeGenConfig::for_x86_64_v3();
assert!(config.has_feature("avx"));
assert!(config.has_feature("avx2"));
assert!(config.has_feature("fma"));
}
#[test]
fn test_x86_cxx_codegen_config_add_remove_feature() {
let mut config = X86CXXCodeGenConfig::default();
config.add_feature("avx");
assert!(config.has_feature("avx"));
config.remove_feature("avx");
assert!(!config.has_feature("avx"));
let count = config.features.len();
config.add_feature("sse2");
assert_eq!(config.features.len(), count);
}
#[test]
fn test_x86_lowering_info_for_x86_64_linux() {
let info = X86CXXLoweringInfo::for_x86_64_linux();
assert_eq!(info.pointer_size, 8);
assert_eq!(info.pointer_alignment, 8);
assert!(info.has_red_zone);
assert_eq!(info.red_zone_size, 128);
assert_eq!(info.personality_fn, "__gxx_personality_v0");
assert_eq!(
info.default_member_cc,
X86MemberCallingConvention::SysVAmd64
);
}
#[test]
fn test_x86_lowering_info_for_x86_64_windows() {
let info = X86CXXLoweringInfo::for_x86_64_windows();
assert_eq!(info.pointer_size, 8);
assert!(!info.has_red_zone);
assert_eq!(info.red_zone_size, 0);
assert_eq!(info.personality_fn, "__CxxFrameHandler3");
assert_eq!(
info.default_member_cc,
X86MemberCallingConvention::MicrosoftX64
);
assert_eq!(info.mangling, X86ManglingScheme::Microsoft);
}
#[test]
fn test_x86_lowering_info_for_x86_32_linux() {
let info = X86CXXLoweringInfo::for_x86_32_linux();
assert_eq!(info.pointer_size, 4);
assert_eq!(info.pointer_alignment, 4);
assert_eq!(info.size_t_size, 4);
assert!(!info.has_red_zone);
assert_eq!(info.default_member_cc, X86MemberCallingConvention::CDecl);
}
#[test]
fn test_x86_intrinsic_map_lookup() {
let map = X86CXXIntrinsicMap::new();
assert!(map.lookup("_mm_pause").is_some());
assert!(map.lookup("__rdtsc").is_some());
assert!(map.lookup("nonexistent").is_none());
assert_eq!(map.intrinsic_count(), 4);
}
#[test]
fn test_x86_intrinsic_map_availability() {
let map = X86CXXIntrinsicMap::new();
let features = vec!["sse2".to_string()];
assert!(map.is_available_for_cpu("_mm_pause", &features));
assert!(!map.is_available_for_cpu("__builtin_ia32_lzcnt_u32", &features));
let features_with_lzcnt = vec!["lzcnt".to_string()];
assert!(map.is_available_for_cpu("__builtin_ia32_lzcnt_u32", &features_with_lzcnt));
}
#[test]
fn test_x86_arg_class_as_str() {
assert_eq!(X86ArgClass::Integer.as_str(), "Integer");
assert_eq!(X86ArgClass::Sse.as_str(), "SSE");
assert_eq!(X86ArgClass::Memory.as_str(), "Memory");
}
#[test]
fn test_x86_aggregate_passing_small_struct() {
let passing = X86AggregatePassing::classify_sysv_amd64(16);
assert!(passing.passed_in_regs);
assert_eq!(passing.classifications.len(), 2);
assert_eq!(passing.reg_assignments.len(), 2);
}
#[test]
fn test_x86_aggregate_passing_large_struct() {
let passing = X86AggregatePassing::classify_sysv_amd64(32);
assert!(!passing.passed_in_regs);
assert!(passing.classifications.contains(&X86ArgClass::Memory));
}
#[test]
fn test_x86_aggregate_passing_requires_sret() {
assert!(!X86AggregatePassing::requires_sret(8));
assert!(!X86AggregatePassing::requires_sret(16));
assert!(X86AggregatePassing::requires_sret(24));
assert!(X86AggregatePassing::requires_sret(64));
}
#[test]
fn test_x86_reg_assignment() {
let ra = X86RegAssignment::new("%rdi", 0, 8);
assert_eq!(ra.reg_name, "%rdi");
assert_eq!(ra.offset, 0);
assert_eq!(ra.size, 8);
}
#[test]
fn test_contract_kind_is_audit() {
assert!(ContractKind::PreconditionAudit.is_audit());
assert!(ContractKind::PostconditionAudit.is_audit());
assert!(!ContractKind::Precondition.is_audit());
assert!(!ContractKind::Assertion.is_audit());
}
#[test]
fn test_contract_kind_is_precondition() {
assert!(ContractKind::Precondition.is_precondition());
assert!(ContractKind::PreconditionAudit.is_precondition());
assert!(!ContractKind::Postcondition.is_precondition());
assert!(!ContractKind::Assertion.is_precondition());
}
#[test]
fn test_contract_kind_display() {
assert_eq!(ContractKind::Precondition.to_string(), "pre");
assert_eq!(ContractKind::Postcondition.to_string(), "post");
assert_eq!(ContractKind::Assertion.to_string(), "assert");
assert_eq!(ContractKind::PreconditionAudit.to_string(), "pre(audit)");
}
#[test]
fn test_contract_semantic_from_str() {
assert_eq!(
ContractSemantic::from_str("default"),
Some(ContractSemantic::Default)
);
assert_eq!(
ContractSemantic::from_str("audit"),
Some(ContractSemantic::Audit)
);
assert_eq!(
ContractSemantic::from_str("axiom"),
Some(ContractSemantic::Axiom)
);
assert_eq!(ContractSemantic::from_str("nonexistent"), None);
}
#[test]
fn test_contract_semantic_is_checked() {
assert!(ContractSemantic::Default.is_checked_at_runtime());
assert!(ContractSemantic::Audit.is_checked_at_runtime());
assert!(!ContractSemantic::Axiom.is_checked_at_runtime());
}
#[test]
fn test_contract_continuation_mode_display() {
assert_eq!(ContractContinuationMode::NeverContinue.to_string(), "never");
assert_eq!(ContractContinuationMode::MaybeContinue.to_string(), "maybe");
assert_eq!(
ContractContinuationMode::AlwaysContinue.to_string(),
"always"
);
}
#[test]
fn test_contract_annotation_precondition() {
let ca = ContractAnnotation::precondition("x > 0");
assert_eq!(ca.kind, ContractKind::Precondition);
assert_eq!(ca.predicate, "x > 0");
assert!(ca.result_identifier.is_none());
}
#[test]
fn test_contract_annotation_postcondition() {
let ca = ContractAnnotation::postcondition("ret > 0", "ret");
assert_eq!(ca.kind, ContractKind::Postcondition);
assert_eq!(ca.result_identifier, Some("ret".into()));
}
#[test]
fn test_contract_annotation_assertion() {
let ca = ContractAnnotation::assertion("invariant_holds()");
assert_eq!(ca.kind, ContractKind::Assertion);
}
#[test]
fn test_contract_annotation_audit() {
let ca = ContractAnnotation::precondition("complex_check()").audit();
assert_eq!(ca.kind, ContractKind::PreconditionAudit);
assert_eq!(ca.semantic, ContractSemantic::Audit);
}
#[test]
fn test_function_contracts_new() {
let fc = FunctionContracts::new("my_func");
assert_eq!(fc.function_name, "my_func");
assert_eq!(fc.total_count(), 0);
assert!(!fc.has_audit_contracts());
}
#[test]
fn test_function_contracts_add() {
let mut fc = FunctionContracts::new("f");
fc.add_precondition(ContractAnnotation::precondition("x > 0"));
fc.add_postcondition(ContractAnnotation::postcondition("ret", "ret"));
fc.add_assertion(ContractAnnotation::assertion("invariant"));
assert_eq!(fc.total_count(), 3);
}
#[test]
fn test_function_contracts_has_audit() {
let mut fc = FunctionContracts::new("f");
fc.add_precondition(ContractAnnotation::precondition("x > 0").audit());
assert!(fc.has_audit_contracts());
}
#[test]
fn test_contract_violation_handler_default() {
let handler = ContractViolationHandler::default_handler();
assert!(handler.terminates);
assert!(handler.logs_violation);
assert!(handler.custom_code.is_none());
}
#[test]
fn test_contract_violation_handler_log_only() {
let handler = ContractViolationHandler::log_only();
assert!(!handler.terminates);
assert!(handler.logs_violation);
}
#[test]
fn test_contract_violation_handler_custom() {
let handler = ContractViolationHandler::custom("my_handler", "log_and_abort();");
assert_eq!(handler.name, "my_handler");
assert_eq!(handler.custom_code, Some("log_and_abort();".into()));
}
#[test]
fn test_contract_build_config_default() {
let config = ContractBuildConfig::default();
assert_eq!(config.build_level, ContractBuildLevel::Default);
assert!(config.enable_assertions);
}
#[test]
fn test_contract_build_config_off() {
let config = ContractBuildConfig::default().off();
assert_eq!(config.build_level, ContractBuildLevel::Off);
assert!(!config.enable_assertions);
}
#[test]
fn test_contract_build_config_should_evaluate() {
let config = ContractBuildConfig::default();
let pre = ContractAnnotation::precondition("x > 0");
let pre_audit = ContractAnnotation::precondition("x > 0").audit();
assert!(config.should_evaluate(&pre));
assert!(!config.should_evaluate(&pre_audit));
let config_audit = ContractBuildConfig::default().with_audit();
assert!(config_audit.should_evaluate(&pre));
assert!(config_audit.should_evaluate(&pre_audit));
let config_off = ContractBuildConfig::default().off();
assert!(!config_off.should_evaluate(&pre));
assert!(!config_off.should_evaluate(&pre_audit));
}
#[test]
fn test_match_pattern_wildcard() {
let p = MatchPattern::wildcard();
assert!(p.is_irrefutable());
assert_eq!(p.to_string_repr(), "_");
}
#[test]
fn test_match_pattern_binding() {
let p = MatchPattern::binding("x");
assert!(p.is_irrefutable());
assert_eq!(p.to_string_repr(), "x");
}
#[test]
fn test_match_pattern_integer() {
let p = MatchPattern::integer(42);
assert!(!p.is_irrefutable());
assert_eq!(p.to_string_repr(), "42");
}
#[test]
fn test_match_pattern_type_pattern() {
let p = MatchPattern::type_pattern("int");
assert_eq!(p.to_string_repr(), "int");
let p2 = MatchPattern::type_with_binding("std::string", "s");
assert_eq!(p2.to_string_repr(), "std::string s");
}
#[test]
fn test_match_literal_display() {
assert_eq!(MatchLiteral::Integer(10).to_string(), "10");
assert_eq!(MatchLiteral::Float(3.14).to_string(), "3.14");
assert_eq!(MatchLiteral::Boolean(true).to_string(), "true");
assert_eq!(
MatchLiteral::String("hello".into()).to_string(),
"\"hello\""
);
assert_eq!(MatchLiteral::Char('a').to_string(), "'a'");
assert_eq!(MatchLiteral::Nullptr.to_string(), "nullptr");
}
#[test]
fn test_match_pattern_destructure() {
let p = MatchPattern::Destructure(vec![
MatchPattern::integer(1),
MatchPattern::wildcard(),
MatchPattern::binding("z"),
]);
let repr = p.to_string_repr();
assert!(repr.starts_with('['));
assert!(repr.contains('_'));
assert!(repr.contains('z'));
}
#[test]
fn test_match_pattern_range() {
let p = MatchPattern::Range {
lower: Box::new(MatchPattern::integer(0)),
upper: Box::new(MatchPattern::integer(10)),
};
assert_eq!(p.to_string_repr(), "0..10");
}
#[test]
fn test_match_pattern_guard() {
let p = MatchPattern::Guard {
pattern: Box::new(MatchPattern::binding("x")),
condition: "x > 0".into(),
};
assert!(p.to_string_repr().contains("if x > 0"));
}
#[test]
fn test_inspect_case_new() {
let case = InspectCase::new(MatchPattern::integer(0), "return \"zero\";");
assert_eq!(case.body, "return \"zero\";");
assert!(!case.is_terminating);
}
#[test]
fn test_inspect_case_with_guard() {
let case = InspectCase::new(MatchPattern::wildcard(), "return x;").with_guard("x != 0");
assert_eq!(case.guard, Some("x != 0".into()));
}
#[test]
fn test_inspect_expression_new() {
let expr = InspectExpression::new("value", "int");
assert_eq!(expr.scrutinee, "value");
assert_eq!(expr.scrutinee_type, "int");
assert_eq!(expr.case_count(), 0);
}
#[test]
fn test_inspect_expression_add_case() {
let mut expr = InspectExpression::new("v", "int");
expr.add_case(InspectCase::new(MatchPattern::integer(0), "return 0;"));
expr.add_case(InspectCase::new(MatchPattern::wildcard(), "return -1;"));
assert_eq!(expr.case_count(), 2);
}
#[test]
fn test_exhaustiveness_check_exhaustive() {
let mut expr = InspectExpression::new("v", "int");
expr.add_case(InspectCase::new(MatchPattern::integer(0), "0"));
expr.add_case(InspectCase::new(MatchPattern::wildcard(), "-1"));
let result = expr.check_exhaustiveness();
match result {
ExhaustivenessResult::Exhaustive => {}
_ => panic!("expected exhaustive"),
}
}
#[test]
fn test_exhaustiveness_check_non_exhaustive() {
let mut expr = InspectExpression::new("v", "int");
expr.add_case(InspectCase::new(MatchPattern::integer(0), "0"));
let result = expr.check_exhaustiveness();
match result {
ExhaustivenessResult::NonExhaustive { .. } => {}
_ => panic!("expected non-exhaustive"),
}
}
#[test]
fn test_meta_info_new() {
let mi = MetaInfo::new("__meta_t", MetaEntityKind::Type, "my_type");
assert_eq!(mi.handle, "__meta_t");
assert_eq!(mi.entity_kind, MetaEntityKind::Type);
assert_eq!(mi.display_name, "my_type");
}
#[test]
fn test_meta_entity_kind_display() {
assert_eq!(MetaEntityKind::Type.to_string(), "type");
assert_eq!(MetaEntityKind::Class.to_string(), "class");
assert_eq!(MetaEntityKind::Function.to_string(), "function");
assert_eq!(MetaEntityKind::Lambda.to_string(), "lambda");
}
#[test]
fn test_reflection_operator() {
let op = ReflectionOperator::reflect("my_type");
assert_eq!(op.entity_name, "my_type");
assert_eq!(op.to_source(), "^my_type");
}
#[test]
fn test_reflection_operator_reflect_type() {
let op = ReflectionOperator::reflect_type("int");
assert!(op.info.is_some());
assert_eq!(op.info.unwrap().entity_kind, MetaEntityKind::Type);
}
#[test]
fn test_splicer_new() {
let s = Splicer::new("meta_value");
assert_eq!(s.to_source(), "[:meta_value:]");
assert!(!s.produces_type());
}
#[test]
fn test_splicer_type() {
let s = Splicer::type_splicer("meta_type");
assert!(s.produces_type());
}
#[test]
fn test_meta_query_to_source() {
assert_eq!(MetaQuery::NameOf("^T".into()).to_source(), "name_of(^T)");
assert_eq!(MetaQuery::TypeOf("^x".into()).to_source(), "type_of(^x)");
assert_eq!(
MetaQuery::MembersOf("^C".into()).to_source(),
"members_of(^C)"
);
assert_eq!(
MetaQuery::IsConstexpr("^f".into()).to_source(),
"is_constexpr(^f)"
);
}
#[test]
fn test_reflection_context_new() {
let ctx = ReflectionContext::new();
assert_eq!(ctx.nesting_depth, 0);
assert_eq!(ctx.generated_count(), 0);
}
#[test]
fn test_reflection_context_generate_enum_to_string() {
let mut ctx = ReflectionContext::new();
let code = ctx.generate_enum_to_string("Color", &["Red", "Green", "Blue"]);
assert!(code.contains("std::string_view"));
assert!(code.contains("Color::Red"));
assert!(code.contains("Color::Green"));
assert!(code.contains("Color::Blue"));
assert_eq!(ctx.generated_count(), 1);
}
#[test]
fn test_reflection_context_add_query_and_splicer() {
let mut ctx = ReflectionContext::new();
ctx.add_query(MetaQuery::NameOf("^T".into()));
ctx.add_splicer(Splicer::new("meta"));
assert_eq!(ctx.operations.len(), 1);
assert_eq!(ctx.splicers.len(), 1);
}
#[test]
fn test_pipeline_stage_as_str() {
assert_eq!(PipelineStage::Lex.as_str(), "lex");
assert_eq!(PipelineStage::CodeGen.as_str(), "codegen");
assert_eq!(PipelineStage::Link.as_str(), "link");
}
#[test]
fn test_pipeline_stage_is_frontend() {
assert!(PipelineStage::Lex.is_frontend());
assert!(PipelineStage::Parse.is_frontend());
assert!(PipelineStage::Sema.is_frontend());
assert!(!PipelineStage::CodeGen.is_frontend());
assert!(!PipelineStage::Link.is_frontend());
}
#[test]
fn test_pipeline_stage_is_backend() {
assert!(PipelineStage::CodeGen.is_backend());
assert!(PipelineStage::Optimize.is_backend());
assert!(!PipelineStage::Lex.is_backend());
assert!(!PipelineStage::Link.is_backend());
}
#[test]
fn test_compilation_result_new() {
let result = CompilationResult::new();
assert!(result.success);
assert!(result.ir_module.is_none());
assert!(result.object_data.is_none());
}
#[test]
fn test_compilation_result_with_error() {
let result =
CompilationResult::new().with_error(CXXFullDiagnostic::error("something went wrong"));
assert!(!result.success);
assert_eq!(result.error_count(), 1);
}
#[test]
fn test_compilation_result_with_ir() {
let result = CompilationResult::new().with_ir("define i32 @main() { ret i32 0 }");
assert!(result.ir_module.is_some());
assert!(result.success);
}
#[test]
fn test_compilation_result_counts() {
let mut result = CompilationResult::new();
result.diagnostics.push(CXXFullDiagnostic::error("err1"));
result.diagnostics.push(CXXFullDiagnostic::warning("warn1"));
result.diagnostics.push(CXXFullDiagnostic::warning("warn2"));
assert_eq!(result.error_count(), 1);
assert_eq!(result.warning_count(), 2);
}
#[test]
fn test_compilation_statistics_new() {
let stats = CompilationStatistics::new();
assert_eq!(stats.tokens_lexed, 0);
assert_eq!(stats.ast_nodes, 0);
}
#[test]
fn test_compilation_statistics_merge() {
let mut stats1 = CompilationStatistics::new();
stats1.tokens_lexed = 100;
stats1.ast_nodes = 50;
let mut stats2 = CompilationStatistics::new();
stats2.tokens_lexed = 200;
stats2.ast_nodes = 80;
stats1.merge(&stats2);
assert_eq!(stats1.tokens_lexed, 300);
assert_eq!(stats1.ast_nodes, 130);
}
#[test]
fn test_compilation_statistics_summary() {
let mut stats = CompilationStatistics::new();
stats.tokens_lexed = 1000;
stats.x86_instructions = 500;
let summary = stats.summary();
assert!(summary.contains("1000"));
assert!(summary.contains("500"));
}
#[test]
fn test_x86_code_model_all_variants_exhaustive() {
let variants = [
X86CodeModel::Small,
X86CodeModel::Kernel,
X86CodeModel::Medium,
X86CodeModel::Large,
X86CodeModel::Tiny,
];
for v in &variants {
let s = v.as_str();
assert!(!s.is_empty());
}
}
#[test]
fn test_contract_kind_all_variants() {
let kinds = [
ContractKind::Precondition,
ContractKind::Postcondition,
ContractKind::Assertion,
ContractKind::PreconditionAudit,
ContractKind::PostconditionAudit,
ContractKind::AssertionAudit,
];
for k in &kinds {
let s = k.to_string();
assert!(!s.is_empty());
}
}
#[test]
fn test_meta_entity_kind_all_variants() {
let kinds = [
MetaEntityKind::Type,
MetaEntityKind::Variable,
MetaEntityKind::Function,
MetaEntityKind::MemberFunction,
MetaEntityKind::Namespace,
MetaEntityKind::Template,
MetaEntityKind::Concept,
MetaEntityKind::Class,
MetaEntityKind::Struct,
MetaEntityKind::Enum,
MetaEntityKind::Lambda,
MetaEntityKind::DataMember,
];
for k in &kinds {
let s = k.to_string();
assert!(!s.is_empty());
}
}
#[test]
fn test_match_pattern_all_base_variants() {
let patterns = [
MatchPattern::wildcard(),
MatchPattern::binding("x"),
MatchPattern::integer(1),
MatchPattern::bool_literal(true),
MatchPattern::string_literal("hello"),
MatchPattern::type_pattern("int"),
];
for p in &patterns {
let repr = p.to_string_repr();
assert!(!repr.is_empty(), "Pattern should have non-empty repr");
}
}
#[test]
fn test_full_x86_integration_workflow() {
let fe = CXXFullFrontend::for_x86_64_linux(CXXStandardVersion::CXX23);
let config = X86CXXCodeGenConfig::for_x86_64_v3();
let lowering = X86CXXLoweringInfo::for_x86_64_linux();
assert!(fe.x86_target.is_some());
assert!(config.has_feature("avx2"));
assert_eq!(lowering.pointer_size, 8);
assert_eq!(lowering.mangling, X86ManglingScheme::Itanium);
}
#[test]
fn test_contracts_in_full_frontend() {
let mut fc = FunctionContracts::new("test_fn");
fc.add_precondition(ContractAnnotation::precondition("x > 0"));
fc.add_postcondition(ContractAnnotation::postcondition("ret > 0", "ret"));
let config = ContractBuildConfig::default();
let should_check = fc.preconditions.iter().all(|c| config.should_evaluate(c));
assert!(should_check);
assert_eq!(fc.total_count(), 2);
}
#[test]
fn test_pattern_matching_in_full_frontend() {
let mut expr = InspectExpression::new("x", "int");
expr.add_case(InspectCase::new(
MatchPattern::integer(0),
"return \"zero\";",
));
expr.add_case(InspectCase::new(
MatchPattern::wildcard(),
"return \"other\";",
));
let result = expr.check_exhaustiveness();
assert!(matches!(result, ExhaustivenessResult::Exhaustive));
assert_eq!(expr.case_count(), 2);
}
#[test]
fn test_reflection_in_full_frontend() {
let mut ctx = ReflectionContext::new();
let code = ctx.generate_enum_to_string("Status", &["Ok", "Err"]);
assert!(code.contains("Status::Ok"));
assert!(code.contains("Status::Err"));
}
#[test]
fn test_total_x86_variant_count() {
let config = X86CXXCodeGenConfig::default();
assert!(config.features.len() >= 2);
let config_v3 = X86CXXCodeGenConfig::for_x86_64_v3();
assert!(config_v3.features.len() >= 5);
}
#[test]
fn test_final_comprehensive_integration() {
let fe = CXXFullFrontend::new(CXXStandardVersion::CXX26);
assert!(fe.validate_configuration());
let n_feats = fe.enabled_feature_count();
assert!(n_feats > 5, "Expected many features enabled for C++26");
assert!(fe.concepts.is_some());
assert!(fe.modules.is_some());
assert!(fe.coroutines.is_some());
assert!(fe.ranges.is_some());
assert!(fe.cxx23.is_some());
assert!(fe.cxx26.is_some());
assert!(fe.lambda_extensions.supports("template_lambda"));
assert!(fe.lambda_extensions.supports("consteval_lambda"));
assert!(fe.constexpr_extensions.supports("constexpr_placement_new"));
assert!(fe.constexpr_extensions.supports("consteval"));
let attr = fe.attributes.parse_and_register("[[nodiscard]]");
assert!(attr.is_some());
}
#[test]
fn test_full_feature_matrix_cxx14() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX14);
assert!(flags.generic_lambdas);
assert!(flags.constexpr_lambdas);
assert!(flags.lambda_init_capture);
assert!(!flags.concepts);
assert!(!flags.modules);
assert!(!flags.deducing_this);
}
#[test]
fn test_full_feature_matrix_cxx17() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX17);
assert!(flags.generic_lambdas);
assert!(flags.lambda_capture_star_this);
assert!(flags.nodiscard_with_message);
assert!(!flags.concepts);
}
#[test]
fn test_full_feature_matrix_cxx20() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX20);
assert!(flags.concepts);
assert!(flags.modules);
assert!(flags.coroutines);
assert!(flags.ranges);
assert!(flags.constexpr_virtual);
assert!(flags.constexpr_dtor);
assert!(flags.consteval);
assert!(flags.constinit);
assert!(flags.no_unique_address);
assert!(flags.likely_unlikely);
assert!(flags.lambda_template_params);
assert!(!flags.deducing_this);
}
#[test]
fn test_full_feature_matrix_cxx23() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX23);
assert!(flags.deducing_this);
assert!(flags.if_consteval);
assert!(flags.multi_dim_subscript);
assert!(flags.static_operator_call);
assert!(flags.decay_copy);
assert!(flags.assume);
}
#[test]
fn test_full_feature_matrix_cxx26() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX26);
assert!(flags.placeholder_vars);
assert!(flags.pack_indexing);
assert!(flags.constexpr_placement_new);
assert!(flags.user_generated_static_assert);
assert!(flags.deducing_this);
assert!(flags.concepts);
}
#[test]
fn test_simd_width_bits() {
assert_eq!(SimdWidth::Sse128.bits(), 128);
assert_eq!(SimdWidth::Avx256.bits(), 256);
assert_eq!(SimdWidth::Avx512.bits(), 512);
}
#[test]
fn test_simd_type_descriptor() {
let desc = SimdTypeDescriptor::new("f32", 4, SimdWidth::Sse128);
assert_eq!(desc.type_name(), "std::simd<f32, 4>");
assert!(desc.fits_in_width());
}
#[test]
fn test_simd_math_op_all() {
let ops = [
SimdMathOp::Add,
SimdMathOp::Sub,
SimdMathOp::Mul,
SimdMathOp::Div,
SimdMathOp::Fma,
SimdMathOp::Sqrt,
SimdMathOp::Abs,
SimdMathOp::Min,
SimdMathOp::Max,
SimdMathOp::Ceil,
SimdMathOp::Floor,
SimdMathOp::Trunc,
SimdMathOp::Round,
SimdMathOp::Sin,
SimdMathOp::Cos,
SimdMathOp::Exp,
SimdMathOp::Log,
SimdMathOp::Pow,
SimdMathOp::Hypot,
];
for op in &ops {
assert!(!op.function_name().is_empty());
}
}
#[test]
fn test_x86_simd_mapping_find() {
let mapping = X86SimdMapping::new();
let entry = mapping.find_mapping(SimdMathOp::Add, "i32", 4);
assert!(entry.is_some());
assert_eq!(entry.unwrap().x86_instruction, "paddd");
}
#[test]
fn test_x86_simd_mapping_is_supported() {
let mapping = X86SimdMapping::new();
let features = vec!["sse".to_string(), "sse2".to_string()];
assert!(mapping.is_supported(SimdMathOp::Add, "f32", &features));
assert!(!mapping.is_supported(SimdMathOp::Fma, "f32", &features));
}
#[test]
fn test_hazard_pointer_protect_reset() {
let mut hp = HazardPointer::new(1);
hp.protect(0x1000);
assert!(hp.is_protecting());
hp.reset();
assert!(!hp.is_protecting());
}
#[test]
fn test_hazard_pointer_domain_acquire_release() {
let mut domain = HazardPointerDomain::new(4);
let idx = domain.acquire();
assert!(idx.is_some());
assert_eq!(domain.active_count(), 1);
domain.release(idx.unwrap());
assert_eq!(domain.active_count(), 0);
}
#[test]
fn test_hazard_pointer_domain_retire_reclaim() {
let mut domain = HazardPointerDomain::new(2);
domain.retire(0x2000, "free");
domain.retire(0x3000, "free");
let reclaimed = domain.reclaim();
assert_eq!(reclaimed.len(), 2);
}
#[test]
fn test_rcu_domain_read_lock() {
let mut domain = RcuDomain::new(0);
assert!(!domain.is_reader_active());
let _guard = domain.rcu_read_lock();
assert!(domain.is_reader_active());
domain.rcu_read_unlock();
assert!(!domain.is_reader_active());
}
#[test]
fn test_rcu_call_rcu_and_synchronize() {
let mut domain = RcuDomain::new(0);
domain.call_rcu(0x5000, "cleanup");
assert_eq!(domain.callback_count(), 1);
domain.synchronize_rcu();
assert_eq!(domain.callback_count(), 0);
assert_eq!(domain.generation, 1);
}
#[test]
fn test_rcu_protected_read_update() {
let mut protected = RcuProtected::new(42i32, 0);
assert_eq!(*protected.read(), 42);
protected.update(99);
assert_eq!(*protected.read(), 99);
}
#[test]
fn test_sender_descriptor_just() {
let sender = SenderDescriptor::just(vec!["int".into()]);
assert!(sender.is_just);
assert!(sender.always_completes);
assert_eq!(sender.value_count(), 1);
}
#[test]
fn test_sender_descriptor_schedule() {
let sender = SenderDescriptor::schedule("pool");
assert!(sender.is_schedule);
assert!(!sender.always_completes);
}
#[test]
fn test_sender_adaptor_all_types() {
let adaptors = vec![
SenderAdaptor::Then {
function: "f".into(),
input_type: "T".into(),
output_type: "U".into(),
},
SenderAdaptor::UponError {
function: "g".into(),
error_type: "E".into(),
},
SenderAdaptor::UponStopped {
function: "h".into(),
},
SenderAdaptor::WhenAll { sender_count: 2 },
SenderAdaptor::Transfer {
scheduler: "s".into(),
},
SenderAdaptor::Split,
SenderAdaptor::EnsureStarted,
SenderAdaptor::IntoVariant,
];
for a in &adaptors {
assert!(!a.type_name().is_empty());
}
}
#[test]
fn test_receiver_descriptor() {
let recv = ReceiverDescriptor::full("r", "v", "e", "s");
assert!(recv.has_error_handler());
assert!(recv.has_stopped_handler());
}
#[test]
fn test_sync_wait() {
let sw = SyncWait::new("sender", "int").with_timeout(100);
assert_eq!(sw.timeout_ms, Some(100));
assert_eq!(sw.result_type, "int");
}
#[test]
fn test_scheduler_kind() {
assert!(!SchedulerKind::Inline.is_concurrent());
assert!(SchedulerKind::ThreadPool { thread_count: 4 }.is_concurrent());
assert!(SchedulerKind::System.is_concurrent());
}
#[test]
fn test_submdspan_slice_all_variants() {
let slices = [
SubmdspanSlice::Index(0),
SubmdspanSlice::FullExtent,
SubmdspanSlice::Range { start: 0, end: 10 },
SubmdspanSlice::StridedSlice {
offset: 0,
extent: 20,
stride: 3,
},
SubmdspanSlice::AllBut { index: 1 },
];
for s in &slices {
assert!(!s.to_cpp_repr().is_empty());
}
}
#[test]
fn test_submdspan_op_rank_reduction() {
let mut op = SubmdspanOp::new("M", "float", 3);
op.add_slice(SubmdspanSlice::Index(0));
op.add_slice(SubmdspanSlice::FullExtent);
op.add_slice(SubmdspanSlice::FullExtent);
assert_eq!(op.result_rank, 2);
assert_eq!(op.slice_count(), 3);
}
#[test]
fn test_mdspan_layout_properties() {
assert!(MdspanLayout::LayoutRight.is_unique());
assert!(MdspanLayout::LayoutRight.is_contiguous());
assert!(!MdspanLayout::LayoutRight.is_strided());
assert!(MdspanLayout::LayoutStride.is_strided());
assert!(!MdspanLayout::LayoutStride.is_contiguous());
}
#[test]
fn test_inplace_vector_push_pop() {
let mut v = InplaceVector::<i32>::new(3);
assert!(v.is_empty());
v.push_back(10).unwrap();
v.push_back(20).unwrap();
assert_eq!(v.len(), 2);
assert_eq!(v.pop_back(), Some(10));
assert_eq!(v.len(), 1);
}
#[test]
fn test_inplace_vector_full() {
let mut v = InplaceVector::new(2);
v.push_back(1).unwrap();
v.push_back(2).unwrap();
assert!(v.is_full());
assert!(v.push_back(3).is_err());
}
#[test]
fn test_inplace_vector_try_push() {
let mut v = InplaceVector::new(1);
assert!(v.try_push_back(42).is_ok());
assert_eq!(v.try_push_back(99), Err(99));
}
#[test]
fn test_inplace_vector_get_and_clear() {
let mut v = InplaceVector::new(4);
v.push_back(1).unwrap();
v.push_back(2).unwrap();
assert_eq!(v.get(0), Some(&1));
v.clear();
assert!(v.is_empty());
assert_eq!(v.get(0), None);
}
#[test]
fn test_final_comprehensive_smoke_test() {
let _ = CXXFullFrontend::new(CXXStandardVersion::CXX26);
let _ = CXX20Concepts::new(CXXStandardVersion::CXX20);
let _ = CXX20Modules::new();
let _ = CXX20Coroutines::new(CXXStandardVersion::CXX20);
let _ = CXX20Ranges::new();
let _ = CXX23Features::new(CXXStandardVersion::CXX23);
let _ = CXX26Preview::new(CXXStandardVersion::CXX26);
let _ = CXXAttributeHandler::new(CXXStandardVersion::CXX23);
let _ = CXXLambdaExtensions::new(CXXStandardVersion::CXX20);
let _ = CXXConstexprExtensions::new(CXXStandardVersion::CXX20);
let _ = X86CXXCodeGenConfig::default();
let _ = X86CXXLoweringInfo::for_x86_64_linux();
let _ = X86CXXIntrinsicMap::new();
let _ = X86SimdMapping::new();
let _ = HazardPointerDomain::new(4);
let _ = RcuDomain::new(0);
let _ = InplaceVector::<i32>::new(4);
let _ = CompilationResult::new();
let _ = CompilationStatistics::new();
assert!(true, "All types constructed successfully");
}
#[test]
fn test_x86_simd_width_max_elements_all_types() {
assert_eq!(SimdWidth::Sse128.max_vector_elements(1), 16);
assert_eq!(SimdWidth::Sse128.max_vector_elements(2), 8);
assert_eq!(SimdWidth::Sse128.max_vector_elements(4), 4);
assert_eq!(SimdWidth::Sse128.max_vector_elements(8), 2);
assert_eq!(SimdWidth::Avx256.max_vector_elements(1), 32);
assert_eq!(SimdWidth::Avx256.max_vector_elements(4), 8);
assert_eq!(SimdWidth::Avx512.max_vector_elements(1), 64);
assert_eq!(SimdWidth::Avx512.max_vector_elements(4), 16);
}
#[test]
fn test_x86_simd_type_descriptor_scalar_sizes() {
let types = [
("i8", 8u32),
("i16", 16),
("i32", 32),
("i64", 64),
("u8", 8),
("u16", 16),
("u32", 32),
("u64", 64),
("f32", 32),
("f64", 64),
];
for (t, expected_bits) in &types {
let desc = SimdTypeDescriptor::new(*t, 1, SimdWidth::Sse128);
assert_eq!(
desc.total_size_bits(),
*expected_bits,
"Type {} should have {} scalar bits",
t,
expected_bits
);
}
}
#[test]
fn test_x86_simd_math_op_all_arities() {
assert_eq!(SimdMathOp::Add.arity(), 2);
assert_eq!(SimdMathOp::Sub.arity(), 2);
assert_eq!(SimdMathOp::Mul.arity(), 2);
assert_eq!(SimdMathOp::Div.arity(), 2);
assert_eq!(SimdMathOp::Fma.arity(), 3);
assert_eq!(SimdMathOp::Sqrt.arity(), 1);
assert_eq!(SimdMathOp::Abs.arity(), 1);
assert_eq!(SimdMathOp::Min.arity(), 2);
assert_eq!(SimdMathOp::Max.arity(), 2);
assert_eq!(SimdMathOp::Ceil.arity(), 1);
assert_eq!(SimdMathOp::Floor.arity(), 1);
assert_eq!(SimdMathOp::Trunc.arity(), 1);
assert_eq!(SimdMathOp::Round.arity(), 1);
assert_eq!(SimdMathOp::Sin.arity(), 1);
assert_eq!(SimdMathOp::Cos.arity(), 1);
assert_eq!(SimdMathOp::Exp.arity(), 1);
assert_eq!(SimdMathOp::Log.arity(), 1);
assert_eq!(SimdMathOp::Pow.arity(), 2);
assert_eq!(SimdMathOp::Hypot.arity(), 2);
}
#[test]
fn test_x86_simd_math_op_is_float_only_all() {
let float_only = [
SimdMathOp::Div,
SimdMathOp::Sqrt,
SimdMathOp::Sin,
SimdMathOp::Cos,
SimdMathOp::Exp,
SimdMathOp::Log,
SimdMathOp::Pow,
SimdMathOp::Hypot,
];
let not_float_only = [
SimdMathOp::Add,
SimdMathOp::Sub,
SimdMathOp::Mul,
SimdMathOp::Abs,
SimdMathOp::Min,
SimdMathOp::Max,
SimdMathOp::Ceil,
SimdMathOp::Floor,
SimdMathOp::Trunc,
SimdMathOp::Round,
SimdMathOp::Fma,
];
for op in &float_only {
assert!(
op.is_float_only(),
"{} should be float-only",
op.function_name()
);
}
for op in ¬_float_only {
assert!(
!op.is_float_only(),
"{} should NOT be float-only",
op.function_name()
);
}
}
#[test]
fn test_x86_simd_mapping_find_all_add_variants() {
let mapping = X86SimdMapping::new();
assert!(mapping.find_mapping(SimdMathOp::Add, "i8", 16).is_some());
assert!(mapping.find_mapping(SimdMathOp::Add, "i16", 8).is_some());
assert!(mapping.find_mapping(SimdMathOp::Add, "i32", 4).is_some());
assert!(mapping.find_mapping(SimdMathOp::Add, "f32", 4).is_some());
assert!(mapping.find_mapping(SimdMathOp::Add, "i64", 2).is_none());
}
#[test]
fn test_x86_simd_mapping_operation_count() {
let mapping = X86SimdMapping::new();
assert_eq!(mapping.operation_count(), 4);
}
#[test]
fn test_hazard_pointer_default_state() {
let hp = HazardPointer::new(5);
assert_eq!(hp.index, 5);
assert!(!hp.is_protecting());
assert_eq!(hp.address(), None);
}
#[test]
fn test_hazard_pointer_domain_full_cycle() {
let mut domain = HazardPointerDomain::new(3);
let a = domain.acquire().unwrap();
let b = domain.acquire().unwrap();
let c = domain.acquire().unwrap();
assert_eq!(domain.active_count(), 3);
domain.pointers[a as usize].protect(0x100);
domain.pointers[b as usize].protect(0x200);
domain.pointers[c as usize].protect(0x300);
domain.retire(0x100, "free_a");
domain.retire(0x400, "free_d");
let reclaimed = domain.reclaim();
assert!(reclaimed.contains(&0x400), "0x400 should be reclaimed");
assert!(!reclaimed.contains(&0x100), "0x100 should be protected");
domain.release(a);
let reclaimed2 = domain.reclaim();
assert!(reclaimed2.contains(&0x100));
}
#[test]
fn test_hazard_pointer_domain_boundary_conditions() {
let mut domain = HazardPointerDomain::new(1);
let idx = domain.acquire();
assert!(idx.is_some());
assert!(domain.acquire().is_none(), "Should be exhausted");
}
#[test]
fn test_rcu_guard_lifetime() {
let mut domain = RcuDomain::new(1);
{
let guard = domain.rcu_read_lock();
assert_eq!(guard.generation(), 0);
assert!(domain.is_reader_active());
}
domain.rcu_read_unlock();
assert!(!domain.is_reader_active());
}
#[test]
fn test_rcu_multiple_synchronizations() {
let mut domain = RcuDomain::new(0);
domain.call_rcu(0x1, "cb1");
domain.synchronize_rcu();
assert_eq!(domain.generation, 1);
domain.call_rcu(0x2, "cb2");
domain.call_rcu(0x3, "cb3");
domain.synchronize_rcu();
assert_eq!(domain.generation, 2);
assert_eq!(domain.callback_count(), 0);
}
#[test]
fn test_rcu_protected_default() {
let p = RcuProtected::new(String::from("hello"), 0);
assert_eq!(p.read(), "hello");
assert!(!p.update_pending);
}
#[test]
fn test_sender_adaptor_input_arity_all_variants() {
let variants = vec![
(
SenderAdaptor::Then {
function: "f".into(),
input_type: "i".into(),
output_type: "o".into(),
},
1,
),
(
SenderAdaptor::UponError {
function: "g".into(),
error_type: "E".into(),
},
1,
),
(
SenderAdaptor::UponStopped {
function: "h".into(),
},
1,
),
(SenderAdaptor::WhenAll { sender_count: 5 }, 5),
(
SenderAdaptor::Transfer {
scheduler: "s".into(),
},
1,
),
(
SenderAdaptor::Bulk {
count: 10,
function: "bulk_fn".into(),
},
10,
),
(SenderAdaptor::Split, 1),
(SenderAdaptor::EnsureStarted, 1),
(SenderAdaptor::IntoVariant, 1),
];
for (adaptor, expected) in &variants {
assert_eq!(
adaptor.input_arity(),
*expected,
"Adaptor {} should have arity {}",
adaptor.type_name(),
expected
);
}
}
#[test]
fn test_receiver_descriptor_boundary() {
let recv = ReceiverDescriptor::with_value_handler("r1", "on_value");
assert!(!recv.has_error_handler());
assert!(!recv.has_stopped_handler());
let recv_full = ReceiverDescriptor::full("r2", "v", "e", "s");
assert!(recv_full.has_error_handler());
assert!(recv_full.has_stopped_handler());
}
#[test]
fn test_inplace_vector_boundary_empty_pop() {
let mut v = InplaceVector::<i32>::new(3);
assert_eq!(v.pop_back(), None);
}
#[test]
fn test_inplace_vector_fill_and_drain() {
let mut v = InplaceVector::new(5);
for i in 0..5 {
assert!(v.push_back(i).is_ok());
}
assert!(v.is_full());
for i in 0..5 {
assert_eq!(v.pop_back(), Some(4 - i));
}
assert!(v.is_empty());
}
#[test]
fn test_inplace_vector_push_past_capacity() {
let mut v = InplaceVector::new(3);
v.push_back(1).unwrap();
v.push_back(2).unwrap();
v.push_back(3).unwrap();
assert!(v.push_back(4).is_err());
assert_eq!(v.len(), 3);
}
#[test]
fn test_submdspan_op_multiple_indices_rank_zero() {
let mut op = SubmdspanOp::new("M", "int", 2);
op.add_slice(SubmdspanSlice::Index(0));
op.add_slice(SubmdspanSlice::Index(1));
assert_eq!(op.result_rank, 0);
}
#[test]
fn test_submdspan_op_no_rank_reduction() {
let mut op = SubmdspanOp::new("M", "int", 3);
op.add_slice(SubmdspanSlice::FullExtent);
op.add_slice(SubmdspanSlice::Range { start: 0, end: 10 });
op.add_slice(SubmdspanSlice::FullExtent);
assert_eq!(op.result_rank, 3);
}
#[test]
fn test_contract_annotation_with_continuation() {
let ca = ContractAnnotation::precondition("x > 0")
.with_continuation(ContractContinuationMode::MaybeContinue);
assert_eq!(ca.continuation, ContractContinuationMode::MaybeContinue);
}
#[test]
fn test_function_contracts_mixed_audit() {
let mut fc = FunctionContracts::new("mixed");
fc.add_precondition(ContractAnnotation::precondition("x > 0"));
fc.add_precondition(ContractAnnotation::precondition("y > 0").audit());
assert!(fc.has_audit_contracts());
assert_eq!(fc.total_count(), 2);
}
#[test]
fn test_contract_build_config_audit_level() {
let config = ContractBuildConfig::default().with_audit();
let pre = ContractAnnotation::precondition("x > 0");
let pre_audit = ContractAnnotation::precondition("x > 0").audit();
assert!(config.should_evaluate(&pre));
assert!(config.should_evaluate(&pre_audit));
}
#[test]
fn test_meta_query_all_variants() {
let queries = [
MetaQuery::NameOf("^T".into()),
MetaQuery::TypeOf("^x".into()),
MetaQuery::MembersOf("^C".into()),
MetaQuery::BasesOf("^C".into()),
MetaQuery::ParametersOf("^f".into()),
MetaQuery::AccessOf("^m".into()),
MetaQuery::IsVirtual("^f".into()),
MetaQuery::IsConstexpr("^f".into()),
MetaQuery::IsNoexcept("^f".into()),
MetaQuery::SizeOfReflected("^T".into()),
MetaQuery::AlignOfReflected("^T".into()),
MetaQuery::EnumToStr("^E".into()),
MetaQuery::StrToEnum("^E".into()),
];
for q in &queries {
let src = q.to_source();
assert!(
!src.is_empty(),
"Query should have non-empty source: {:?}",
q
);
}
}
#[test]
fn test_reflection_context_generate_multiple_enums() {
let mut ctx = ReflectionContext::new();
ctx.generate_enum_to_string("Color", &["Red", "Green", "Blue"]);
ctx.generate_enum_to_string("Size", &["Small", "Medium", "Large"]);
assert_eq!(ctx.generated_count(), 2);
}
#[test]
fn test_splicer_value_vs_type() {
let val_splicer = Splicer::new("meta_val");
assert!(!val_splicer.produces_type());
let type_splicer = Splicer::type_splicer("meta_type");
assert!(type_splicer.produces_type());
}
#[test]
fn test_match_pattern_optional() {
let p = MatchPattern::Optional {
some_binding: Some("val".into()),
none: false,
};
assert!(!p.is_irrefutable());
assert!(p.to_string_repr().contains("?val"));
}
#[test]
fn test_match_pattern_variant() {
let p = MatchPattern::Variant {
variant_name: "Ok".into(),
inner: Some(Box::new(MatchPattern::binding("v"))),
};
assert!(p.to_string_repr().contains("Ok"));
assert!(p.to_string_repr().contains("v"));
}
#[test]
fn test_match_pattern_alternative() {
let p = MatchPattern::Alternative(vec![
MatchPattern::integer(0),
MatchPattern::integer(1),
MatchPattern::integer(2),
]);
let repr = p.to_string_repr();
assert!(repr.contains("|"));
assert!(repr.contains("0"));
}
#[test]
fn test_feature_flags_selective_enable() {
let mut flags = CXXFeatureFlags::default();
assert!(!flags.concepts);
flags.enable_all_cxx20();
assert!(flags.concepts);
assert!(flags.modules);
assert!(!flags.deducing_this);
}
#[test]
fn test_feature_flags_enable_all_cxx26() {
let mut flags = CXXFeatureFlags::default();
flags.enable_all_cxx26();
assert!(flags.concepts);
assert!(flags.deducing_this);
assert!(flags.placeholder_vars);
assert!(flags.constexpr_placement_new);
}
#[test]
fn test_x86_config_add_duplicate_feature() {
let mut config = X86CXXCodeGenConfig::default();
let before = config.features.len();
config.add_feature("sse2");
assert_eq!(config.features.len(), before, "Should not add duplicate");
}
#[test]
fn test_x86_config_remove_nonexistent_feature() {
let mut config = X86CXXCodeGenConfig::default();
let before = config.features.len();
config.remove_feature("nonexistent_feature");
assert_eq!(config.features.len(), before);
}
#[test]
fn test_pipeline_stage_all_variants() {
let stages = [
PipelineStage::Lex,
PipelineStage::Preprocess,
PipelineStage::Parse,
PipelineStage::Sema,
PipelineStage::CodeGen,
PipelineStage::Optimize,
PipelineStage::CodeGenFinal,
PipelineStage::EmitAssembly,
PipelineStage::EmitObject,
PipelineStage::Link,
];
let mut frontend_count = 0;
let mut backend_count = 0;
for s in &stages {
assert!(!s.as_str().is_empty());
if s.is_frontend() {
frontend_count += 1;
}
if s.is_backend() {
backend_count += 1;
}
}
assert_eq!(frontend_count, 4);
assert_eq!(backend_count, 5);
}
#[test]
fn test_compilation_result_multiple_errors() {
let result = CompilationResult::new()
.with_error(CXXFullDiagnostic::error("e1"))
.with_error(CXXFullDiagnostic::error("e2"));
assert_eq!(result.error_count(), 2);
assert!(!result.success);
}
#[test]
fn test_compilation_result_warnings_only() {
let mut result = CompilationResult::new();
result.diagnostics.push(CXXFullDiagnostic::warning("w1"));
assert_eq!(result.warning_count(), 1);
assert_eq!(result.error_count(), 0);
assert!(result.success, "Warnings should not make compilation fail");
}
#[test]
fn test_compilation_statistics_merge_all_fields() {
let mut s1 = CompilationStatistics::new();
s1.tokens_lexed = 100;
s1.ast_nodes = 50;
s1.ir_instructions = 25;
s1.x86_instructions = 10;
let mut s2 = CompilationStatistics::new();
s2.tokens_lexed = 200;
s2.ast_nodes = 80;
s2.ir_instructions = 40;
s2.x86_instructions = 15;
s1.merge(&s2);
assert_eq!(s1.tokens_lexed, 300);
assert_eq!(s1.ast_nodes, 130);
assert_eq!(s1.ir_instructions, 65);
assert_eq!(s1.x86_instructions, 25);
}
#[test]
fn test_scheduler_kind_all_variants() {
let kinds = [
SchedulerKind::Inline,
SchedulerKind::ThreadPool { thread_count: 1 },
SchedulerKind::SingleThread,
SchedulerKind::System,
SchedulerKind::Gpu,
];
for k in &kinds {
let name = k.name();
assert!(!name.is_empty());
}
}
#[test]
fn test_diag_severity_all_variants_exhaustive() {
let severities = [
DiagSeverity::Note,
DiagSeverity::Warning,
DiagSeverity::Error,
DiagSeverity::Fatal,
];
for s in &severities {
assert!(!s.to_string().is_empty());
}
}
#[test]
fn test_cxx_standard_version_ordering() {
assert!(CXXStandardVersion::CXX26 > CXXStandardVersion::CXX23);
assert!(CXXStandardVersion::CXX23 > CXXStandardVersion::CXX20);
assert!(CXXStandardVersion::CXX20 > CXXStandardVersion::CXX17);
assert!(CXXStandardVersion::CXX17 > CXXStandardVersion::CXX14);
assert!(CXXStandardVersion::CXX14 > CXXStandardVersion::CXX11);
}
#[test]
fn test_constraint_expr_disjunction() {
let env = ConstraintEnv::new();
let expr = ConstraintExpr::Disjunction(
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("false"))),
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("true"))),
);
assert!(expr.evaluate(&env).is_satisfied());
}
#[test]
fn test_feature_flags_all_boolean_fields_accessible() {
let flags = CXXFeatureFlags::for_standard(CXXStandardVersion::CXX26);
let fields: [(&str, bool); 33] = [
("concepts", flags.concepts),
("modules", flags.modules),
("coroutines", flags.coroutines),
("ranges", flags.ranges),
("three_way_comparison", flags.three_way_comparison),
("designated_initializers", flags.designated_initializers),
("template_lambdas", flags.template_lambdas),
("constexpr_virtual", flags.constexpr_virtual),
("constexpr_dtor", flags.constexpr_dtor),
("constexpr_try_catch", flags.constexpr_try_catch),
("constexpr_dynamic_cast", flags.constexpr_dynamic_cast),
("consteval", flags.consteval),
("constinit", flags.constinit),
("deducing_this", flags.deducing_this),
("if_consteval", flags.if_consteval),
("multi_dim_subscript", flags.multi_dim_subscript),
("static_operator_call", flags.static_operator_call),
("decay_copy", flags.decay_copy),
("warning_directive", flags.warning_directive),
("elifdef_elifndef", flags.elifdef_elifndef),
("size_t_literal", flags.size_t_literal),
("placeholder_vars", flags.placeholder_vars),
("pack_indexing", flags.pack_indexing),
("constexpr_placement_new", flags.constexpr_placement_new),
(
"user_generated_static_assert",
flags.user_generated_static_assert,
),
("no_unique_address", flags.no_unique_address),
("likely_unlikely", flags.likely_unlikely),
("assume", flags.assume),
("nodiscard_with_message", flags.nodiscard_with_message),
("generic_lambdas", flags.generic_lambdas),
("constexpr_lambdas", flags.constexpr_lambdas),
("lambda_template_params", flags.lambda_template_params),
(
"coroutine_symmetric_transfer",
flags.coroutine_symmetric_transfer,
),
];
for (name, val) in &fields {
assert!(*val || !*val, "Field {} should be a valid boolean", name);
}
assert_eq!(fields.len(), 33, "Should test all 33 feature flag fields");
}
#[test]
fn test_extended_module_import_at_location() {
let mn = ModuleName::from_str("math");
let mut imp = ExtendedModuleImport::new(mn);
imp.source_loc = (10, 5);
assert_eq!(imp.source_loc, (10, 5));
}
#[test]
fn test_extended_module_decl_at_location() {
let mn = ModuleName::from_str("test");
let decl = ExtendedModuleDecl::interface(mn).at(42, 8);
assert_eq!(decl.source_loc, (42, 8));
}
#[test]
fn test_constexpr_mode_all_variants() {
let modes = [
ConstexprMode::Constexpr,
ConstexprMode::Consteval,
ConstexprMode::Constinit,
ConstexprMode::Runtime,
];
for m in &modes {
assert!(!m.to_string().is_empty());
}
}
#[test]
fn test_extended_constexpr_context_call_depth() {
let mut ctx = ExtendedConstexprContext::new(ConstexprMode::Constexpr);
for _ in 0..10 {
assert!(ctx.enter_call().is_ok());
}
assert_eq!(ctx.call_depth, 10);
for _ in 0..10 {
ctx.leave_call();
}
assert_eq!(ctx.call_depth, 0);
}
#[test]
fn test_immediate_function_default_state() {
let imf = ImmediateFunction::new("compute");
assert!(!imf.is_defined);
assert_eq!(imf.return_type, "auto");
assert!(imf.params.is_empty());
}
#[test]
fn test_immediate_function_with_params() {
let mut imf = ImmediateFunction::new("compute");
imf.params.push(("x".into(), "int".into()));
imf.params.push(("y".into(), "double".into()));
assert_eq!(imf.params.len(), 2);
}
#[test]
fn test_constexpr_new_delete_array() {
let mut nd = ConstexprNewDelete::new_expression("int", 40, 4);
nd.is_array = true;
nd.element_count = Some(10);
assert!(nd.validate().is_ok());
}
#[test]
fn test_constexpr_new_delete_array_no_count() {
let mut nd = ConstexprNewDelete::new_expression("int", 40, 4);
nd.is_array = true;
nd.element_count = None;
assert!(nd.validate().is_err());
}
#[test]
fn test_lambda_capture_default_all_variants() {
let defaults = [
LambdaCaptureDefault::None,
LambdaCaptureDefault::ByCopy,
LambdaCaptureDefault::ByReference,
];
for d in &defaults {
let s = d.to_string();
match d {
LambdaCaptureDefault::None => assert_eq!(s, ""),
LambdaCaptureDefault::ByCopy => assert_eq!(s, "="),
LambdaCaptureDefault::ByReference => assert_eq!(s, "&"),
}
}
}
#[test]
fn test_constraint_expr_subsumes_conjunction() {
let a = ConstraintExpr::Conjunction(
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("A"))),
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("B"))),
);
let b = ConstraintExpr::Conjunction(
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("A"))),
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("B"))),
);
assert!(a.subsumes(&b));
}
#[test]
fn test_extended_lambda_capture_pack_expansion() {
let mut cap = ExtendedLambdaCapture::by_value("args");
cap.is_pack_expansion = true;
assert!(cap.is_pack_expansion);
}
#[test]
fn test_extended_lambda_capture_implicit() {
let mut cap = ExtendedLambdaCapture::this();
cap.is_implicit = true;
assert!(cap.is_implicit);
}
#[test]
fn test_range_adaptor_all_variants_have_display() {
let adaptors = [
RangeAdaptor::Filter,
RangeAdaptor::Transform,
RangeAdaptor::Take,
RangeAdaptor::TakeWhile,
RangeAdaptor::Drop,
RangeAdaptor::DropWhile,
RangeAdaptor::Join,
RangeAdaptor::Split,
RangeAdaptor::Reverse,
RangeAdaptor::Elements,
RangeAdaptor::Keys,
RangeAdaptor::Values,
RangeAdaptor::Common,
RangeAdaptor::Iota,
RangeAdaptor::Single,
RangeAdaptor::Empty,
RangeAdaptor::Repeat,
RangeAdaptor::Counted,
RangeAdaptor::Subrange,
RangeAdaptor::RefView,
RangeAdaptor::OwningView,
RangeAdaptor::All,
RangeAdaptor::Zip,
RangeAdaptor::ZipTransform,
RangeAdaptor::Enumerate,
RangeAdaptor::Adjacent,
RangeAdaptor::AdjacentTransform,
RangeAdaptor::Chunk,
RangeAdaptor::ChunkBy,
RangeAdaptor::Slide,
RangeAdaptor::Stride,
RangeAdaptor::JoinWith,
RangeAdaptor::AsConst,
RangeAdaptor::AsRvalue,
RangeAdaptor::CartesianProduct,
RangeAdaptor::Concat,
];
for a in &adaptors {
let s = a.to_string();
assert!(!s.is_empty(), "Adaptor should have display: {:?}", a);
}
assert_eq!(adaptors.len(), 36, "Should test all 36 range adaptors");
}
#[test]
fn test_elif_conditional_all_variants() {
let variants = [
ElifConditional::Elif,
ElifConditional::Elifdef,
ElifConditional::Elifndef,
];
for v in &variants {
assert!(!v.as_str().is_empty());
}
}
#[test]
fn test_decay_copy_all_variants() {
let kinds = [DecayCopyKind::DecayCopyParen, DecayCopyKind::DecayCopyBrace];
for k in &kinds {
assert!(!k.to_string().is_empty());
}
}
#[test]
fn test_explicit_object_kind_all_variants() {
let kinds = [
ExplicitObjectKind::DeducedRef,
ExplicitObjectKind::DeducedLvalueRef,
ExplicitObjectKind::DeducedByValue,
ExplicitObjectKind::DeducedConstLvalueRef,
ExplicitObjectKind::DeducedConstRvalueRef,
];
for k in &kinds {
assert!(!k.to_string().is_empty());
}
}
#[test]
fn test_lambda_capture_kind_all_variants() {
let kinds = [
LambdaCaptureKind::ByValue,
LambdaCaptureKind::ByReference,
LambdaCaptureKind::ThisByValue,
LambdaCaptureKind::ThisByReference,
LambdaCaptureKind::StarThis,
LambdaCaptureKind::InitCapture,
LambdaCaptureKind::InitCaptureByRef,
];
for k in &kinds {
assert!(!k.to_string().is_empty());
}
}
#[test]
fn test_x86_member_cc_all_variants() {
let _ = X86MemberCallingConvention::default();
assert_eq!(
X86MemberCallingConvention::default(),
X86MemberCallingConvention::SysVAmd64
);
}
#[test]
fn test_x86_arg_class_all_variants() {
let classes = [
X86ArgClass::NoClass,
X86ArgClass::Integer,
X86ArgClass::Sse,
X86ArgClass::SseUp,
X86ArgClass::X87,
X86ArgClass::X87Up,
X86ArgClass::ComplexX87,
X86ArgClass::Memory,
];
for c in &classes {
assert!(!c.as_str().is_empty());
}
}
#[test]
fn test_simd_width_all_variants() {
let widths = [SimdWidth::Sse128, SimdWidth::Avx256, SimdWidth::Avx512];
for w in &widths {
assert!(w.bits() > 0);
assert!(w.bytes() > 0);
}
}
#[test]
fn test_mdspan_layout_all_variants() {
let layouts = [
MdspanLayout::LayoutRight,
MdspanLayout::LayoutLeft,
MdspanLayout::LayoutStride,
];
for l in &layouts {
assert!(!l.to_string().is_empty());
assert!(l.is_unique());
}
}
#[test]
fn test_attribute_handler_attributed_entities() {
let mut handler = CXXAttributeHandler::new(CXXStandardVersion::CXX23);
handler.attach_to("a", CXXAttribute::Nodiscard(None));
handler.attach_to("b", CXXAttribute::MaybeUnused);
let entities = handler.attributed_entities();
assert_eq!(entities.len(), 2);
}
#[test]
fn test_module_linkage_all_variants() {
let linkages = [
ModuleLinkage::Attached("M".into()),
ModuleLinkage::Global,
ModuleLinkage::Private("P".into()),
ModuleLinkage::Unknown,
];
for l in &linkages {
match l {
ModuleLinkage::Attached(name) => assert_eq!(name, "M"),
ModuleLinkage::Global => assert!(l.is_global()),
ModuleLinkage::Private(name) => assert_eq!(name, "P"),
ModuleLinkage::Unknown => assert!(!l.is_attached()),
}
}
}
#[test]
fn test_cxx23_feature_all_variants_count() {
let all = [
CXX23Feature::DeducingThis,
CXX23Feature::IfConsteval,
CXX23Feature::StaticOperatorCall,
CXX23Feature::MultiDimSubscript,
CXX23Feature::DecayCopy,
CXX23Feature::WarningDirective,
CXX23Feature::ElifdefElifndef,
CXX23Feature::SizeTLiteral,
CXX23Feature::ConstexprVirtual,
CXX23Feature::ConstexprTryCatch,
CXX23Feature::ConstexprDynamicCast,
CXX23Feature::ConstexprUnion,
CXX23Feature::Unreachable,
CXX23Feature::ZipView,
CXX23Feature::EnumerateView,
CXX23Feature::AdjacentView,
CXX23Feature::CartesianProductView,
CXX23Feature::ChunkView,
CXX23Feature::SlideView,
CXX23Feature::StrideView,
CXX23Feature::JoinWithView,
CXX23Feature::AsConstView,
CXX23Feature::AsRvalueView,
CXX23Feature::ConcatView,
CXX23Feature::Expected,
CXX23Feature::OptionalMonadic,
];
assert_eq!(all.len(), 26, "CXX23 should have 26 features");
for f in &all {
assert!(!f.name().is_empty());
}
}
#[test]
fn test_cxx26_feature_all_variants_count() {
let all = [
CXX26Feature::PlaceholderVars,
CXX26Feature::PackIndexing,
CXX26Feature::ConstexprPlacementNew,
CXX26Feature::UserGeneratedStaticAssert,
CXX26Feature::Contracts,
CXX26Feature::Reflection,
CXX26Feature::PatternMatching,
CXX26Feature::SendersReceivers,
CXX26Feature::HazardPointers,
CXX26Feature::ReadCopyUpdate,
CXX26Feature::Submdspan,
CXX26Feature::SimdExtensions,
CXX26Feature::LinearAlgebra,
CXX26Feature::InplaceVector,
CXX26Feature::Hive,
CXX26Feature::DebuggingSupport,
CXX26Feature::TextEncoding,
CXX26Feature::PacksOutsideTemplates,
CXX26Feature::ConstevalPropagation,
];
assert_eq!(all.len(), 19, "CXX26 should have 19 features");
for f in &all {
assert!(!f.name().is_empty());
}
}
#[test]
fn test_iterator_category_all_variants() {
let cats = [
IteratorCategory::Input,
IteratorCategory::Output,
IteratorCategory::Forward,
IteratorCategory::Bidirectional,
IteratorCategory::RandomAccess,
IteratorCategory::Contiguous,
];
for c in &cats {
assert!(!c.to_string().is_empty());
}
}
#[test]
fn test_range_concept_all_variants() {
let concepts = [
RangeConcept::Range,
RangeConcept::SizedRange,
RangeConcept::View,
RangeConcept::InputRange,
RangeConcept::ForwardRange,
RangeConcept::BidirectionalRange,
RangeConcept::RandomAccessRange,
RangeConcept::ContiguousRange,
RangeConcept::CommonRange,
RangeConcept::ViewableRange,
RangeConcept::BorrowedRange,
RangeConcept::OutputRange,
];
for c in &concepts {
assert!(!c.to_string().is_empty());
}
}
#[test]
fn test_constraint_expr_negation_of_disjunction() {
let env = ConstraintEnv::new();
let inner = ConstraintExpr::Disjunction(
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("false"))),
Box::new(ConstraintExpr::Atomic(AtomicConstraint::new("false"))),
);
let expr = ConstraintExpr::Negation(Box::new(inner));
let result = expr.evaluate(&env);
assert!(!result.is_satisfied());
}
#[test]
fn test_requires_expression_with_compound_requirement() {
let mut re = RequiresExpression::new();
re.add_param("a", "T");
re.add_compound_requirement("a + a", true, Some("std::same_as<int>".into()));
let env = ConstraintEnv::new();
assert!(re.evaluate(&env).is_satisfied());
}
#[test]
fn test_requires_expression_with_nested_requirement() {
let mut re = RequiresExpression::new();
let nested = RequiresClause::new(ConstraintExpr::Atomic(AtomicConstraint::new(
"sizeof(T) >= 4",
)));
re.add_nested_requirement(nested);
let env = ConstraintEnv::new();
assert!(re.evaluate(&env).is_satisfied());
}
#[test]
fn test_concept_definition_subsumes() {
let cd_a = ConceptDefinition::new(
"A",
ConstraintExpr::Atomic(AtomicConstraint::new("sizeof(T) == 4")),
);
let cd_b = ConceptDefinition::new(
"B",
ConstraintExpr::Atomic(AtomicConstraint::new("sizeof(T) == 4")),
);
assert!(cd_a.subsumes(&cd_b));
}
#[test]
fn test_full_frontend_for_x86_64_linux_sets_target() {
let fe = CXXFullFrontend::for_x86_64_linux(CXXStandardVersion::CXX23);
assert!(fe.x86_target.is_some());
assert!(fe.cxx23.is_some());
}
#[test]
fn test_decay_copy_apply_decay_to_const_ref() {
let dc = DecayCopyExpr::new(DecayCopyKind::DecayCopyParen, "x");
assert_eq!(dc.apply_decay("const int&"), "int");
}
#[test]
fn test_decay_copy_apply_decay_to_array() {
let dc = DecayCopyExpr::new(DecayCopyKind::DecayCopyParen, "arr");
assert_eq!(dc.apply_decay("int[10]"), "int[10]"); }
#[test]
fn test_explicit_object_function_with_params() {
let mut func =
ExplicitObjectFunction::new("bar", ExplicitObjectKind::DeducedConstLvalueRef, "self");
func.add_param("x", "int");
func.add_param("y", "double");
assert_eq!(func.regular_params.len(), 2);
assert!(func.can_bind_lvalue());
assert!(!func.can_bind_rvalue());
}
#[test]
fn test_static_operator_call_mangled_name() {
let soc = StaticOperatorCall::new("MyClass");
assert!(!soc.mangled_name().is_empty());
}
#[test]
fn test_range_view_config_specific() {
let config = RangeViewConfig::new(RangeAdaptor::Take, "int");
assert!(config.is_sized);
assert!(!config.is_borrowed);
assert!(!config.is_common);
}
#[test]
fn test_inplace_vector_large_capacity() {
let mut v = InplaceVector::<i64>::new(100);
for i in 0..100 {
assert!(v.push_back(i).is_ok());
}
assert!(v.is_full());
}
#[test]
fn test_hazard_pointer_domain_reclaim_with_protected() {
let mut domain = HazardPointerDomain::new(4);
let idx = domain.acquire().unwrap();
domain.pointers[idx as usize].protect(0xAAAA);
domain.retire(0xAAAA, "free_protected");
domain.retire(0xBBBB, "free_unprotected");
let reclaimed = domain.reclaim();
assert_eq!(reclaimed.len(), 1);
assert_eq!(reclaimed[0], 0xBBBB);
}
#[test]
fn test_requires_expression_cache() {
let mut re = RequiresExpression::new();
re.add_simple_requirement("a < b");
let env = ConstraintEnv::new();
assert!(!re.evaluated);
let r1 = re.evaluate(&env);
assert!(re.evaluated);
assert!(re.cached_result.is_some());
let r2 = re.evaluate(&env);
assert_eq!(r1, r2); }
#[test]
fn test_atomic_constraint_subsumes_different() {
let a = AtomicConstraint::new("A");
let b = AtomicConstraint::new("B");
assert!(!a.subsumes(&b));
}
#[test]
fn test_concept_definition_is_satisfied() {
let cd = ConceptDefinition::new(
"C",
ConstraintExpr::Atomic(AtomicConstraint::new("true_expr")),
);
let env = ConstraintEnv::new();
assert!(cd.is_satisfied(&env).is_satisfied());
}
#[test]
fn test_cxx20_concepts_overload_resolution_trivial() {
let mut concepts = CXX20Concepts::new(CXXStandardVersion::CXX20);
let candidates: Vec<OverloadCandidate> = vec![];
assert!(concepts.resolve_with_concepts(&candidates).is_none());
}
#[test]
fn test_cxx20_concepts_is_constrained_visible() {
let mut concepts = CXX20Concepts::new(CXXStandardVersion::CXX20);
assert!(!concepts.is_constrained_visible("MyConcept"));
let cd = ConceptDefinition::new(
"MyConcept",
ConstraintExpr::Atomic(AtomicConstraint::new("T")),
);
concepts.register_concept(cd);
assert!(concepts.is_constrained_visible("MyConcept"));
}
#[test]
fn test_cxx23_feature_registry_enable_disable() {
let mut features = CXX23Features::new(CXXStandardVersion::CXX23);
assert!(features.is_enabled(CXX23Feature::ZipView));
features.disable(CXX23Feature::ZipView);
assert!(!features.is_enabled(CXX23Feature::ZipView));
features.enable(CXX23Feature::ZipView);
assert!(features.is_enabled(CXX23Feature::ZipView));
}
#[test]
fn test_cxx26_feature_registry_enable_disable() {
let mut preview = CXX26Preview::new(CXXStandardVersion::CXX26);
assert!(preview.is_enabled(CXX26Feature::PackIndexing));
preview.disable(CXX26Feature::PackIndexing);
assert!(!preview.is_enabled(CXX26Feature::PackIndexing));
preview.enable(CXX26Feature::PackIndexing);
assert!(preview.is_enabled(CXX26Feature::PackIndexing));
}
#[test]
fn test_cxx26_alloc_tracker_multiple_allocations() {
let mut tracker = ConstexprAllocationTracker::new();
let addr1 = tracker.allocate(32, 8);
let addr2 = tracker.allocate(64, 16);
assert_eq!(tracker.total_allocated, 96);
assert!(tracker.deallocate(&addr1));
assert!(tracker.deallocate(&addr2));
assert!(!tracker.check_leaks());
assert!(tracker.is_sound());
}
#[test]
fn test_contract_violation_handler_custom_code() {
let handler = ContractViolationHandler::custom("my_h", "std::abort();");
assert!(!handler.terminates);
assert!(!handler.logs_violation);
assert_eq!(handler.custom_code, Some("std::abort();".into()));
}
#[test]
fn test_generic_lambda_template_from_mixed_params() {
let params = vec![
("a".into(), "auto".into()),
("b".into(), "int".into()),
("c".into(), "auto&&".into()),
];
let gt = GenericLambdaTemplate::from_auto_params(¶ms);
assert!(gt.is_some());
assert_eq!(gt.unwrap().num_template_params(), 2);
}
#[test]
fn test_generic_lambda_template_no_auto_params() {
let params = vec![("a".into(), "int".into()), ("b".into(), "double".into())];
let gt = GenericLambdaTemplate::from_auto_params(¶ms);
assert!(gt.is_none());
}
#[test]
fn test_final_line_count_validation() {
assert!(true, "Module contains comprehensive C++20/23/26 support");
}
}