1use std::collections::{HashMap, HashSet};
35
36use rucc_ast::{
37 self as ast, ArraySize, Complexity, Derived, ParamKind, Scalar, TypeSpec, TypeofArg,
38};
39use rucc_base::float::Format;
40use rucc_base::{Idx, Symbol, sym};
41use rucc_diag::{Diagnostic, Span};
42use rucc_session::Std;
43use rucc_target::{TargetInfo, VaList};
44use rucc_types::{
45 ArrayLen, FieldDecl, FloatKind, FunctionType, IntKind, Qualifiers, RecordKind, RecordOptions,
46 TypeId, adjust_parameter, is_complete, is_function, is_integer, is_pointer, is_void, layout,
47};
48
49use crate::check::Checker;
50use crate::decl::DeclId;
51use crate::scope::{Binding, Tag, TagKind};
52
53mod tag;
54
55const MAX_BIT_INT_WIDTH: u32 = 128;
64
65#[derive(Debug, Default)]
67pub(crate) struct Built {
68 specified: HashMap<ast::DeclSpecsId, TypeId>,
75 defined: HashSet<TypeId>,
82 params: HashMap<Idx<ast::Param>, Vec<DeclId>>,
91 va_list: Option<TypeId>,
98}
99
100#[derive(Debug, Clone, Copy)]
107struct Subject {
108 name: Option<Symbol>,
110 span: Span,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116enum TagUse {
117 Known(TypeId),
119 New,
121 Anonymous,
123 Wrong,
125}
126
127#[derive(Debug, Clone, Copy, Default)]
129pub(in crate::check) struct Place {
130 parameter: bool,
133 member: bool,
136 prototype: bool,
139}
140
141pub(in crate::check) const MEMBER: Place =
143 Place { parameter: false, member: true, prototype: false };
144
145impl Checker<'_> {
146 pub fn type_name(&mut self, id: ast::TypeNameId) -> TypeId {
148 let name = self.ast[id];
149 self.declared_type(name.specs, name.declarator)
150 }
151
152 pub fn declared_type(
158 &mut self,
159 specs: ast::DeclSpecsId,
160 declarator: ast::DeclaratorId,
161 ) -> TypeId {
162 self.build_type(specs, declarator, Place::default())
163 }
164
165 pub(in crate::check) fn declared_specs(&mut self, specs: ast::DeclSpecsId) -> TypeId {
170 let span = self.ast[specs].span;
171 self.specified_type(specs, Subject { name: None, span }, Place::default())
172 }
173
174 pub fn declare_typedef(&mut self, name: Symbol, ty: TypeId) {
180 self.scopes.declare(name, Binding::Typedef(ty));
181 }
182
183 fn build_type(
185 &mut self,
186 specs: ast::DeclSpecsId,
187 declarator: ast::DeclaratorId,
188 place: Place,
189 ) -> TypeId {
190 let node = self.ast[declarator];
191 let subject = Subject {
192 name: node.name,
193 span: if node.name.is_some() { node.name_span } else { node.span },
194 };
195 let base = self.specified_type(specs, subject, place);
196 self.derive(base, declarator, subject, place)
197 }
198
199 fn specified_type(&mut self, id: ast::DeclSpecsId, subject: Subject, place: Place) -> TypeId {
206 if let Some(&ty) = self.built.specified.get(&id) {
207 return ty;
208 }
209 let specs = self.ast[id];
210 let base = self.type_spec(specs.ty, specs.span, subject, place);
211 let ty = self.qualify(base, specs.quals, specs.span);
212 self.built.specified.insert(id, ty);
213 ty
214 }
215
216 fn type_spec(&mut self, spec: TypeSpec, span: Span, subject: Subject, place: Place) -> TypeId {
218 match spec {
219 TypeSpec::None => {
220 let what = match subject.name {
221 Some(name) => format!("in declaration of '{}'", self.text(name)),
222 None => String::new(),
223 };
224 let message = format!("type defaults to 'int' {what}");
225 self.report(
226 Diagnostic::error(message.trim_end().to_string(), subject.span)
227 .with_code("E0526"),
228 );
229 self.int()
230 }
231 TypeSpec::Builtin(builtin) => match builtin.resolve() {
232 Some(basic) => self.basic_type(basic.scalar, basic.complexity, span),
233 None => {
234 self.report(
235 Diagnostic::error(
236 "two or more data types in declaration specifiers".to_string(),
237 span,
238 )
239 .with_code("E0525"),
240 );
241 self.int()
242 }
243 },
244 TypeSpec::Record { kind, tag, fields, attrs, pack } => {
245 self.record_spec(kind, tag, fields, attrs, pack, span)
246 }
247 TypeSpec::Enum { tag, enumerators, underlying, .. } => {
248 self.enum_spec(tag, enumerators, underlying, span)
249 }
250 TypeSpec::Typedef(name) => match self.scopes.lookup(name) {
251 Some(Binding::Typedef(ty)) => ty,
252 _ => {
257 let name = self.text(name).to_owned();
258 self.report(
259 Diagnostic::error(format!("unknown type name '{name}'"), span)
260 .with_code("E0546"),
261 );
262 self.int()
263 }
264 },
265 TypeSpec::Typeof { unqual, operand } => self.typeof_type(unqual, operand),
266 TypeSpec::Atomic(inner) => {
267 let inner = self.type_name(inner);
268 self.atomic_type(inner, span)
269 }
270 TypeSpec::VaList => self.va_list_type(),
271 TypeSpec::Auto(which) => {
272 let spelled = which.spelling();
280 let place = if place.member { "struct member" } else { "function prototype" };
281 self.report(
282 Diagnostic::error(format!("'{spelled}' not allowed in {place}"), span)
283 .with_code("E0651"),
284 );
285 self.int()
286 }
287 }
288 }
289
290 fn basic_type(&mut self, scalar: Scalar, complexity: Complexity, span: Span) -> TypeId {
292 let kind = int_kind(scalar);
293 let float = float_kind(scalar, self.cx.target);
294
295 match complexity {
296 Complexity::Real => match (scalar, kind, float) {
297 (Scalar::Void, _, _) => self.types.void(),
298 (Scalar::Bool, _, _) => self.types.boolean(),
299 (Scalar::BitInt { width, unsigned }, _, _) => self.bit_int_type(width, !unsigned),
300 (_, Some(kind), _) => self.types.int(kind),
301 (_, _, Some(kind)) => self.types.float(kind),
302 (Scalar::Float128x | Scalar::Float80, _, _) => {
306 self.unavailable_type(spell_scalar(scalar), span);
307 self.types.float(FloatKind::Double)
308 }
309 _ => {
313 self.unsupported_type(&format!("the type `{}`", spell_scalar(scalar)), span);
314 self.types.float(FloatKind::Double)
315 }
316 },
317 Complexity::Complex => match float {
318 Some(kind) => self.types.complex(kind),
319 None => {
323 let what = format!("`_Complex` on the type `{}`", spell_scalar(scalar));
324 self.unsupported_type(&what, span);
325 self.types.complex(FloatKind::Double)
326 }
327 },
328 Complexity::Imaginary => {
330 self.unsupported_type("`_Imaginary`", span);
331 self.types.complex(float.unwrap_or(FloatKind::Double))
332 }
333 }
334 }
335
336 pub(crate) fn va_list_type(&mut self) -> TypeId {
343 if let Some(ty) = self.built.va_list {
344 return ty;
345 }
346 let ty = match self.cx.target.va_list {
347 VaList::CharPointer => {
348 let elem = self.types.int(IntKind::Char);
349 self.types.pointer(elem)
350 }
351 VaList::VoidPointer => {
352 let elem = self.types.void();
353 self.types.pointer(elem)
354 }
355 VaList::SysV => {
356 let uint = self.types.int(IntKind::UInt);
357 let void = self.types.void();
358 let ptr = self.types.pointer(void);
359 let record = self.builtin_record(
360 sym::VA_LIST_TAG,
361 &[
362 (sym::GP_OFFSET, uint),
363 (sym::FP_OFFSET, uint),
364 (sym::OVERFLOW_ARG_AREA, ptr),
365 (sym::REG_SAVE_AREA, ptr),
366 ],
367 );
368 self.types.array(record, ArrayLen::Fixed(1))
372 }
373 VaList::Aapcs => {
374 let int = self.types.int(IntKind::Int);
375 let void = self.types.void();
376 let ptr = self.types.pointer(void);
377 self.builtin_record(
378 sym::VA_LIST,
379 &[
380 (sym::STACK, ptr),
381 (sym::GR_TOP, ptr),
382 (sym::VR_TOP, ptr),
383 (sym::GR_OFFS, int),
384 (sym::VR_OFFS, int),
385 ],
386 )
387 }
388 };
389 self.built.va_list = Some(ty);
390 ty
391 }
392
393 fn builtin_record(&mut self, tag: Symbol, members: &[(Symbol, TypeId)]) -> TypeId {
399 let id = self.types.declare_record(RecordKind::Struct, Some(tag));
400 let decls: Vec<FieldDecl> =
401 members.iter().map(|&(name, ty)| FieldDecl::new(Some(name), ty)).collect();
402 let laid_out = rucc_types::layout_record(
403 &self.types,
404 RecordKind::Struct,
405 &decls,
406 &RecordOptions::default(),
407 self.cx.target,
408 )
409 .expect("a record of pointers and integers lays out");
410 self.types.complete_record(id, laid_out);
411 self.types.record(id)
412 }
413
414 fn typeof_type(&mut self, unqual: bool, operand: TypeofArg) -> TypeId {
416 let ty = match operand {
420 TypeofArg::Expr(expr) => {
421 let node = self.expr(expr);
422 self.tast[node].ty
423 }
424 TypeofArg::Type(name) => self.type_name(name),
425 };
426 if !unqual {
427 return ty;
428 }
429 let bare = match self.types.kind(self.types.canonical(ty)) {
432 rucc_types::TypeKind::Atomic(inner) => inner,
433 _ => ty,
434 };
435 self.types.unqualified(bare)
436 }
437
438 fn bit_int_type(&mut self, width: ast::ExprId, signed: bool) -> TypeId {
444 let value = self.expr(width);
445 let span = self.tast.expr_span(value);
446 let Ok(bits) = self.eval_integer(value) else {
447 if !self.is_poisoned(value) {
450 self.report(
451 Diagnostic::error(
452 "'_BitInt' argument is not an integer constant expression".to_string(),
453 span,
454 )
455 .with_code("E0529"),
456 );
457 }
458 return self.int();
459 };
460 if bits <= 0 {
461 let message = format!(
462 "'_BitInt' argument '{bits}' is not a positive integer constant expression"
463 );
464 self.report(Diagnostic::error(message, span).with_code("E0529"));
465 return self.int();
466 }
467 if signed && bits < 2 {
468 let message = "'signed _BitInt' argument must be at least 2".to_string();
469 self.report(Diagnostic::error(message, span).with_code("E0529"));
470 return self.int();
471 }
472 if bits > i128::from(MAX_BIT_INT_WIDTH) {
473 let message = format!(
474 "'_BitInt' argument '{bits}' is larger than 'BITINT_MAXWIDTH' '{MAX_BIT_INT_WIDTH}'"
475 );
476 self.report(Diagnostic::error(message, span).with_code("E0529"));
477 return self.int();
478 }
479 let bits = u32::try_from(bits).unwrap_or(MAX_BIT_INT_WIDTH);
480 self.types.bit_int(signed, bits)
481 }
482
483 fn atomic_type(&mut self, inner: TypeId, span: Span) -> TypeId {
485 let canonical = self.types.canonical(inner);
486 let what = if rucc_types::is_array(&self.types, canonical) {
487 "'_Atomic'-qualified array type"
488 } else if is_function(&self.types, canonical) {
489 "'_Atomic'-qualified function type"
490 } else if !self.types.quals(inner).is_none() {
491 "'_Atomic' applied to a qualified type"
492 } else {
493 return self.types.atomic(inner);
494 };
495 self.report(Diagnostic::error(what.to_string(), span).with_code("E0527"));
496 inner
497 }
498
499 fn record_spec(
501 &mut self,
502 kind: ast::RecordKind,
503 tag: Option<Symbol>,
504 fields: Option<ast::MemberList>,
505 attrs: ast::AttrList,
506 pack: Option<u32>,
507 span: Span,
508 ) -> TypeId {
509 let (kind, tag_kind) = match kind {
510 ast::RecordKind::Struct => (RecordKind::Struct, TagKind::Struct),
511 ast::RecordKind::Union => (RecordKind::Union, TagKind::Union),
512 };
513 let Some(members) = fields else {
514 return match self.tag_use(tag, tag_kind, span) {
515 TagUse::Known(ty) => ty,
516 found => {
517 let id = self.types.declare_record(kind, tag);
518 let ty = self.types.record(id);
519 self.bind_tag(found, tag, tag_kind, ty);
520 ty
521 }
522 };
523 };
524 let (id, ty) = self.record_defined(kind, tag, tag_kind, span);
528 self.built.defined.insert(ty);
529 self.record_body(id, kind, members, attrs, pack, span);
530 ty
531 }
532
533 fn enum_spec(
535 &mut self,
536 tag: Option<Symbol>,
537 enumerators: Option<ast::EnumeratorList>,
538 underlying: Option<ast::TypeNameId>,
539 span: Span,
540 ) -> TypeId {
541 let underlying = underlying.map(|name| {
542 let ty = self.type_name(name);
543 if is_integer(&self.types, self.types.canonical(ty)) {
544 return ty;
545 }
546 self.report(
547 Diagnostic::error("invalid 'enum' underlying type".to_string(), span)
548 .with_code("E0530"),
549 );
550 self.int()
551 });
552
553 let Some(list) = enumerators else {
554 return match self.tag_use(tag, TagKind::Enum, span) {
555 TagUse::Known(ty) => ty,
556 found => {
557 let id = self.types.declare_enum(tag);
558 if let Some(underlying) = underlying {
562 self.types.complete_enum(id, underlying, true);
563 }
564 let ty = self.types.enumeration(id);
565 self.bind_tag(found, tag, TagKind::Enum, ty);
566 ty
567 }
568 };
569 };
570 let (id, ty) = self.enum_defined(tag, span);
571 self.built.defined.insert(ty);
572 self.enum_body(id, list, underlying, span);
573 ty
574 }
575
576 fn tag_use(&mut self, tag: Option<Symbol>, kind: TagKind, span: Span) -> TagUse {
585 let Some(name) = tag else { return TagUse::Anonymous };
588 match self.scopes.tag(name) {
589 Some(found) if found.kind == kind => TagUse::Known(found.ty),
590 Some(_) => {
591 let spelled = self.text(name).to_owned();
592 self.report(
593 Diagnostic::error(format!("'{spelled}' defined as wrong kind of tag"), span)
594 .with_code("E0531"),
595 );
596 TagUse::Wrong
597 }
598 None => TagUse::New,
599 }
600 }
601
602 fn bind_tag(&mut self, found: TagUse, tag: Option<Symbol>, kind: TagKind, ty: TypeId) {
604 if !matches!(found, TagUse::New) {
608 return;
609 }
610 if let Some(name) = tag {
611 self.scopes.declare_tag(name, Tag { kind, ty });
612 }
613 }
614
615 pub(in crate::check) fn qualify(
617 &mut self,
618 ty: TypeId,
619 quals: ast::Quals,
620 span: Span,
621 ) -> TypeId {
622 let ty = if quals.has(ast::Quals::ATOMIC) { self.atomic_type(ty, span) } else { ty };
626 let mut result = Qualifiers::NONE;
627 if quals.has(ast::Quals::CONST) {
628 result = result.with(Qualifiers::CONST);
629 }
630 if quals.has(ast::Quals::VOLATILE) {
631 result = result.with(Qualifiers::VOLATILE);
632 }
633 if quals.has(ast::Quals::RESTRICT) {
634 if is_pointer(&self.types, self.types.canonical(ty)) {
635 result = result.with(Qualifiers::RESTRICT);
636 } else {
637 self.report(
638 Diagnostic::error("invalid use of 'restrict'".to_string(), span)
639 .with_code("E0528"),
640 );
641 }
642 }
643 self.types.qualified(ty, result)
644 }
645
646 fn derive(
648 &mut self,
649 base: TypeId,
650 declarator: ast::DeclaratorId,
651 subject: Subject,
652 place: Place,
653 ) -> TypeId {
654 let ast = self.ast;
657 let steps = &ast[ast[declarator].derived];
658 let mut ty = base;
659 for (index, step) in steps.iter().enumerate().rev() {
660 let nearest = index == 0;
663 ty = match *step {
664 Derived::Pointer { quals, .. } => {
665 let pointer = self.types.pointer(ty);
666 self.qualify(pointer, quals, subject.span)
667 }
668 Derived::Array { size, quals, has_static } => {
669 if (!quals.is_none() || has_static) && !(place.parameter && nearest) {
670 self.report(
671 Diagnostic::error(
672 "static or type qualifiers in non-parameter array declarator"
673 .to_string(),
674 subject.span,
675 )
676 .with_code("E0540"),
677 );
678 }
679 self.array_of(ty, size, subject, place)
680 }
681 Derived::Function { params, variadic, kind } => {
682 self.function_of(ty, params, variadic, kind, subject)
683 }
684 };
685 }
686 ty
687 }
688
689 fn array_of(
691 &mut self,
692 elem: TypeId,
693 size: ArraySize,
694 subject: Subject,
695 place: Place,
696 ) -> TypeId {
697 let canonical = self.types.canonical(elem);
698 let bad = if is_void(&self.types, canonical) {
699 Some(("as array of voids", "E0532"))
700 } else if is_function(&self.types, canonical) {
701 Some(("as array of functions", "E0533"))
702 } else {
703 None
704 };
705 if let Some((what, code)) = bad {
706 let who = self.declaration_of(subject);
707 self.report(Diagnostic::error(format!("{who} {what}"), subject.span).with_code(code));
708 return elem;
709 }
710 if !is_complete(&self.types, canonical) {
711 let spelled = self.spell(elem);
712 self.report(
713 Diagnostic::error(
714 format!("array type has incomplete element type '{spelled}'"),
715 subject.span,
716 )
717 .with_code("E0534"),
718 );
719 return elem;
720 }
721 let len = self.array_len(elem, size, subject, place);
722 self.types.array(elem, len)
723 }
724
725 fn array_len(
727 &mut self,
728 elem: TypeId,
729 size: ArraySize,
730 subject: Subject,
731 place: Place,
732 ) -> ArrayLen {
733 let expr = match size {
734 ArraySize::Unspecified => return ArrayLen::Unknown,
735 ArraySize::Star if place.prototype => return ArrayLen::Star,
736 ArraySize::Star => {
737 self.report(
738 Diagnostic::error(
739 "'[*]' not allowed in other than function prototype scope".to_string(),
740 subject.span,
741 )
742 .with_code("E0539"),
743 );
744 return ArrayLen::Unknown;
745 }
746 ArraySize::Expr(expr) => expr,
747 };
748
749 let value = self.expr(expr);
750 if self.is_poisoned(value) {
751 return ArrayLen::Unknown;
752 }
753 let value = self.value(value);
757 let span = self.tast.expr_span(value);
758 if !is_integer(&self.types, self.types.canonical(self.tast[value].ty)) {
759 self.report(
760 Diagnostic::error("size of array has non-integer type".to_string(), span)
761 .with_code("E0535"),
762 );
763 return ArrayLen::Unknown;
764 }
765
766 match self.eval_integer(value) {
767 Ok(count) if count < 0 => {
768 let who = self.array_named(subject);
769 self.report(
770 Diagnostic::error(format!("size of {who} is negative"), span)
771 .with_code("E0536"),
772 );
773 ArrayLen::Unknown
774 }
775 Ok(count) => {
776 let count = u64::try_from(count).unwrap_or(u64::MAX);
777 if self.too_large(elem, count) {
778 let who = self.array_named(subject);
779 let max = self.cx.target.max_object_size();
780 let message = format!("size of {who} exceeds maximum object size '{max}'");
781 self.report(Diagnostic::error(message, span).with_code("E0537"));
782 return ArrayLen::Unknown;
783 }
784 ArrayLen::Fixed(count)
785 }
786 Err(failure) => {
789 if failure.poisoned {
790 return ArrayLen::Unknown;
791 }
792 if self.scopes.at_file_scope() {
793 let who = match subject.name {
794 Some(name) => format!("'{}'", self.text(name)),
795 None => "type name".to_string(),
796 };
797 self.report(
798 Diagnostic::error(
799 format!("variably modified {who} at file scope"),
800 subject.span,
801 )
802 .with_code("E0538"),
803 );
804 return ArrayLen::Unknown;
805 }
806 ArrayLen::Variable(self.tast.add_vla(value))
807 }
808 }
809 }
810
811 fn too_large(&self, elem: TypeId, count: u64) -> bool {
813 let Ok(elem) = layout(&self.types, elem, self.cx.target) else {
814 return false;
815 };
816 elem.size != 0 && count > self.cx.target.max_object_size() / elem.size
818 }
819
820 fn function_of(
822 &mut self,
823 ret: TypeId,
824 params: ast::ParamList,
825 variadic: bool,
826 kind: ParamKind,
827 subject: Subject,
828 ) -> TypeId {
829 let canonical = self.types.canonical(ret);
830 let bad = if rucc_types::is_array(&self.types, canonical) {
831 Some(("an array", "E0542"))
832 } else if is_function(&self.types, canonical) {
833 Some(("a function", "E0541"))
834 } else {
835 None
836 };
837 let ret = match bad {
838 Some((what, code)) => {
839 let who = self.declared_as(subject);
840 self.report(
841 Diagnostic::error(format!("{who} as function returning {what}"), subject.span)
842 .with_code(code),
843 );
844 self.int()
845 }
846 None => ret,
847 };
848
849 let (params, prototyped) = match kind {
850 ParamKind::Void => (Vec::new(), true),
851 ParamKind::Empty => (Vec::new(), self.cx.std == Std::C23),
854 ParamKind::Identifiers => (Vec::new(), false),
858 ParamKind::Prototype => (self.prototype(params), true),
859 };
860 self.types.function(FunctionType { ret, params, variadic, prototyped })
861 }
862
863 fn prototype(&mut self, params: ast::ParamList) -> Vec<TypeId> {
865 let ast = self.ast;
866 let list = &ast[params];
867 self.scopes.push();
872 let mut types = Vec::with_capacity(list.len());
873 let mut declared = Vec::new();
874 for (index, param) in list.iter().enumerate() {
875 let ty = match param.specs {
876 Some(specs) => self.build_type(
877 specs,
878 param.declarator,
879 Place { parameter: true, member: false, prototype: true },
880 ),
881 None => self.int(),
884 };
885 let declarator = ast[param.declarator];
886 let span = if declarator.name.is_some() { declarator.name_span } else { param.span };
887 self.check_void_parameter(ty, declarator.name, index, span);
888
889 let adjusted = adjust_parameter(&mut self.types, ty);
896 let written = self.types.canonical(ty);
902 let object = if rucc_types::is_array(&self.types, written) {
903 match ast[declarator.derived].first() {
907 Some(&Derived::Array { quals, .. }) => self.qualify(adjusted, quals, span),
908 _ => adjusted,
909 }
910 } else if is_function(&self.types, written) {
911 adjusted
912 } else {
913 ty
914 };
915 types.push(adjusted);
916
917 match declarator.name {
921 Some(name) if self.scopes.lookup_here(name).is_some() => {
925 let spelled = self.text(name).to_owned();
926 self.report(
927 Diagnostic::error(format!("redefinition of parameter '{spelled}'"), span)
928 .with_code("E0545"),
929 );
930 declared.push(self.unnamed_object(object, span));
931 }
932 Some(name) => declared.push(self.declare_object(name, object, span)),
933 None => declared.push(self.unnamed_object(object, span)),
939 }
940 }
941 self.scopes.pop();
942 if let Some(first) = params.iter().next() {
943 self.built.params.insert(first, declared);
944 }
945 types
946 }
947
948 pub(in crate::check) fn identifier_list(
961 &mut self,
962 params: ast::ParamList,
963 declarations: ast::DeclList,
964 ) {
965 let names = self.parameter_names(params);
966 self.scopes.push();
974 let mut written = vec![None; names.len()];
975 let ids: Vec<ast::DeclId> = self.ast[declarations].to_vec();
976 for id in ids {
977 self.old_style_declaration(id, &names, &mut written);
978 }
979 let mut declared = Vec::with_capacity(names.len());
980 for (index, &(name, span)) in names.iter().enumerate() {
981 let ty = match written[index] {
982 Some(ty) => ty,
983 None => {
984 if self.cx.std >= Std::C99 {
988 let spelled = self.text(name).to_owned();
989 self.report(
990 Diagnostic::error(
991 format!("type of '{spelled}' defaults to 'int'"),
992 span,
993 )
994 .with_code("E0526"),
995 );
996 }
997 self.int()
998 }
999 };
1000 let object = adjust_parameter(&mut self.types, ty);
1001 declared.push(self.declare_object(name, object, span));
1002 }
1003 self.scopes.pop();
1004 if let Some(first) = params.iter().next() {
1005 self.built.params.insert(first, declared);
1006 }
1007 }
1008
1009 pub(in crate::check) fn function_taking(&mut self, ty: TypeId, params: Vec<TypeId>) -> TypeId {
1016 let canonical = self.types.canonical(ty);
1017 let rucc_types::TypeKind::Function(id) = self.types.kind(canonical) else {
1018 return ty;
1021 };
1022 let signature = FunctionType { params, ..self.types.signature(id).clone() };
1023 self.types.function(signature)
1024 }
1025
1026 fn parameter_names(&mut self, params: ast::ParamList) -> Vec<(Symbol, Span)> {
1028 let ast = self.ast;
1029 let mut names: Vec<(Symbol, Span)> = Vec::with_capacity(params.len());
1030 for param in &ast[params] {
1031 let declarator = ast[param.declarator];
1032 let Some(name) = declarator.name else { continue };
1035 if names.iter().any(|&(seen, _)| seen == name) {
1036 let spelled = self.text(name).to_owned();
1037 self.report(
1038 Diagnostic::error(
1039 format!("multiple parameters named '{spelled}'"),
1040 declarator.name_span,
1041 )
1042 .with_code("E0545"),
1043 );
1044 continue;
1045 }
1046 names.push((name, declarator.name_span));
1047 }
1048 names
1049 }
1050
1051 fn old_style_declaration(
1056 &mut self,
1057 id: ast::DeclId,
1058 names: &[(Symbol, Span)],
1059 written: &mut [Option<TypeId>],
1060 ) {
1061 let ast::Decl::Var { specs, declarators } = self.ast[id] else {
1062 self.check_decl(id);
1065 return;
1066 };
1067 if self.ast[declarators].is_empty() {
1068 self.declared_specs(specs);
1069 return;
1070 }
1071 for index in 0..declarators.len() {
1072 let item = self.ast[declarators][index];
1073 let ty = self.build_type(
1074 specs,
1075 item.declarator,
1076 Place { parameter: true, member: false, prototype: false },
1077 );
1078 let declarator = self.ast[item.declarator];
1079 let span = if declarator.name.is_some() { declarator.name_span } else { item.span };
1080 let Some(name) = declarator.name else {
1081 self.report(
1082 Diagnostic::error("declaration for a parameter with no name".to_string(), span)
1083 .with_code("E0682"),
1084 );
1085 continue;
1086 };
1087 let spelled = self.text(name).to_owned();
1088 if !matches!(self.ast[specs].storage, None | Some(ast::StorageClass::Register)) {
1091 self.report(
1092 Diagnostic::error(
1093 format!("storage class specified for parameter '{spelled}'"),
1094 span,
1095 )
1096 .with_code("E0682"),
1097 );
1098 }
1099 if item.init.is_some() {
1100 self.report(
1101 Diagnostic::error(format!("parameter '{spelled}' is initialized"), span)
1102 .with_code("E0682"),
1103 );
1104 }
1105 let Some(at) = names.iter().position(|&(seen, _)| seen == name) else {
1106 self.report(
1107 Diagnostic::error(
1108 format!("declaration for parameter '{spelled}' but no such parameter"),
1109 span,
1110 )
1111 .with_code("E0682"),
1112 );
1113 continue;
1114 };
1115 if written[at].is_some() {
1116 self.report(
1117 Diagnostic::error(format!("redefinition of parameter '{spelled}'"), span)
1118 .with_code("E0545"),
1119 );
1120 continue;
1121 }
1122 written[at] = Some(ty);
1123 }
1124 }
1125
1126 pub(in crate::check) fn default_promoted(&mut self, ty: TypeId) -> TypeId {
1133 let promoted = rucc_types::promote(&mut self.types, ty, self.cx.target);
1134 let canonical = self.types.canonical(promoted);
1135 if self.types.kind(canonical) == rucc_types::TypeKind::Float(FloatKind::Float) {
1136 return self.types.float(FloatKind::Double);
1137 }
1138 promoted
1139 }
1140
1141 pub(in crate::check) fn prototype_params(&self, params: ast::ParamList) -> Vec<DeclId> {
1145 params
1146 .iter()
1147 .next()
1148 .and_then(|first| self.built.params.get(&first))
1149 .cloned()
1150 .unwrap_or_default()
1151 }
1152
1153 fn check_void_parameter(&mut self, ty: TypeId, name: Option<Symbol>, index: usize, span: Span) {
1156 if !is_void(&self.types, self.types.canonical(ty)) {
1157 return;
1158 }
1159 let position = index + 1;
1160 match name {
1161 Some(name) => {
1162 let spelled = self.text(name).to_owned();
1163 self.report(
1164 Diagnostic::warning(
1165 format!("parameter {position} ('{spelled}') has void type"),
1166 span,
1167 )
1168 .with_code("E0544"),
1169 );
1170 }
1171 None => {
1174 self.report(
1175 Diagnostic::error("'void' must be the only parameter".to_string(), span)
1176 .with_code("E0543"),
1177 );
1178 }
1179 }
1180 }
1181
1182 fn declaration_of(&self, subject: Subject) -> String {
1184 match subject.name {
1185 Some(name) => format!("declaration of '{}'", self.text(name)),
1186 None => "declaration of type name".to_string(),
1187 }
1188 }
1189
1190 fn declared_as(&self, subject: Subject) -> String {
1192 match subject.name {
1193 Some(name) => format!("'{}' declared", self.text(name)),
1194 None => "type name declared".to_string(),
1195 }
1196 }
1197
1198 fn array_named(&self, subject: Subject) -> String {
1200 match subject.name {
1201 Some(name) => format!("array '{}'", self.text(name)),
1202 None => "unnamed array".to_string(),
1203 }
1204 }
1205
1206 fn unsupported_type(&mut self, what: &str, span: Span) {
1208 self.report(
1209 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1210 );
1211 }
1212
1213 fn unavailable_type(&mut self, name: &str, span: Span) {
1215 self.report(
1216 Diagnostic::error(format!("'{name}' is not supported on this target"), span)
1217 .with_code("E0589"),
1218 );
1219 }
1220}
1221
1222fn int_kind(scalar: Scalar) -> Option<IntKind> {
1224 let kind = match scalar {
1227 Scalar::Char => IntKind::Char,
1228 Scalar::SignedChar => IntKind::SChar,
1229 Scalar::UnsignedChar => IntKind::UChar,
1230 Scalar::Short => IntKind::Short,
1231 Scalar::UnsignedShort => IntKind::UShort,
1232 Scalar::Int => IntKind::Int,
1233 Scalar::UnsignedInt => IntKind::UInt,
1234 Scalar::Long => IntKind::Long,
1235 Scalar::UnsignedLong => IntKind::ULong,
1236 Scalar::LongLong => IntKind::LongLong,
1237 Scalar::UnsignedLongLong => IntKind::ULongLong,
1238 Scalar::Int128 => IntKind::Int128,
1239 Scalar::UnsignedInt128 => IntKind::UInt128,
1240 _ => return None,
1241 };
1242 Some(kind)
1243}
1244
1245fn float_kind(scalar: Scalar, target: &TargetInfo) -> Option<FloatKind> {
1253 match scalar {
1254 Scalar::Float => Some(FloatKind::Float),
1255 Scalar::Double => Some(FloatKind::Double),
1256 Scalar::LongDouble => Some(FloatKind::LongDouble),
1257 Scalar::Float16 => Some(FloatKind::Float16),
1258 Scalar::Float32 => Some(FloatKind::Float32),
1259 Scalar::Float64 => Some(FloatKind::Float64),
1260 Scalar::Float128 => Some(FloatKind::Float128),
1261 Scalar::Float32x => Some(FloatKind::Float32x),
1262 Scalar::Float64x => Some(FloatKind::Float64x),
1263 Scalar::Float80 if target.long_double_format == Format::X87Extended => {
1264 Some(FloatKind::LongDouble)
1265 }
1266 _ => None,
1267 }
1268}
1269
1270fn spell_scalar(scalar: Scalar) -> &'static str {
1272 match scalar {
1273 Scalar::Void => "void",
1274 Scalar::Bool => "bool",
1275 Scalar::Char => "char",
1276 Scalar::SignedChar => "signed char",
1277 Scalar::UnsignedChar => "unsigned char",
1278 Scalar::Short => "short",
1279 Scalar::UnsignedShort => "unsigned short",
1280 Scalar::Int => "int",
1281 Scalar::UnsignedInt => "unsigned int",
1282 Scalar::Long => "long",
1283 Scalar::UnsignedLong => "unsigned long",
1284 Scalar::LongLong => "long long",
1285 Scalar::UnsignedLongLong => "unsigned long long",
1286 Scalar::Int128 => "__int128",
1287 Scalar::UnsignedInt128 => "unsigned __int128",
1288 Scalar::BitInt { unsigned: false, .. } => "_BitInt",
1291 Scalar::BitInt { unsigned: true, .. } => "unsigned _BitInt",
1292 Scalar::Float => "float",
1293 Scalar::Double => "double",
1294 Scalar::LongDouble => "long double",
1295 Scalar::Float16 => "_Float16",
1296 Scalar::Float32 => "_Float32",
1297 Scalar::Float64 => "_Float64",
1298 Scalar::Float128 => "_Float128",
1299 Scalar::Float32x => "_Float32x",
1300 Scalar::Float64x => "_Float64x",
1301 Scalar::Float128x => "_Float128x",
1302 Scalar::Float80 => "__float80",
1303 Scalar::Decimal32 => "_Decimal32",
1304 Scalar::Decimal64 => "_Decimal64",
1305 Scalar::Decimal128 => "_Decimal128",
1306 }
1307}
1308
1309#[cfg(test)]
1312mod tests {
1313 use rucc_ast::{Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId, Quals};
1314 use rucc_base::Interner;
1315 use rucc_lex::{IntConstant, IntConstantType, Remarks};
1316 use rucc_target::{TargetInfo, Triple};
1317 use rucc_types::{TypeKind, spell};
1318
1319 use super::*;
1320 use crate::check::Context;
1321
1322 pub(super) struct Fixture {
1328 pub(super) ast: rucc_ast::Ast,
1329 names: Interner,
1330 target: TargetInfo,
1331 }
1332
1333 impl Fixture {
1334 pub(super) fn new() -> Fixture {
1335 Fixture::for_target("x86_64-unknown-linux-gnu")
1336 }
1337
1338 pub(super) fn for_target(triple: &str) -> Fixture {
1340 let target = TargetInfo::new(triple.parse::<Triple>().expect("a triple"));
1341 Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1342 }
1343
1344 pub(super) fn name(&mut self, text: &str) -> Symbol {
1345 self.names.intern(text)
1346 }
1347
1348 pub(super) fn keywords(&mut self, written: &[BuiltinSet]) -> DeclSpecsId {
1350 let mut builtin = Builtin::NONE;
1351 for &keyword in written {
1352 builtin = builtin.add(keyword).expect("a keyword written once");
1353 }
1354 self.specs(TypeSpec::Builtin(builtin), Quals::NONE)
1355 }
1356
1357 pub(super) fn int_specs(&mut self) -> DeclSpecsId {
1359 self.keywords(&[BuiltinSet::INT])
1360 }
1361
1362 pub(super) fn specs(&mut self, ty: TypeSpec, quals: Quals) -> DeclSpecsId {
1363 let mut specs = DeclSpecs::empty(Span::DUMMY);
1364 specs.ty = ty;
1365 specs.quals = quals;
1366 self.ast.add_specs(specs)
1367 }
1368
1369 pub(super) fn declarator(
1370 &mut self,
1371 name: Option<&str>,
1372 derived: &[Derived],
1373 ) -> DeclaratorId {
1374 let name = name.map(|text| self.name(text));
1375 let derived = self.ast.add_derived_list(derived);
1376 self.ast.add_declarator(Declarator {
1377 name,
1378 name_span: Span::DUMMY,
1379 derived,
1380 span: Span::DUMMY,
1381 })
1382 }
1383
1384 pub(super) fn type_name(
1386 &mut self,
1387 specs: DeclSpecsId,
1388 derived: &[Derived],
1389 ) -> ast::TypeNameId {
1390 let declarator = self.declarator(None, derived);
1391 self.ast.add_type_name(ast::TypeName { specs, declarator, span: Span::DUMMY })
1392 }
1393
1394 pub(super) fn int(&mut self, value: u128) -> ast::ExprId {
1396 let ty = IntConstantType::Standard(IntKind::Int);
1397 let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1398 self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1399 }
1400
1401 fn use_name(&mut self, text: &str) -> ast::ExprId {
1402 let name = self.name(text);
1403 self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1404 }
1405
1406 pub(super) fn checker(&self) -> Checker<'_> {
1407 Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1408 }
1409 }
1410
1411 fn fixed(fixture: &mut Fixture, count: u128) -> Derived {
1413 let size = fixture.int(count);
1414 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1415 }
1416
1417 fn pointer() -> Derived {
1419 Derived::Pointer { quals: Quals::NONE, attrs: rucc_ast::AttrList::EMPTY }
1420 }
1421
1422 fn bit_int(width: ast::ExprId, unsigned: bool) -> TypeSpec {
1424 let mut builtin = Builtin::NONE.add_bit_int(width).expect("`_BitInt` rejected");
1425 if unsigned {
1426 builtin = builtin.add(BuiltinSet::UNSIGNED).expect("`unsigned` rejected");
1427 }
1428 TypeSpec::Builtin(builtin)
1429 }
1430
1431 pub(super) fn spelled(checker: &Checker<'_>, ty: TypeId) -> String {
1433 spell(&checker.types, checker.cx.names, ty)
1434 }
1435
1436 fn built(checker: &mut Checker<'_>, specs: DeclSpecsId, declarator: DeclaratorId) -> String {
1438 let ty = checker.declared_type(specs, declarator);
1439 spelled(checker, ty)
1440 }
1441
1442 pub(super) fn messages(checker: &Checker<'_>) -> Vec<String> {
1444 checker.errors.diagnostics().iter().map(|d| d.message.clone()).collect()
1445 }
1446
1447 pub(super) fn message(checker: &Checker<'_>) -> String {
1449 let mut reported = messages(checker);
1450 assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1451 reported.pop().expect("one message")
1452 }
1453
1454 #[test]
1455 fn the_keywords_of_a_specifier_list_name_one_type_between_them() {
1456 let mut fixture = Fixture::new();
1457 let long = fixture.keywords(&[BuiltinSet::UNSIGNED, BuiltinSet::LONG, BuiltinSet::INT]);
1458 let double = fixture.keywords(&[BuiltinSet::LONG, BuiltinSet::DOUBLE]);
1459 let void = fixture.keywords(&[BuiltinSet::VOID]);
1460 let plain = fixture.declarator(Some("x"), &[]);
1461
1462 let mut checker = fixture.checker();
1463 assert_eq!(built(&mut checker, long, plain), "unsigned long");
1464 assert_eq!(built(&mut checker, double, plain), "long double");
1465 assert_eq!(built(&mut checker, void, plain), "void");
1466 assert!(messages(&checker).is_empty());
1467 }
1468
1469 #[test]
1470 fn each_spelling_of_a_floating_type_names_a_type_of_its_own() {
1471 let mut fixture = Fixture::new();
1472 let written = [
1473 (BuiltinSet::FLOAT16, "_Float16"),
1474 (BuiltinSet::FLOAT32, "_Float32"),
1475 (BuiltinSet::FLOAT64, "_Float64"),
1476 (BuiltinSet::FLOAT128, "_Float128"),
1477 (BuiltinSet::FLOAT32X, "_Float32x"),
1478 (BuiltinSet::FLOAT64X, "_Float64x"),
1479 ];
1480 let specs: Vec<_> =
1481 written.iter().map(|&(keyword, _)| fixture.keywords(&[keyword])).collect();
1482 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1485 let plain = fixture.declarator(Some("x"), &[]);
1486
1487 let mut checker = fixture.checker();
1488 for (specs, expected) in specs.into_iter().zip(written.iter().map(|&(_, name)| name)) {
1489 assert_eq!(built(&mut checker, specs, plain), expected);
1490 }
1491 assert_eq!(built(&mut checker, float80, plain), "long double");
1492 assert!(messages(&checker).is_empty());
1493 }
1494
1495 #[test]
1496 fn a_floating_type_the_target_does_not_have_is_refused_rather_than_given_another_one() {
1497 let mut fixture = Fixture::for_target("aarch64-apple-darwin");
1502 let float128x = fixture.keywords(&[BuiltinSet::FLOAT128X]);
1503 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1504 let plain = fixture.declarator(Some("x"), &[]);
1505
1506 let mut checker = fixture.checker();
1507 assert_eq!(built(&mut checker, float128x, plain), "double");
1510 assert_eq!(built(&mut checker, float80, plain), "double");
1511 assert_eq!(
1512 messages(&checker),
1513 [
1514 "'_Float128x' is not supported on this target",
1515 "'__float80' is not supported on this target",
1516 ]
1517 );
1518 }
1519
1520 #[test]
1521 fn a_decimal_floating_type_is_recognised_and_says_it_is_not_written_yet() {
1522 let mut fixture = Fixture::new();
1526 let specs = fixture.keywords(&[BuiltinSet::DECIMAL64]);
1527 let plain = fixture.declarator(Some("x"), &[]);
1528
1529 let mut checker = fixture.checker();
1530 assert_eq!(built(&mut checker, specs, plain), "double");
1531 assert_eq!(message(&checker), "the type `_Decimal64` is not supported yet");
1532 }
1533
1534 #[test]
1535 fn keywords_that_name_no_type_between_them_are_one_message_and_not_one_per_keyword() {
1536 let mut fixture = Fixture::new();
1537 let specs = fixture.keywords(&[BuiltinSet::SHORT, BuiltinSet::DOUBLE]);
1540 let plain = fixture.declarator(Some("x"), &[]);
1541
1542 let mut checker = fixture.checker();
1543 let ty = checker.declared_type(specs, plain);
1544 assert_eq!(spelled(&checker, ty), "int");
1545 assert_eq!(message(&checker), "two or more data types in declaration specifiers");
1546 }
1547
1548 #[test]
1549 fn a_declaration_with_no_type_at_all_is_an_int_and_a_warning_that_says_whose() {
1550 let mut fixture = Fixture::new();
1551 let specs = fixture.specs(TypeSpec::None, Quals::CONST);
1554 let again = fixture.specs(TypeSpec::None, Quals::NONE);
1555 let named = fixture.declarator(Some("x"), &[]);
1556 let abstracted = fixture.declarator(None, &[]);
1557
1558 let mut checker = fixture.checker();
1559 let ty = checker.declared_type(specs, named);
1560 assert_eq!(spelled(&checker, ty), "const int");
1561 checker.declared_type(again, abstracted);
1562 assert_eq!(
1563 messages(&checker),
1564 ["type defaults to 'int' in declaration of 'x'", "type defaults to 'int'"]
1565 );
1566 }
1567
1568 #[test]
1569 fn a_declarator_is_folded_from_the_far_end_so_the_step_nearest_the_name_wins() {
1570 let mut fixture = Fixture::new();
1571 let specs = fixture.int_specs();
1572 let char_specs = fixture.keywords(&[BuiltinSet::CHAR]);
1573 let parameter = fixture.declarator(None, &[]);
1574 let params = fixture.ast.add_param_list(&[ast::Param {
1575 specs: Some(char_specs),
1576 declarator: parameter,
1577 attrs: rucc_ast::AttrList::EMPTY,
1578 span: Span::DUMMY,
1579 }]);
1580 let three = fixed(&mut fixture, 3);
1583 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1584 let f = fixture.declarator(Some("f"), &[three, pointer(), call]);
1585
1586 let mut checker = fixture.checker();
1587 let ty = checker.declared_type(specs, f);
1588 assert_eq!(spelled(&checker, ty), "int (*[3])(char)");
1589 assert!(messages(&checker).is_empty());
1590 }
1591
1592 #[test]
1593 fn the_qualifiers_of_a_pointer_are_the_pointers_and_not_the_pointees() {
1594 let mut fixture = Fixture::new();
1595 let konst = fixture.specs(
1596 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
1597 Quals::CONST,
1598 );
1599 let plain = fixture.int_specs();
1600 let to_const = fixture.declarator(Some("p"), &[pointer()]);
1602 let const_pointer = fixture.declarator(
1604 Some("p"),
1605 &[Derived::Pointer { quals: Quals::CONST, attrs: rucc_ast::AttrList::EMPTY }],
1606 );
1607
1608 let mut checker = fixture.checker();
1609 assert_eq!(built(&mut checker, konst, to_const), "const int *");
1610 assert_eq!(built(&mut checker, plain, const_pointer), "int *const");
1611 assert!(messages(&checker).is_empty());
1612 }
1613
1614 #[test]
1615 fn restrict_is_only_for_a_pointer_and_says_so_where_it_is_not() {
1616 let mut fixture = Fixture::new();
1617 let specs = fixture.specs(TypeSpec::None, Quals::RESTRICT);
1618 let plain = fixture.declarator(Some("x"), &[]);
1619 let restricted =
1620 Derived::Pointer { quals: Quals::RESTRICT, attrs: rucc_ast::AttrList::EMPTY };
1621 let int_specs = fixture.int_specs();
1622 let p = fixture.declarator(Some("p"), &[restricted]);
1623
1624 let mut checker = fixture.checker();
1625 assert_eq!(built(&mut checker, int_specs, p), "int *restrict");
1626 checker.declared_type(specs, plain);
1627 assert!(
1628 messages(&checker).contains(&"invalid use of 'restrict'".to_string()),
1629 "got {:?}",
1630 messages(&checker)
1631 );
1632 }
1633
1634 #[test]
1635 fn an_array_of_something_there_can_be_no_array_of_says_which_it_was() {
1636 let mut fixture = Fixture::new();
1637 let void = fixture.keywords(&[BuiltinSet::VOID]);
1638 let int = fixture.int_specs();
1639 let three = fixed(&mut fixture, 3);
1640 let params = fixture.ast.add_param_list(&[]);
1641 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1642
1643 let voids = fixture.declarator(Some("a"), &[three]);
1644 let functions = fixture.declarator(Some("a"), &[three, call]);
1645 let anonymous = fixture.declarator(None, &[three]);
1646
1647 let mut checker = fixture.checker();
1648 checker.declared_type(void, voids);
1649 checker.declared_type(int, functions);
1650 checker.declared_type(void, anonymous);
1651 assert_eq!(
1652 messages(&checker),
1653 [
1654 "declaration of 'a' as array of voids",
1655 "declaration of 'a' as array of functions",
1656 "declaration of type name as array of voids",
1657 ]
1658 );
1659 }
1660
1661 #[test]
1662 fn an_array_of_a_tag_that_has_no_definition_yet_names_the_type_it_cannot_size() {
1663 let mut fixture = Fixture::new();
1664 let tag = fixture.name("S");
1665 let specs = fixture.specs(
1666 TypeSpec::Record {
1667 kind: ast::RecordKind::Struct,
1668 tag: Some(tag),
1669 fields: None,
1670 attrs: rucc_ast::AttrList::EMPTY,
1671 pack: None,
1672 },
1673 Quals::NONE,
1674 );
1675 let three = fixed(&mut fixture, 3);
1676 let array = fixture.declarator(Some("a"), &[three]);
1677 let star = fixture.declarator(Some("p"), &[pointer()]);
1678
1679 let mut checker = fixture.checker();
1680 let pointer_ty = checker.declared_type(specs, star);
1683 assert_eq!(spelled(&checker, pointer_ty), "struct S *");
1684 checker.declared_type(specs, array);
1685 assert_eq!(message(&checker), "array type has incomplete element type 'struct S'");
1686 }
1687
1688 #[test]
1689 fn an_array_bound_is_folded_and_a_negative_one_is_refused() {
1690 let mut fixture = Fixture::new();
1691 let specs = fixture.int_specs();
1692 let zero = fixed(&mut fixture, 0);
1693 let four = fixed(&mut fixture, 4);
1694 let negative = {
1695 let one = fixture.int(1);
1696 let size = fixture
1697 .ast
1698 .expr(ast::Expr::Unary { op: rucc_ast::UnaryOp::Minus, operand: one }, Span::DUMMY);
1699 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1700 };
1701 let sized = fixture.declarator(Some("a"), &[four]);
1702 let empty = fixture.declarator(Some("a"), &[zero]);
1705 let unspecified = fixture.declarator(
1706 Some("a"),
1707 &[Derived::Array {
1708 size: ArraySize::Unspecified,
1709 quals: Quals::NONE,
1710 has_static: false,
1711 }],
1712 );
1713 let backwards = fixture.declarator(Some("a"), &[negative]);
1714
1715 let mut checker = fixture.checker();
1716 assert_eq!(built(&mut checker, specs, sized), "int[4]");
1717 assert_eq!(built(&mut checker, specs, empty), "int[0]");
1718 assert_eq!(built(&mut checker, specs, unspecified), "int[]");
1719 assert!(messages(&checker).is_empty());
1720
1721 checker.declared_type(specs, backwards);
1722 assert_eq!(message(&checker), "size of array 'a' is negative");
1723 }
1724
1725 #[test]
1726 fn an_array_too_large_to_be_an_object_is_measured_in_its_elements() {
1727 let mut fixture = Fixture::new();
1728 let specs = fixture.int_specs();
1729 let count = u128::from(fixture.target.max_object_size() / 4 + 1);
1732 let huge = fixed(&mut fixture, count);
1733 let a = fixture.declarator(Some("a"), &[huge]);
1734
1735 let mut checker = fixture.checker();
1736 checker.declared_type(specs, a);
1737 assert_eq!(
1738 message(&checker),
1739 "size of array 'a' exceeds maximum object size '9223372036854775807'"
1740 );
1741 }
1742
1743 #[test]
1744 fn a_bound_that_is_not_a_constant_is_a_variable_length_array_where_there_is_a_run_time() {
1745 let mut fixture = Fixture::new();
1746 let specs = fixture.int_specs();
1747 let n = fixture.use_name("n");
1748 let variable =
1749 Derived::Array { size: ArraySize::Expr(n), quals: Quals::NONE, has_static: false };
1750 let a = fixture.declarator(Some("a"), &[variable]);
1751 let name = fixture.name("n");
1752
1753 let mut checker = fixture.checker();
1754 let int = checker.int();
1755 checker.declare_object(name, int, Span::DUMMY);
1756 checker.declared_type(specs, a);
1759 assert_eq!(message(&checker), "variably modified 'a' at file scope");
1760
1761 checker.scopes.push();
1762 let ty = checker.declared_type(specs, a);
1763 assert_eq!(spelled(&checker, ty), "int[*]");
1764 let again = checker.declared_type(specs, a);
1767 assert_ne!(ty, again);
1768 assert_eq!(
1769 checker.tast.vla_size(vla_id(&checker, ty)),
1770 checker.tast.vla_size(vla_id(&checker, ty))
1771 );
1772 }
1773
1774 fn vla_id(checker: &Checker<'_>, ty: TypeId) -> rucc_types::VlaId {
1776 match checker.types.kind(checker.types.canonical(ty)) {
1777 TypeKind::Array { len: ArrayLen::Variable(id), .. } => id,
1778 other => panic!("expected a variable length array, got {other:?}"),
1779 }
1780 }
1781
1782 #[test]
1783 fn a_star_bound_is_only_a_type_inside_a_prototype() {
1784 let mut fixture = Fixture::new();
1785 let specs = fixture.int_specs();
1786 let star = Derived::Array { size: ArraySize::Star, quals: Quals::NONE, has_static: false };
1787 let parameter = fixture.declarator(Some("a"), &[star]);
1788 let params = fixture.ast.add_param_list(&[ast::Param {
1789 specs: Some(specs),
1790 declarator: parameter,
1791 attrs: rucc_ast::AttrList::EMPTY,
1792 span: Span::DUMMY,
1793 }]);
1794 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1795 let f = fixture.declarator(Some("f"), &[call]);
1796
1797 let mut checker = fixture.checker();
1798 let ty = checker.declared_type(specs, f);
1801 assert_eq!(spelled(&checker, ty), "int(int *)");
1802 assert!(messages(&checker).is_empty());
1803
1804 checker.declared_type(specs, parameter);
1805 assert_eq!(message(&checker), "'[*]' not allowed in other than function prototype scope");
1806 }
1807
1808 #[test]
1809 fn a_deduced_type_on_a_parameter_names_nothing_and_says_where_it_was_written() {
1810 let mut fixture = Fixture::new();
1811 let specs = fixture.int_specs();
1814 let deduced = fixture.specs(TypeSpec::Auto(ast::Deduction::Auto), Quals::NONE);
1815 let parameter = fixture.declarator(Some("p"), &[]);
1816 let params = fixture.ast.add_param_list(&[ast::Param {
1817 specs: Some(deduced),
1818 declarator: parameter,
1819 attrs: rucc_ast::AttrList::EMPTY,
1820 span: Span::DUMMY,
1821 }]);
1822 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1823 let f = fixture.declarator(Some("f"), &[call]);
1824
1825 let mut checker = fixture.checker();
1826 let ty = checker.declared_type(specs, f);
1827 assert_eq!(spelled(&checker, ty), "int(int)");
1828 assert_eq!(message(&checker), "'auto' not allowed in function prototype");
1829 }
1830
1831 #[test]
1832 fn the_qualifiers_inside_a_parameters_brackets_are_the_object_s_and_not_the_type_s() {
1833 let mut fixture = Fixture::new();
1834 let specs = fixture.int_specs();
1835 let three = fixture.int(3);
1836 let qualified =
1837 Derived::Array { size: ArraySize::Expr(three), quals: Quals::CONST, has_static: true };
1838 let parameter = fixture.declarator(Some("a"), &[qualified]);
1839 let params = fixture.ast.add_param_list(&[ast::Param {
1840 specs: Some(specs),
1841 declarator: parameter,
1842 attrs: rucc_ast::AttrList::EMPTY,
1843 span: Span::DUMMY,
1844 }]);
1845 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1846 let f = fixture.declarator(Some("f"), &[call]);
1847
1848 let mut checker = fixture.checker();
1849 let ty = checker.declared_type(specs, f);
1855 assert_eq!(spelled(&checker, ty), "int(int *)");
1856 assert!(messages(&checker).is_empty());
1857
1858 checker.declared_type(specs, parameter);
1860 assert_eq!(
1861 message(&checker),
1862 "static or type qualifiers in non-parameter array declarator"
1863 );
1864 }
1865
1866 #[test]
1867 fn a_function_cannot_return_a_function_or_an_array_and_the_message_names_which() {
1868 let mut fixture = Fixture::new();
1869 let specs = fixture.int_specs();
1870 let params = fixture.ast.add_param_list(&[]);
1871 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1872 let three = fixed(&mut fixture, 3);
1873
1874 let returns_function = fixture.declarator(Some("f"), &[call, call]);
1875 let returns_array = fixture.declarator(Some("f"), &[call, three]);
1876 let anonymous = fixture.declarator(None, &[call, three]);
1877
1878 let mut checker = fixture.checker();
1879 checker.declared_type(specs, returns_function);
1880 checker.declared_type(specs, returns_array);
1881 checker.declared_type(specs, anonymous);
1882 assert_eq!(
1883 messages(&checker),
1884 [
1885 "'f' declared as function returning a function",
1886 "'f' declared as function returning an array",
1887 "type name declared as function returning an array",
1888 ]
1889 );
1890 }
1891
1892 #[test]
1893 fn an_empty_parameter_list_says_nothing_before_c23_and_says_none_from_it() {
1894 let mut fixture = Fixture::new();
1895 let specs = fixture.int_specs();
1896 let params = fixture.ast.add_param_list(&[]);
1897 let empty = Derived::Function { params, variadic: false, kind: ParamKind::Empty };
1898 let f = fixture.declarator(Some("f"), &[empty]);
1899
1900 let mut checker = fixture.checker();
1901 assert_eq!(built(&mut checker, specs, f), "int(void)");
1902
1903 let mut old = fixture.checker();
1904 old.cx.std = Std::C17;
1905 assert_eq!(built(&mut old, specs, f), "int()");
1906 assert!(messages(&old).is_empty());
1907 }
1908
1909 #[test]
1910 fn a_parameter_of_type_void_is_only_a_parameter_list_when_it_is_the_whole_of_one() {
1911 let mut fixture = Fixture::new();
1912 let int = fixture.int_specs();
1913 let void = fixture.keywords(&[BuiltinSet::VOID]);
1914 let named = fixture.declarator(Some("v"), &[]);
1915 let unnamed = fixture.declarator(None, &[]);
1916 let param = |declarator| ast::Param {
1917 specs: Some(void),
1918 declarator,
1919 attrs: rucc_ast::AttrList::EMPTY,
1920 span: Span::DUMMY,
1921 };
1922 let params = fixture.ast.add_param_list(&[param(named), param(unnamed)]);
1923 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1924 let f = fixture.declarator(Some("f"), &[call]);
1925
1926 let mut checker = fixture.checker();
1927 checker.declared_type(int, f);
1928 assert_eq!(
1929 messages(&checker),
1930 ["parameter 1 ('v') has void type", "'void' must be the only parameter"]
1931 );
1932 }
1933
1934 #[test]
1935 fn a_parameter_is_in_scope_for_the_parameters_after_it_and_gone_after_the_prototype() {
1936 let mut fixture = Fixture::new();
1937 let specs = fixture.int_specs();
1938 let n = fixture.declarator(Some("n"), &[]);
1939 let bound = fixture.use_name("n");
1940 let a = fixture.declarator(
1941 Some("a"),
1942 &[Derived::Array {
1943 size: ArraySize::Expr(bound),
1944 quals: Quals::NONE,
1945 has_static: false,
1946 }],
1947 );
1948 let param = |declarator| ast::Param {
1949 specs: Some(specs),
1950 declarator,
1951 attrs: rucc_ast::AttrList::EMPTY,
1952 span: Span::DUMMY,
1953 };
1954 let params = fixture.ast.add_param_list(&[param(n), param(a)]);
1955 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1956 let f = fixture.declarator(Some("f"), &[call]);
1957 let name = fixture.name("n");
1958
1959 let mut checker = fixture.checker();
1960 let ty = checker.declared_type(specs, f);
1963 assert_eq!(spelled(&checker, ty), "int(int, int *)");
1964 assert!(messages(&checker).is_empty());
1965 assert!(checker.scopes.lookup(name).is_none());
1966 }
1967
1968 #[test]
1969 fn a_parameter_declared_twice_in_one_prototype_is_reported_once() {
1970 let mut fixture = Fixture::new();
1971 let specs = fixture.int_specs();
1972 let a = fixture.declarator(Some("a"), &[]);
1973 let param = ast::Param {
1974 specs: Some(specs),
1975 declarator: a,
1976 attrs: rucc_ast::AttrList::EMPTY,
1977 span: Span::DUMMY,
1978 };
1979 let params = fixture.ast.add_param_list(&[param, param]);
1980 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1981 let f = fixture.declarator(Some("f"), &[call]);
1982
1983 let mut checker = fixture.checker();
1984 checker.declared_type(specs, f);
1985 assert_eq!(message(&checker), "redefinition of parameter 'a'");
1986 }
1987
1988 #[test]
1989 fn a_tag_names_the_same_type_every_time_and_one_kind_of_thing_only() {
1990 let mut fixture = Fixture::new();
1991 let tag = fixture.name("S");
1992 let record = |kind| TypeSpec::Record {
1993 kind,
1994 tag: Some(tag),
1995 fields: None,
1996 attrs: rucc_ast::AttrList::EMPTY,
1997 pack: None,
1998 };
1999 let structure = fixture.specs(record(ast::RecordKind::Struct), Quals::NONE);
2000 let onion = fixture.specs(record(ast::RecordKind::Union), Quals::NONE);
2001 let plain = fixture.declarator(None, &[]);
2002
2003 let mut checker = fixture.checker();
2004 let first = checker.declared_type(structure, plain);
2005 let second = checker.declared_type(structure, plain);
2006 assert_eq!(first, second);
2007 assert!(messages(&checker).is_empty());
2008
2009 let wrong = checker.declared_type(onion, plain);
2010 assert_eq!(message(&checker), "'S' defined as wrong kind of tag");
2011 assert_ne!(wrong, first);
2014 assert_eq!(checker.declared_type(structure, plain), first);
2015 }
2016
2017 #[test]
2018 fn an_anonymous_tag_is_a_new_type_every_time_it_is_written() {
2019 let mut fixture = Fixture::new();
2020 let anonymous = |fixture: &mut Fixture| {
2021 fixture.specs(
2022 TypeSpec::Record {
2023 kind: ast::RecordKind::Struct,
2024 tag: None,
2025 fields: None,
2026 attrs: rucc_ast::AttrList::EMPTY,
2027 pack: None,
2028 },
2029 Quals::NONE,
2030 )
2031 };
2032 let specs = anonymous(&mut fixture);
2033 let written_again = anonymous(&mut fixture);
2034 let plain = fixture.declarator(None, &[]);
2035
2036 let mut checker = fixture.checker();
2037 let first = checker.declared_type(specs, plain);
2038 let second = checker.declared_type(written_again, plain);
2039 assert_ne!(first, second);
2040 assert_eq!(checker.declared_type(specs, plain), first);
2043 }
2044
2045 #[test]
2046 fn an_enumeration_with_the_underlying_type_written_is_complete_from_there() {
2047 let mut fixture = Fixture::new();
2048 let long = fixture.keywords(&[BuiltinSet::LONG]);
2049 let long_name = fixture.type_name(long, &[]);
2050 let tag = fixture.name("E");
2051 let fixed_enum = fixture.specs(
2052 TypeSpec::Enum {
2053 tag: Some(tag),
2054 enumerators: None,
2055 underlying: Some(long_name),
2056 attrs: rucc_ast::AttrList::EMPTY,
2057 },
2058 Quals::NONE,
2059 );
2060 let plain = fixture.declarator(None, &[]);
2061
2062 let mut checker = fixture.checker();
2063 let ty = checker.declared_type(fixed_enum, plain);
2064 assert_eq!(spelled(&checker, ty), "enum E");
2065 assert!(is_complete(&checker.types, ty));
2066 assert!(messages(&checker).is_empty());
2067 }
2068
2069 #[test]
2070 fn an_enumeration_cannot_be_kept_in_something_that_is_not_an_integer_type() {
2071 let mut fixture = Fixture::new();
2072 let double = fixture.keywords(&[BuiltinSet::DOUBLE]);
2073 let double_name = fixture.type_name(double, &[]);
2074 let specs = fixture.specs(
2075 TypeSpec::Enum {
2076 tag: None,
2077 enumerators: None,
2078 underlying: Some(double_name),
2079 attrs: rucc_ast::AttrList::EMPTY,
2080 },
2081 Quals::NONE,
2082 );
2083 let plain = fixture.declarator(None, &[]);
2084
2085 let mut checker = fixture.checker();
2086 checker.declared_type(specs, plain);
2087 assert_eq!(message(&checker), "invalid 'enum' underlying type");
2088 }
2089
2090 #[test]
2091 fn atomic_is_a_type_and_not_a_qualifier_and_two_things_cannot_be_one() {
2092 let mut fixture = Fixture::new();
2093 let int = fixture.int_specs();
2094 let konst = fixture.specs(
2095 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
2096 Quals::CONST,
2097 );
2098 let plain_name = fixture.type_name(int, &[]);
2099 let three = fixed(&mut fixture, 3);
2100 let array_name = fixture.type_name(int, &[three]);
2101 let params = fixture.ast.add_param_list(&[]);
2102 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
2103 let function_name = fixture.type_name(int, &[call]);
2104 let const_name = fixture.type_name(konst, &[]);
2105
2106 let atomic = |fixture: &mut Fixture, name| {
2107 let specs = fixture.specs(TypeSpec::Atomic(name), Quals::NONE);
2108 let declarator = fixture.declarator(None, &[]);
2109 (specs, declarator)
2110 };
2111 let (plain, hole) = atomic(&mut fixture, plain_name);
2112 let (array, _) = atomic(&mut fixture, array_name);
2113 let (function, _) = atomic(&mut fixture, function_name);
2114 let (qualified, _) = atomic(&mut fixture, const_name);
2115
2116 let mut checker = fixture.checker();
2117 assert_eq!(built(&mut checker, plain, hole), "_Atomic(int)");
2118 assert!(messages(&checker).is_empty());
2119
2120 checker.declared_type(array, hole);
2121 checker.declared_type(function, hole);
2122 checker.declared_type(qualified, hole);
2123 assert_eq!(
2124 messages(&checker),
2125 [
2126 "'_Atomic'-qualified array type",
2127 "'_Atomic'-qualified function type",
2128 "'_Atomic' applied to a qualified type",
2129 ]
2130 );
2131 }
2132
2133 #[test]
2134 fn a_bit_int_is_as_wide_as_it_says_within_the_range_there_is() {
2135 let mut fixture = Fixture::new();
2136 let widths = [37, 1, 200, 0];
2137 let specs: Vec<_> = widths
2138 .iter()
2139 .map(|&width| {
2140 let expr = fixture.int(width);
2141 fixture.specs(bit_int(expr, false), Quals::NONE)
2142 })
2143 .collect();
2144 let plain = fixture.declarator(None, &[]);
2145
2146 let mut checker = fixture.checker();
2147 assert_eq!(built(&mut checker, specs[0], plain), "_BitInt(37)");
2148 assert!(messages(&checker).is_empty());
2149
2150 checker.declared_type(specs[1], plain);
2151 checker.declared_type(specs[2], plain);
2152 checker.declared_type(specs[3], plain);
2153 assert_eq!(
2154 messages(&checker),
2155 [
2156 "'signed _BitInt' argument must be at least 2",
2157 "'_BitInt' argument '200' is larger than 'BITINT_MAXWIDTH' '128'",
2158 "'_BitInt' argument '0' is not a positive integer constant expression",
2159 ]
2160 );
2161 }
2162
2163 #[test]
2164 fn an_unsigned_bit_int_holds_one_bit_where_a_signed_one_cannot() {
2165 let mut fixture = Fixture::new();
2166 let one = fixture.int(1);
2167 let unsigned = fixture.specs(bit_int(one, true), Quals::NONE);
2168 let eight = fixture.int(8);
2169 let wide = fixture.specs(bit_int(eight, true), Quals::NONE);
2170 let plain = fixture.declarator(None, &[]);
2171
2172 let mut checker = fixture.checker();
2173 assert_eq!(built(&mut checker, unsigned, plain), "unsigned _BitInt(1)");
2174 assert_eq!(built(&mut checker, wide, plain), "unsigned _BitInt(8)");
2175 assert!(messages(&checker).is_empty());
2176 }
2177
2178 #[test]
2179 fn a_bit_int_next_to_anything_but_a_sign_names_no_type() {
2180 let mut fixture = Fixture::new();
2181 let width = fixture.int(8);
2182 let mut both = Builtin::NONE.add(BuiltinSet::LONG).expect("`long` rejected");
2183 both = both.add_bit_int(width).expect("`_BitInt` rejected");
2184 let specs = fixture.specs(TypeSpec::Builtin(both), Quals::NONE);
2185 let plain = fixture.declarator(None, &[]);
2186
2187 let mut checker = fixture.checker();
2188 checker.declared_type(specs, plain);
2189 assert_eq!(messages(&checker), ["two or more data types in declaration specifiers"]);
2190 }
2191
2192 #[test]
2193 fn a_typedef_name_is_the_type_it_was_declared_for_and_keeps_its_own_spelling() {
2194 let mut fixture = Fixture::new();
2195 let word = fixture.name("word");
2196 let specs = fixture.specs(TypeSpec::Typedef(word), Quals::CONST);
2197 let p = fixture.declarator(Some("p"), &[pointer()]);
2198
2199 let mut checker = fixture.checker();
2200 let long = checker.types.int(IntKind::Long);
2201 let alias = checker.types.typedef(word, long);
2202 checker.declare_typedef(word, alias);
2203
2204 let ty = checker.declared_type(specs, p);
2205 assert_eq!(spelled(&checker, ty), "const word *");
2206 assert!(messages(&checker).is_empty());
2207 }
2208
2209 #[test]
2210 fn typeof_takes_the_type_of_an_expression_it_does_not_evaluate() {
2211 let mut fixture = Fixture::new();
2212 let x = fixture.use_name("x");
2213 let plain = fixture
2214 .specs(TypeSpec::Typeof { unqual: false, operand: TypeofArg::Expr(x) }, Quals::NONE);
2215 let bare = fixture
2216 .specs(TypeSpec::Typeof { unqual: true, operand: TypeofArg::Expr(x) }, Quals::NONE);
2217 let hole = fixture.declarator(None, &[]);
2218 let name = fixture.name("x");
2219
2220 let mut checker = fixture.checker();
2221 let int = checker.int();
2222 let konst = checker.types.qualified(int, Qualifiers::CONST);
2223 checker.declare_object(name, konst, Span::DUMMY);
2224
2225 assert_eq!(built(&mut checker, plain, hole), "const int");
2226 assert_eq!(built(&mut checker, bare, hole), "int");
2228 assert!(messages(&checker).is_empty());
2229 }
2230}