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
65const MAX_OBJECT_SIZE: u64 = i64::MAX as u64;
70
71#[derive(Debug, Default)]
73pub(crate) struct Built {
74 specified: HashMap<ast::DeclSpecsId, TypeId>,
81 defined: HashSet<TypeId>,
88 params: HashMap<Idx<ast::Param>, Vec<DeclId>>,
97 va_list: Option<TypeId>,
104}
105
106#[derive(Debug, Clone, Copy)]
113struct Subject {
114 name: Option<Symbol>,
116 span: Span,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122enum TagUse {
123 Known(TypeId),
125 New,
127 Anonymous,
129 Wrong,
131}
132
133#[derive(Debug, Clone, Copy, Default)]
135pub(in crate::check) struct Place {
136 parameter: bool,
139 member: bool,
142 prototype: bool,
145}
146
147pub(in crate::check) const MEMBER: Place =
149 Place { parameter: false, member: true, prototype: false };
150
151impl Checker<'_> {
152 pub fn type_name(&mut self, id: ast::TypeNameId) -> TypeId {
154 let name = self.ast[id];
155 self.declared_type(name.specs, name.declarator)
156 }
157
158 pub fn declared_type(
164 &mut self,
165 specs: ast::DeclSpecsId,
166 declarator: ast::DeclaratorId,
167 ) -> TypeId {
168 self.build_type(specs, declarator, Place::default())
169 }
170
171 pub(in crate::check) fn declared_specs(&mut self, specs: ast::DeclSpecsId) -> TypeId {
176 let span = self.ast[specs].span;
177 self.specified_type(specs, Subject { name: None, span }, Place::default())
178 }
179
180 pub fn declare_typedef(&mut self, name: Symbol, ty: TypeId) {
186 self.scopes.declare(name, Binding::Typedef(ty));
187 }
188
189 fn build_type(
191 &mut self,
192 specs: ast::DeclSpecsId,
193 declarator: ast::DeclaratorId,
194 place: Place,
195 ) -> TypeId {
196 let node = self.ast[declarator];
197 let subject = Subject {
198 name: node.name,
199 span: if node.name.is_some() { node.name_span } else { node.span },
200 };
201 let base = self.specified_type(specs, subject, place);
202 self.derive(base, declarator, subject, place)
203 }
204
205 fn specified_type(&mut self, id: ast::DeclSpecsId, subject: Subject, place: Place) -> TypeId {
212 if let Some(&ty) = self.built.specified.get(&id) {
213 return ty;
214 }
215 let specs = self.ast[id];
216 let base = self.type_spec(specs.ty, specs.span, subject, place);
217 let ty = self.qualify(base, specs.quals, specs.span);
218 self.built.specified.insert(id, ty);
219 ty
220 }
221
222 fn type_spec(&mut self, spec: TypeSpec, span: Span, subject: Subject, place: Place) -> TypeId {
224 match spec {
225 TypeSpec::None => {
226 let what = match subject.name {
227 Some(name) => format!("in declaration of '{}'", self.text(name)),
228 None => String::new(),
229 };
230 let message = format!("type defaults to 'int' {what}");
231 self.report(
232 Diagnostic::error(message.trim_end().to_string(), subject.span)
233 .with_code("E0526"),
234 );
235 self.int()
236 }
237 TypeSpec::Builtin(builtin) => match builtin.resolve() {
238 Some(basic) => self.basic_type(basic.scalar, basic.complexity, span),
239 None => {
240 self.report(
241 Diagnostic::error(
242 "two or more data types in declaration specifiers".to_string(),
243 span,
244 )
245 .with_code("E0525"),
246 );
247 self.int()
248 }
249 },
250 TypeSpec::Record { kind, tag, fields, .. } => self.record_spec(kind, tag, fields, span),
251 TypeSpec::Enum { tag, enumerators, underlying, .. } => {
252 self.enum_spec(tag, enumerators, underlying, span)
253 }
254 TypeSpec::Typedef(name) => match self.scopes.lookup(name) {
255 Some(Binding::Typedef(ty)) => ty,
256 _ => {
261 let name = self.text(name).to_owned();
262 self.report(
263 Diagnostic::error(format!("unknown type name '{name}'"), span)
264 .with_code("E0546"),
265 );
266 self.int()
267 }
268 },
269 TypeSpec::Typeof { unqual, operand } => self.typeof_type(unqual, operand),
270 TypeSpec::Atomic(inner) => {
271 let inner = self.type_name(inner);
272 self.atomic_type(inner, span)
273 }
274 TypeSpec::VaList => self.va_list_type(),
275 TypeSpec::Auto(which) => {
276 let spelled = which.spelling();
284 let place = if place.member { "struct member" } else { "function prototype" };
285 self.report(
286 Diagnostic::error(format!("'{spelled}' not allowed in {place}"), span)
287 .with_code("E0651"),
288 );
289 self.int()
290 }
291 }
292 }
293
294 fn basic_type(&mut self, scalar: Scalar, complexity: Complexity, span: Span) -> TypeId {
296 let kind = int_kind(scalar);
297 let float = float_kind(scalar, self.cx.target);
298
299 match complexity {
300 Complexity::Real => match (scalar, kind, float) {
301 (Scalar::Void, _, _) => self.types.void(),
302 (Scalar::Bool, _, _) => self.types.boolean(),
303 (Scalar::BitInt { width, unsigned }, _, _) => self.bit_int_type(width, !unsigned),
304 (_, Some(kind), _) => self.types.int(kind),
305 (_, _, Some(kind)) => self.types.float(kind),
306 (Scalar::Float128x | Scalar::Float80, _, _) => {
310 self.unavailable_type(spell_scalar(scalar), span);
311 self.types.float(FloatKind::Double)
312 }
313 _ => {
317 self.unsupported_type(&format!("the type `{}`", spell_scalar(scalar)), span);
318 self.types.float(FloatKind::Double)
319 }
320 },
321 Complexity::Complex => match float {
322 Some(kind) => self.types.complex(kind),
323 None => {
327 let what = format!("`_Complex` on the type `{}`", spell_scalar(scalar));
328 self.unsupported_type(&what, span);
329 self.types.complex(FloatKind::Double)
330 }
331 },
332 Complexity::Imaginary => {
334 self.unsupported_type("`_Imaginary`", span);
335 self.types.complex(float.unwrap_or(FloatKind::Double))
336 }
337 }
338 }
339
340 pub(crate) fn va_list_type(&mut self) -> TypeId {
347 if let Some(ty) = self.built.va_list {
348 return ty;
349 }
350 let ty = match self.cx.target.va_list {
351 VaList::CharPointer => {
352 let elem = self.types.int(IntKind::Char);
353 self.types.pointer(elem)
354 }
355 VaList::VoidPointer => {
356 let elem = self.types.void();
357 self.types.pointer(elem)
358 }
359 VaList::SysV => {
360 let uint = self.types.int(IntKind::UInt);
361 let void = self.types.void();
362 let ptr = self.types.pointer(void);
363 let record = self.builtin_record(
364 sym::VA_LIST_TAG,
365 &[
366 (sym::GP_OFFSET, uint),
367 (sym::FP_OFFSET, uint),
368 (sym::OVERFLOW_ARG_AREA, ptr),
369 (sym::REG_SAVE_AREA, ptr),
370 ],
371 );
372 self.types.array(record, ArrayLen::Fixed(1))
376 }
377 VaList::Aapcs => {
378 let int = self.types.int(IntKind::Int);
379 let void = self.types.void();
380 let ptr = self.types.pointer(void);
381 self.builtin_record(
382 sym::VA_LIST,
383 &[
384 (sym::STACK, ptr),
385 (sym::GR_TOP, ptr),
386 (sym::VR_TOP, ptr),
387 (sym::GR_OFFS, int),
388 (sym::VR_OFFS, int),
389 ],
390 )
391 }
392 };
393 self.built.va_list = Some(ty);
394 ty
395 }
396
397 fn builtin_record(&mut self, tag: Symbol, members: &[(Symbol, TypeId)]) -> TypeId {
403 let id = self.types.declare_record(RecordKind::Struct, Some(tag));
404 let decls: Vec<FieldDecl> =
405 members.iter().map(|&(name, ty)| FieldDecl::new(Some(name), ty)).collect();
406 let laid_out = rucc_types::layout_record(
407 &self.types,
408 RecordKind::Struct,
409 &decls,
410 &RecordOptions::default(),
411 self.cx.target,
412 )
413 .expect("a record of pointers and integers lays out");
414 self.types.complete_record(id, laid_out);
415 self.types.record(id)
416 }
417
418 fn typeof_type(&mut self, unqual: bool, operand: TypeofArg) -> TypeId {
420 let ty = match operand {
424 TypeofArg::Expr(expr) => {
425 let node = self.expr(expr);
426 self.tast[node].ty
427 }
428 TypeofArg::Type(name) => self.type_name(name),
429 };
430 if !unqual {
431 return ty;
432 }
433 let bare = match self.types.kind(self.types.canonical(ty)) {
436 rucc_types::TypeKind::Atomic(inner) => inner,
437 _ => ty,
438 };
439 self.types.unqualified(bare)
440 }
441
442 fn bit_int_type(&mut self, width: ast::ExprId, signed: bool) -> TypeId {
448 let value = self.expr(width);
449 let span = self.tast.expr_span(value);
450 let Ok(bits) = self.eval_integer(value) else {
451 if !self.is_poisoned(value) {
454 self.report(
455 Diagnostic::error(
456 "'_BitInt' argument is not an integer constant expression".to_string(),
457 span,
458 )
459 .with_code("E0529"),
460 );
461 }
462 return self.int();
463 };
464 if bits <= 0 {
465 let message = format!(
466 "'_BitInt' argument '{bits}' is not a positive integer constant expression"
467 );
468 self.report(Diagnostic::error(message, span).with_code("E0529"));
469 return self.int();
470 }
471 if signed && bits < 2 {
472 let message = "'signed _BitInt' argument must be at least 2".to_string();
473 self.report(Diagnostic::error(message, span).with_code("E0529"));
474 return self.int();
475 }
476 if bits > i128::from(MAX_BIT_INT_WIDTH) {
477 let message = format!(
478 "'_BitInt' argument '{bits}' is larger than 'BITINT_MAXWIDTH' '{MAX_BIT_INT_WIDTH}'"
479 );
480 self.report(Diagnostic::error(message, span).with_code("E0529"));
481 return self.int();
482 }
483 let bits = u32::try_from(bits).unwrap_or(MAX_BIT_INT_WIDTH);
484 self.types.bit_int(signed, bits)
485 }
486
487 fn atomic_type(&mut self, inner: TypeId, span: Span) -> TypeId {
489 let canonical = self.types.canonical(inner);
490 let what = if rucc_types::is_array(&self.types, canonical) {
491 "'_Atomic'-qualified array type"
492 } else if is_function(&self.types, canonical) {
493 "'_Atomic'-qualified function type"
494 } else if !self.types.quals(inner).is_none() {
495 "'_Atomic' applied to a qualified type"
496 } else {
497 return self.types.atomic(inner);
498 };
499 self.report(Diagnostic::error(what.to_string(), span).with_code("E0527"));
500 inner
501 }
502
503 fn record_spec(
505 &mut self,
506 kind: ast::RecordKind,
507 tag: Option<Symbol>,
508 fields: Option<ast::MemberList>,
509 span: Span,
510 ) -> TypeId {
511 let (kind, tag_kind) = match kind {
512 ast::RecordKind::Struct => (RecordKind::Struct, TagKind::Struct),
513 ast::RecordKind::Union => (RecordKind::Union, TagKind::Union),
514 };
515 let Some(members) = fields else {
516 return match self.tag_use(tag, tag_kind, span) {
517 TagUse::Known(ty) => ty,
518 found => {
519 let id = self.types.declare_record(kind, tag);
520 let ty = self.types.record(id);
521 self.bind_tag(found, tag, tag_kind, ty);
522 ty
523 }
524 };
525 };
526 let (id, ty) = self.record_defined(kind, tag, tag_kind, span);
530 self.built.defined.insert(ty);
531 self.record_body(id, kind, members, span);
532 ty
533 }
534
535 fn enum_spec(
537 &mut self,
538 tag: Option<Symbol>,
539 enumerators: Option<ast::EnumeratorList>,
540 underlying: Option<ast::TypeNameId>,
541 span: Span,
542 ) -> TypeId {
543 let underlying = underlying.map(|name| {
544 let ty = self.type_name(name);
545 if is_integer(&self.types, self.types.canonical(ty)) {
546 return ty;
547 }
548 self.report(
549 Diagnostic::error("invalid 'enum' underlying type".to_string(), span)
550 .with_code("E0530"),
551 );
552 self.int()
553 });
554
555 let Some(list) = enumerators else {
556 return match self.tag_use(tag, TagKind::Enum, span) {
557 TagUse::Known(ty) => ty,
558 found => {
559 let id = self.types.declare_enum(tag);
560 if let Some(underlying) = underlying {
564 self.types.complete_enum(id, underlying, true);
565 }
566 let ty = self.types.enumeration(id);
567 self.bind_tag(found, tag, TagKind::Enum, ty);
568 ty
569 }
570 };
571 };
572 let (id, ty) = self.enum_defined(tag, span);
573 self.built.defined.insert(ty);
574 self.enum_body(id, list, underlying, span);
575 ty
576 }
577
578 fn tag_use(&mut self, tag: Option<Symbol>, kind: TagKind, span: Span) -> TagUse {
587 let Some(name) = tag else { return TagUse::Anonymous };
590 match self.scopes.tag(name) {
591 Some(found) if found.kind == kind => TagUse::Known(found.ty),
592 Some(_) => {
593 let spelled = self.text(name).to_owned();
594 self.report(
595 Diagnostic::error(format!("'{spelled}' defined as wrong kind of tag"), span)
596 .with_code("E0531"),
597 );
598 TagUse::Wrong
599 }
600 None => TagUse::New,
601 }
602 }
603
604 fn bind_tag(&mut self, found: TagUse, tag: Option<Symbol>, kind: TagKind, ty: TypeId) {
606 if !matches!(found, TagUse::New) {
610 return;
611 }
612 if let Some(name) = tag {
613 self.scopes.declare_tag(name, Tag { kind, ty });
614 }
615 }
616
617 pub(in crate::check) fn qualify(
619 &mut self,
620 ty: TypeId,
621 quals: ast::Quals,
622 span: Span,
623 ) -> TypeId {
624 let ty = if quals.has(ast::Quals::ATOMIC) { self.atomic_type(ty, span) } else { ty };
628 let mut result = Qualifiers::NONE;
629 if quals.has(ast::Quals::CONST) {
630 result = result.with(Qualifiers::CONST);
631 }
632 if quals.has(ast::Quals::VOLATILE) {
633 result = result.with(Qualifiers::VOLATILE);
634 }
635 if quals.has(ast::Quals::RESTRICT) {
636 if is_pointer(&self.types, self.types.canonical(ty)) {
637 result = result.with(Qualifiers::RESTRICT);
638 } else {
639 self.report(
640 Diagnostic::error("invalid use of 'restrict'".to_string(), span)
641 .with_code("E0528"),
642 );
643 }
644 }
645 self.types.qualified(ty, result)
646 }
647
648 fn derive(
650 &mut self,
651 base: TypeId,
652 declarator: ast::DeclaratorId,
653 subject: Subject,
654 place: Place,
655 ) -> TypeId {
656 let ast = self.ast;
659 let steps = &ast[ast[declarator].derived];
660 let mut ty = base;
661 for (index, step) in steps.iter().enumerate().rev() {
662 let nearest = index == 0;
665 ty = match *step {
666 Derived::Pointer { quals, .. } => {
667 let pointer = self.types.pointer(ty);
668 self.qualify(pointer, quals, subject.span)
669 }
670 Derived::Array { size, quals, has_static } => {
671 if (!quals.is_none() || has_static) && !(place.parameter && nearest) {
672 self.report(
673 Diagnostic::error(
674 "static or type qualifiers in non-parameter array declarator"
675 .to_string(),
676 subject.span,
677 )
678 .with_code("E0540"),
679 );
680 }
681 self.array_of(ty, size, subject, place)
682 }
683 Derived::Function { params, variadic, kind } => {
684 self.function_of(ty, params, variadic, kind, subject)
685 }
686 };
687 }
688 ty
689 }
690
691 fn array_of(
693 &mut self,
694 elem: TypeId,
695 size: ArraySize,
696 subject: Subject,
697 place: Place,
698 ) -> TypeId {
699 let canonical = self.types.canonical(elem);
700 let bad = if is_void(&self.types, canonical) {
701 Some(("as array of voids", "E0532"))
702 } else if is_function(&self.types, canonical) {
703 Some(("as array of functions", "E0533"))
704 } else {
705 None
706 };
707 if let Some((what, code)) = bad {
708 let who = self.declaration_of(subject);
709 self.report(Diagnostic::error(format!("{who} {what}"), subject.span).with_code(code));
710 return elem;
711 }
712 if !is_complete(&self.types, canonical) {
713 let spelled = self.spell(elem);
714 self.report(
715 Diagnostic::error(
716 format!("array type has incomplete element type '{spelled}'"),
717 subject.span,
718 )
719 .with_code("E0534"),
720 );
721 return elem;
722 }
723 let len = self.array_len(elem, size, subject, place);
724 self.types.array(elem, len)
725 }
726
727 fn array_len(
729 &mut self,
730 elem: TypeId,
731 size: ArraySize,
732 subject: Subject,
733 place: Place,
734 ) -> ArrayLen {
735 let expr = match size {
736 ArraySize::Unspecified => return ArrayLen::Unknown,
737 ArraySize::Star if place.prototype => return ArrayLen::Star,
738 ArraySize::Star => {
739 self.report(
740 Diagnostic::error(
741 "'[*]' not allowed in other than function prototype scope".to_string(),
742 subject.span,
743 )
744 .with_code("E0539"),
745 );
746 return ArrayLen::Unknown;
747 }
748 ArraySize::Expr(expr) => expr,
749 };
750
751 let value = self.expr(expr);
752 if self.is_poisoned(value) {
753 return ArrayLen::Unknown;
754 }
755 let value = self.value(value);
759 let span = self.tast.expr_span(value);
760 if !is_integer(&self.types, self.types.canonical(self.tast[value].ty)) {
761 self.report(
762 Diagnostic::error("size of array has non-integer type".to_string(), span)
763 .with_code("E0535"),
764 );
765 return ArrayLen::Unknown;
766 }
767
768 match self.eval_integer(value) {
769 Ok(count) if count < 0 => {
770 let who = self.array_named(subject);
771 self.report(
772 Diagnostic::error(format!("size of {who} is negative"), span)
773 .with_code("E0536"),
774 );
775 ArrayLen::Unknown
776 }
777 Ok(count) => {
778 let count = u64::try_from(count).unwrap_or(u64::MAX);
779 if self.too_large(elem, count) {
780 let who = self.array_named(subject);
781 let message =
782 format!("size of {who} exceeds maximum object size '{MAX_OBJECT_SIZE}'");
783 self.report(Diagnostic::error(message, span).with_code("E0537"));
784 return ArrayLen::Unknown;
785 }
786 ArrayLen::Fixed(count)
787 }
788 Err(failure) => {
791 if failure.poisoned {
792 return ArrayLen::Unknown;
793 }
794 if self.scopes.at_file_scope() {
795 let who = match subject.name {
796 Some(name) => format!("'{}'", self.text(name)),
797 None => "type name".to_string(),
798 };
799 self.report(
800 Diagnostic::error(
801 format!("variably modified {who} at file scope"),
802 subject.span,
803 )
804 .with_code("E0538"),
805 );
806 return ArrayLen::Unknown;
807 }
808 ArrayLen::Variable(self.tast.add_vla(value))
809 }
810 }
811 }
812
813 fn too_large(&self, elem: TypeId, count: u64) -> bool {
815 let Ok(elem) = layout(&self.types, elem, self.cx.target) else {
816 return false;
817 };
818 elem.size != 0 && count > MAX_OBJECT_SIZE / elem.size
820 }
821
822 fn function_of(
824 &mut self,
825 ret: TypeId,
826 params: ast::ParamList,
827 variadic: bool,
828 kind: ParamKind,
829 subject: Subject,
830 ) -> TypeId {
831 let canonical = self.types.canonical(ret);
832 let bad = if rucc_types::is_array(&self.types, canonical) {
833 Some(("an array", "E0542"))
834 } else if is_function(&self.types, canonical) {
835 Some(("a function", "E0541"))
836 } else {
837 None
838 };
839 let ret = match bad {
840 Some((what, code)) => {
841 let who = self.declared_as(subject);
842 self.report(
843 Diagnostic::error(format!("{who} as function returning {what}"), subject.span)
844 .with_code(code),
845 );
846 self.int()
847 }
848 None => ret,
849 };
850
851 let (params, prototyped) = match kind {
852 ParamKind::Void => (Vec::new(), true),
853 ParamKind::Empty => (Vec::new(), self.cx.std == Std::C23),
856 ParamKind::Identifiers => (Vec::new(), false),
860 ParamKind::Prototype => (self.prototype(params), true),
861 };
862 self.types.function(FunctionType { ret, params, variadic, prototyped })
863 }
864
865 fn prototype(&mut self, params: ast::ParamList) -> Vec<TypeId> {
867 let ast = self.ast;
868 let list = &ast[params];
869 self.scopes.push();
874 let mut types = Vec::with_capacity(list.len());
875 let mut declared = Vec::new();
876 for (index, param) in list.iter().enumerate() {
877 let ty = match param.specs {
878 Some(specs) => self.build_type(
879 specs,
880 param.declarator,
881 Place { parameter: true, member: false, prototype: true },
882 ),
883 None => self.int(),
886 };
887 let declarator = ast[param.declarator];
888 let span = if declarator.name.is_some() { declarator.name_span } else { param.span };
889 self.check_void_parameter(ty, declarator.name, index, span);
890
891 let adjusted = adjust_parameter(&mut self.types, ty);
898 let written = self.types.canonical(ty);
904 let object = if rucc_types::is_array(&self.types, written) {
905 match ast[declarator.derived].first() {
909 Some(&Derived::Array { quals, .. }) => self.qualify(adjusted, quals, span),
910 _ => adjusted,
911 }
912 } else if is_function(&self.types, written) {
913 adjusted
914 } else {
915 ty
916 };
917 types.push(adjusted);
918
919 if let Some(name) = declarator.name {
920 if self.scopes.lookup_here(name).is_some() {
921 let spelled = self.text(name).to_owned();
922 self.report(
923 Diagnostic::error(format!("redefinition of parameter '{spelled}'"), span)
924 .with_code("E0545"),
925 );
926 } else {
927 declared.push(self.declare_object(name, object, span));
931 }
932 }
933 }
934 self.scopes.pop();
935 if let Some(first) = params.iter().next() {
936 self.built.params.insert(first, declared);
937 }
938 types
939 }
940
941 pub(in crate::check) fn prototype_params(&self, params: ast::ParamList) -> Vec<DeclId> {
945 params
946 .iter()
947 .next()
948 .and_then(|first| self.built.params.get(&first))
949 .cloned()
950 .unwrap_or_default()
951 }
952
953 fn check_void_parameter(&mut self, ty: TypeId, name: Option<Symbol>, index: usize, span: Span) {
956 if !is_void(&self.types, self.types.canonical(ty)) {
957 return;
958 }
959 let position = index + 1;
960 match name {
961 Some(name) => {
962 let spelled = self.text(name).to_owned();
963 self.report(
964 Diagnostic::warning(
965 format!("parameter {position} ('{spelled}') has void type"),
966 span,
967 )
968 .with_code("E0544"),
969 );
970 }
971 None => {
974 self.report(
975 Diagnostic::error("'void' must be the only parameter".to_string(), span)
976 .with_code("E0543"),
977 );
978 }
979 }
980 }
981
982 fn declaration_of(&self, subject: Subject) -> String {
984 match subject.name {
985 Some(name) => format!("declaration of '{}'", self.text(name)),
986 None => "declaration of type name".to_string(),
987 }
988 }
989
990 fn declared_as(&self, subject: Subject) -> String {
992 match subject.name {
993 Some(name) => format!("'{}' declared", self.text(name)),
994 None => "type name declared".to_string(),
995 }
996 }
997
998 fn array_named(&self, subject: Subject) -> String {
1000 match subject.name {
1001 Some(name) => format!("array '{}'", self.text(name)),
1002 None => "unnamed array".to_string(),
1003 }
1004 }
1005
1006 fn unsupported_type(&mut self, what: &str, span: Span) {
1008 self.report(
1009 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1010 );
1011 }
1012
1013 fn unavailable_type(&mut self, name: &str, span: Span) {
1015 self.report(
1016 Diagnostic::error(format!("'{name}' is not supported on this target"), span)
1017 .with_code("E0589"),
1018 );
1019 }
1020}
1021
1022fn int_kind(scalar: Scalar) -> Option<IntKind> {
1024 let kind = match scalar {
1027 Scalar::Char => IntKind::Char,
1028 Scalar::SignedChar => IntKind::SChar,
1029 Scalar::UnsignedChar => IntKind::UChar,
1030 Scalar::Short => IntKind::Short,
1031 Scalar::UnsignedShort => IntKind::UShort,
1032 Scalar::Int => IntKind::Int,
1033 Scalar::UnsignedInt => IntKind::UInt,
1034 Scalar::Long => IntKind::Long,
1035 Scalar::UnsignedLong => IntKind::ULong,
1036 Scalar::LongLong => IntKind::LongLong,
1037 Scalar::UnsignedLongLong => IntKind::ULongLong,
1038 Scalar::Int128 => IntKind::Int128,
1039 Scalar::UnsignedInt128 => IntKind::UInt128,
1040 _ => return None,
1041 };
1042 Some(kind)
1043}
1044
1045fn float_kind(scalar: Scalar, target: &TargetInfo) -> Option<FloatKind> {
1053 match scalar {
1054 Scalar::Float => Some(FloatKind::Float),
1055 Scalar::Double => Some(FloatKind::Double),
1056 Scalar::LongDouble => Some(FloatKind::LongDouble),
1057 Scalar::Float16 => Some(FloatKind::Float16),
1058 Scalar::Float32 => Some(FloatKind::Float32),
1059 Scalar::Float64 => Some(FloatKind::Float64),
1060 Scalar::Float128 => Some(FloatKind::Float128),
1061 Scalar::Float32x => Some(FloatKind::Float32x),
1062 Scalar::Float64x => Some(FloatKind::Float64x),
1063 Scalar::Float80 if target.long_double_format == Format::X87Extended => {
1064 Some(FloatKind::LongDouble)
1065 }
1066 _ => None,
1067 }
1068}
1069
1070fn spell_scalar(scalar: Scalar) -> &'static str {
1072 match scalar {
1073 Scalar::Void => "void",
1074 Scalar::Bool => "bool",
1075 Scalar::Char => "char",
1076 Scalar::SignedChar => "signed char",
1077 Scalar::UnsignedChar => "unsigned char",
1078 Scalar::Short => "short",
1079 Scalar::UnsignedShort => "unsigned short",
1080 Scalar::Int => "int",
1081 Scalar::UnsignedInt => "unsigned int",
1082 Scalar::Long => "long",
1083 Scalar::UnsignedLong => "unsigned long",
1084 Scalar::LongLong => "long long",
1085 Scalar::UnsignedLongLong => "unsigned long long",
1086 Scalar::Int128 => "__int128",
1087 Scalar::UnsignedInt128 => "unsigned __int128",
1088 Scalar::BitInt { unsigned: false, .. } => "_BitInt",
1091 Scalar::BitInt { unsigned: true, .. } => "unsigned _BitInt",
1092 Scalar::Float => "float",
1093 Scalar::Double => "double",
1094 Scalar::LongDouble => "long double",
1095 Scalar::Float16 => "_Float16",
1096 Scalar::Float32 => "_Float32",
1097 Scalar::Float64 => "_Float64",
1098 Scalar::Float128 => "_Float128",
1099 Scalar::Float32x => "_Float32x",
1100 Scalar::Float64x => "_Float64x",
1101 Scalar::Float128x => "_Float128x",
1102 Scalar::Float80 => "__float80",
1103 Scalar::Decimal32 => "_Decimal32",
1104 Scalar::Decimal64 => "_Decimal64",
1105 Scalar::Decimal128 => "_Decimal128",
1106 }
1107}
1108
1109#[cfg(test)]
1112mod tests {
1113 use rucc_ast::{Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId, Quals};
1114 use rucc_base::Interner;
1115 use rucc_lex::{IntConstant, IntConstantType, Remarks};
1116 use rucc_target::{TargetInfo, Triple};
1117 use rucc_types::{TypeKind, spell};
1118
1119 use super::*;
1120 use crate::check::Context;
1121
1122 pub(super) struct Fixture {
1128 pub(super) ast: rucc_ast::Ast,
1129 names: Interner,
1130 target: TargetInfo,
1131 }
1132
1133 impl Fixture {
1134 pub(super) fn new() -> Fixture {
1135 Fixture::for_target("x86_64-unknown-linux-gnu")
1136 }
1137
1138 pub(super) fn for_target(triple: &str) -> Fixture {
1140 let target = TargetInfo::new(triple.parse::<Triple>().expect("a triple"));
1141 Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1142 }
1143
1144 pub(super) fn name(&mut self, text: &str) -> Symbol {
1145 self.names.intern(text)
1146 }
1147
1148 pub(super) fn keywords(&mut self, written: &[BuiltinSet]) -> DeclSpecsId {
1150 let mut builtin = Builtin::NONE;
1151 for &keyword in written {
1152 builtin = builtin.add(keyword).expect("a keyword written once");
1153 }
1154 self.specs(TypeSpec::Builtin(builtin), Quals::NONE)
1155 }
1156
1157 pub(super) fn int_specs(&mut self) -> DeclSpecsId {
1159 self.keywords(&[BuiltinSet::INT])
1160 }
1161
1162 pub(super) fn specs(&mut self, ty: TypeSpec, quals: Quals) -> DeclSpecsId {
1163 let mut specs = DeclSpecs::empty(Span::DUMMY);
1164 specs.ty = ty;
1165 specs.quals = quals;
1166 self.ast.add_specs(specs)
1167 }
1168
1169 pub(super) fn declarator(
1170 &mut self,
1171 name: Option<&str>,
1172 derived: &[Derived],
1173 ) -> DeclaratorId {
1174 let name = name.map(|text| self.name(text));
1175 let derived = self.ast.add_derived_list(derived);
1176 self.ast.add_declarator(Declarator {
1177 name,
1178 name_span: Span::DUMMY,
1179 derived,
1180 span: Span::DUMMY,
1181 })
1182 }
1183
1184 pub(super) fn type_name(
1186 &mut self,
1187 specs: DeclSpecsId,
1188 derived: &[Derived],
1189 ) -> ast::TypeNameId {
1190 let declarator = self.declarator(None, derived);
1191 self.ast.add_type_name(ast::TypeName { specs, declarator, span: Span::DUMMY })
1192 }
1193
1194 pub(super) fn int(&mut self, value: u128) -> ast::ExprId {
1196 let ty = IntConstantType::Standard(IntKind::Int);
1197 let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1198 self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1199 }
1200
1201 fn use_name(&mut self, text: &str) -> ast::ExprId {
1202 let name = self.name(text);
1203 self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1204 }
1205
1206 pub(super) fn checker(&self) -> Checker<'_> {
1207 Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1208 }
1209 }
1210
1211 fn fixed(fixture: &mut Fixture, count: u128) -> Derived {
1213 let size = fixture.int(count);
1214 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1215 }
1216
1217 fn pointer() -> Derived {
1219 Derived::Pointer { quals: Quals::NONE, attrs: rucc_ast::AttrList::EMPTY }
1220 }
1221
1222 fn bit_int(width: ast::ExprId, unsigned: bool) -> TypeSpec {
1224 let mut builtin = Builtin::NONE.add_bit_int(width).expect("`_BitInt` rejected");
1225 if unsigned {
1226 builtin = builtin.add(BuiltinSet::UNSIGNED).expect("`unsigned` rejected");
1227 }
1228 TypeSpec::Builtin(builtin)
1229 }
1230
1231 pub(super) fn spelled(checker: &Checker<'_>, ty: TypeId) -> String {
1233 spell(&checker.types, checker.cx.names, ty)
1234 }
1235
1236 fn built(checker: &mut Checker<'_>, specs: DeclSpecsId, declarator: DeclaratorId) -> String {
1238 let ty = checker.declared_type(specs, declarator);
1239 spelled(checker, ty)
1240 }
1241
1242 pub(super) fn messages(checker: &Checker<'_>) -> Vec<String> {
1244 checker.errors.diagnostics().iter().map(|d| d.message.clone()).collect()
1245 }
1246
1247 pub(super) fn message(checker: &Checker<'_>) -> String {
1249 let mut reported = messages(checker);
1250 assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1251 reported.pop().expect("one message")
1252 }
1253
1254 #[test]
1255 fn the_keywords_of_a_specifier_list_name_one_type_between_them() {
1256 let mut fixture = Fixture::new();
1257 let long = fixture.keywords(&[BuiltinSet::UNSIGNED, BuiltinSet::LONG, BuiltinSet::INT]);
1258 let double = fixture.keywords(&[BuiltinSet::LONG, BuiltinSet::DOUBLE]);
1259 let void = fixture.keywords(&[BuiltinSet::VOID]);
1260 let plain = fixture.declarator(Some("x"), &[]);
1261
1262 let mut checker = fixture.checker();
1263 assert_eq!(built(&mut checker, long, plain), "unsigned long");
1264 assert_eq!(built(&mut checker, double, plain), "long double");
1265 assert_eq!(built(&mut checker, void, plain), "void");
1266 assert!(messages(&checker).is_empty());
1267 }
1268
1269 #[test]
1270 fn each_spelling_of_a_floating_type_names_a_type_of_its_own() {
1271 let mut fixture = Fixture::new();
1272 let written = [
1273 (BuiltinSet::FLOAT16, "_Float16"),
1274 (BuiltinSet::FLOAT32, "_Float32"),
1275 (BuiltinSet::FLOAT64, "_Float64"),
1276 (BuiltinSet::FLOAT128, "_Float128"),
1277 (BuiltinSet::FLOAT32X, "_Float32x"),
1278 (BuiltinSet::FLOAT64X, "_Float64x"),
1279 ];
1280 let specs: Vec<_> =
1281 written.iter().map(|&(keyword, _)| fixture.keywords(&[keyword])).collect();
1282 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1285 let plain = fixture.declarator(Some("x"), &[]);
1286
1287 let mut checker = fixture.checker();
1288 for (specs, expected) in specs.into_iter().zip(written.iter().map(|&(_, name)| name)) {
1289 assert_eq!(built(&mut checker, specs, plain), expected);
1290 }
1291 assert_eq!(built(&mut checker, float80, plain), "long double");
1292 assert!(messages(&checker).is_empty());
1293 }
1294
1295 #[test]
1296 fn a_floating_type_the_target_does_not_have_is_refused_rather_than_given_another_one() {
1297 let mut fixture = Fixture::for_target("aarch64-apple-darwin");
1302 let float128x = fixture.keywords(&[BuiltinSet::FLOAT128X]);
1303 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1304 let plain = fixture.declarator(Some("x"), &[]);
1305
1306 let mut checker = fixture.checker();
1307 assert_eq!(built(&mut checker, float128x, plain), "double");
1310 assert_eq!(built(&mut checker, float80, plain), "double");
1311 assert_eq!(
1312 messages(&checker),
1313 [
1314 "'_Float128x' is not supported on this target",
1315 "'__float80' is not supported on this target",
1316 ]
1317 );
1318 }
1319
1320 #[test]
1321 fn a_decimal_floating_type_is_recognised_and_says_it_is_not_written_yet() {
1322 let mut fixture = Fixture::new();
1326 let specs = fixture.keywords(&[BuiltinSet::DECIMAL64]);
1327 let plain = fixture.declarator(Some("x"), &[]);
1328
1329 let mut checker = fixture.checker();
1330 assert_eq!(built(&mut checker, specs, plain), "double");
1331 assert_eq!(message(&checker), "the type `_Decimal64` is not supported yet");
1332 }
1333
1334 #[test]
1335 fn keywords_that_name_no_type_between_them_are_one_message_and_not_one_per_keyword() {
1336 let mut fixture = Fixture::new();
1337 let specs = fixture.keywords(&[BuiltinSet::SHORT, BuiltinSet::DOUBLE]);
1340 let plain = fixture.declarator(Some("x"), &[]);
1341
1342 let mut checker = fixture.checker();
1343 let ty = checker.declared_type(specs, plain);
1344 assert_eq!(spelled(&checker, ty), "int");
1345 assert_eq!(message(&checker), "two or more data types in declaration specifiers");
1346 }
1347
1348 #[test]
1349 fn a_declaration_with_no_type_at_all_is_an_int_and_a_warning_that_says_whose() {
1350 let mut fixture = Fixture::new();
1351 let specs = fixture.specs(TypeSpec::None, Quals::CONST);
1354 let again = fixture.specs(TypeSpec::None, Quals::NONE);
1355 let named = fixture.declarator(Some("x"), &[]);
1356 let abstracted = fixture.declarator(None, &[]);
1357
1358 let mut checker = fixture.checker();
1359 let ty = checker.declared_type(specs, named);
1360 assert_eq!(spelled(&checker, ty), "const int");
1361 checker.declared_type(again, abstracted);
1362 assert_eq!(
1363 messages(&checker),
1364 ["type defaults to 'int' in declaration of 'x'", "type defaults to 'int'"]
1365 );
1366 }
1367
1368 #[test]
1369 fn a_declarator_is_folded_from_the_far_end_so_the_step_nearest_the_name_wins() {
1370 let mut fixture = Fixture::new();
1371 let specs = fixture.int_specs();
1372 let char_specs = fixture.keywords(&[BuiltinSet::CHAR]);
1373 let parameter = fixture.declarator(None, &[]);
1374 let params = fixture.ast.add_param_list(&[ast::Param {
1375 specs: Some(char_specs),
1376 declarator: parameter,
1377 attrs: rucc_ast::AttrList::EMPTY,
1378 span: Span::DUMMY,
1379 }]);
1380 let three = fixed(&mut fixture, 3);
1383 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1384 let f = fixture.declarator(Some("f"), &[three, pointer(), call]);
1385
1386 let mut checker = fixture.checker();
1387 let ty = checker.declared_type(specs, f);
1388 assert_eq!(spelled(&checker, ty), "int (*[3])(char)");
1389 assert!(messages(&checker).is_empty());
1390 }
1391
1392 #[test]
1393 fn the_qualifiers_of_a_pointer_are_the_pointers_and_not_the_pointees() {
1394 let mut fixture = Fixture::new();
1395 let konst = fixture.specs(
1396 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
1397 Quals::CONST,
1398 );
1399 let plain = fixture.int_specs();
1400 let to_const = fixture.declarator(Some("p"), &[pointer()]);
1402 let const_pointer = fixture.declarator(
1404 Some("p"),
1405 &[Derived::Pointer { quals: Quals::CONST, attrs: rucc_ast::AttrList::EMPTY }],
1406 );
1407
1408 let mut checker = fixture.checker();
1409 assert_eq!(built(&mut checker, konst, to_const), "const int *");
1410 assert_eq!(built(&mut checker, plain, const_pointer), "int *const");
1411 assert!(messages(&checker).is_empty());
1412 }
1413
1414 #[test]
1415 fn restrict_is_only_for_a_pointer_and_says_so_where_it_is_not() {
1416 let mut fixture = Fixture::new();
1417 let specs = fixture.specs(TypeSpec::None, Quals::RESTRICT);
1418 let plain = fixture.declarator(Some("x"), &[]);
1419 let restricted =
1420 Derived::Pointer { quals: Quals::RESTRICT, attrs: rucc_ast::AttrList::EMPTY };
1421 let int_specs = fixture.int_specs();
1422 let p = fixture.declarator(Some("p"), &[restricted]);
1423
1424 let mut checker = fixture.checker();
1425 assert_eq!(built(&mut checker, int_specs, p), "int *restrict");
1426 checker.declared_type(specs, plain);
1427 assert!(
1428 messages(&checker).contains(&"invalid use of 'restrict'".to_string()),
1429 "got {:?}",
1430 messages(&checker)
1431 );
1432 }
1433
1434 #[test]
1435 fn an_array_of_something_there_can_be_no_array_of_says_which_it_was() {
1436 let mut fixture = Fixture::new();
1437 let void = fixture.keywords(&[BuiltinSet::VOID]);
1438 let int = fixture.int_specs();
1439 let three = fixed(&mut fixture, 3);
1440 let params = fixture.ast.add_param_list(&[]);
1441 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1442
1443 let voids = fixture.declarator(Some("a"), &[three]);
1444 let functions = fixture.declarator(Some("a"), &[three, call]);
1445 let anonymous = fixture.declarator(None, &[three]);
1446
1447 let mut checker = fixture.checker();
1448 checker.declared_type(void, voids);
1449 checker.declared_type(int, functions);
1450 checker.declared_type(void, anonymous);
1451 assert_eq!(
1452 messages(&checker),
1453 [
1454 "declaration of 'a' as array of voids",
1455 "declaration of 'a' as array of functions",
1456 "declaration of type name as array of voids",
1457 ]
1458 );
1459 }
1460
1461 #[test]
1462 fn an_array_of_a_tag_that_has_no_definition_yet_names_the_type_it_cannot_size() {
1463 let mut fixture = Fixture::new();
1464 let tag = fixture.name("S");
1465 let specs = fixture.specs(
1466 TypeSpec::Record {
1467 kind: ast::RecordKind::Struct,
1468 tag: Some(tag),
1469 fields: None,
1470 attrs: rucc_ast::AttrList::EMPTY,
1471 },
1472 Quals::NONE,
1473 );
1474 let three = fixed(&mut fixture, 3);
1475 let array = fixture.declarator(Some("a"), &[three]);
1476 let star = fixture.declarator(Some("p"), &[pointer()]);
1477
1478 let mut checker = fixture.checker();
1479 let pointer_ty = checker.declared_type(specs, star);
1482 assert_eq!(spelled(&checker, pointer_ty), "struct S *");
1483 checker.declared_type(specs, array);
1484 assert_eq!(message(&checker), "array type has incomplete element type 'struct S'");
1485 }
1486
1487 #[test]
1488 fn an_array_bound_is_folded_and_a_negative_one_is_refused() {
1489 let mut fixture = Fixture::new();
1490 let specs = fixture.int_specs();
1491 let zero = fixed(&mut fixture, 0);
1492 let four = fixed(&mut fixture, 4);
1493 let negative = {
1494 let one = fixture.int(1);
1495 let size = fixture
1496 .ast
1497 .expr(ast::Expr::Unary { op: rucc_ast::UnaryOp::Minus, operand: one }, Span::DUMMY);
1498 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1499 };
1500 let sized = fixture.declarator(Some("a"), &[four]);
1501 let empty = fixture.declarator(Some("a"), &[zero]);
1504 let unspecified = fixture.declarator(
1505 Some("a"),
1506 &[Derived::Array {
1507 size: ArraySize::Unspecified,
1508 quals: Quals::NONE,
1509 has_static: false,
1510 }],
1511 );
1512 let backwards = fixture.declarator(Some("a"), &[negative]);
1513
1514 let mut checker = fixture.checker();
1515 assert_eq!(built(&mut checker, specs, sized), "int[4]");
1516 assert_eq!(built(&mut checker, specs, empty), "int[0]");
1517 assert_eq!(built(&mut checker, specs, unspecified), "int[]");
1518 assert!(messages(&checker).is_empty());
1519
1520 checker.declared_type(specs, backwards);
1521 assert_eq!(message(&checker), "size of array 'a' is negative");
1522 }
1523
1524 #[test]
1525 fn an_array_too_large_to_be_an_object_is_measured_in_its_elements() {
1526 let mut fixture = Fixture::new();
1527 let specs = fixture.int_specs();
1528 let count = u128::from(MAX_OBJECT_SIZE / 4 + 1);
1531 let huge = fixed(&mut fixture, count);
1532 let a = fixture.declarator(Some("a"), &[huge]);
1533
1534 let mut checker = fixture.checker();
1535 checker.declared_type(specs, a);
1536 assert_eq!(
1537 message(&checker),
1538 "size of array 'a' exceeds maximum object size '9223372036854775807'"
1539 );
1540 }
1541
1542 #[test]
1543 fn a_bound_that_is_not_a_constant_is_a_variable_length_array_where_there_is_a_run_time() {
1544 let mut fixture = Fixture::new();
1545 let specs = fixture.int_specs();
1546 let n = fixture.use_name("n");
1547 let variable =
1548 Derived::Array { size: ArraySize::Expr(n), quals: Quals::NONE, has_static: false };
1549 let a = fixture.declarator(Some("a"), &[variable]);
1550 let name = fixture.name("n");
1551
1552 let mut checker = fixture.checker();
1553 let int = checker.int();
1554 checker.declare_object(name, int, Span::DUMMY);
1555 checker.declared_type(specs, a);
1558 assert_eq!(message(&checker), "variably modified 'a' at file scope");
1559
1560 checker.scopes.push();
1561 let ty = checker.declared_type(specs, a);
1562 assert_eq!(spelled(&checker, ty), "int[*]");
1563 let again = checker.declared_type(specs, a);
1566 assert_ne!(ty, again);
1567 assert_eq!(
1568 checker.tast.vla_size(vla_id(&checker, ty)),
1569 checker.tast.vla_size(vla_id(&checker, ty))
1570 );
1571 }
1572
1573 fn vla_id(checker: &Checker<'_>, ty: TypeId) -> rucc_types::VlaId {
1575 match checker.types.kind(checker.types.canonical(ty)) {
1576 TypeKind::Array { len: ArrayLen::Variable(id), .. } => id,
1577 other => panic!("expected a variable length array, got {other:?}"),
1578 }
1579 }
1580
1581 #[test]
1582 fn a_star_bound_is_only_a_type_inside_a_prototype() {
1583 let mut fixture = Fixture::new();
1584 let specs = fixture.int_specs();
1585 let star = Derived::Array { size: ArraySize::Star, quals: Quals::NONE, has_static: false };
1586 let parameter = fixture.declarator(Some("a"), &[star]);
1587 let params = fixture.ast.add_param_list(&[ast::Param {
1588 specs: Some(specs),
1589 declarator: parameter,
1590 attrs: rucc_ast::AttrList::EMPTY,
1591 span: Span::DUMMY,
1592 }]);
1593 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1594 let f = fixture.declarator(Some("f"), &[call]);
1595
1596 let mut checker = fixture.checker();
1597 let ty = checker.declared_type(specs, f);
1600 assert_eq!(spelled(&checker, ty), "int(int *)");
1601 assert!(messages(&checker).is_empty());
1602
1603 checker.declared_type(specs, parameter);
1604 assert_eq!(message(&checker), "'[*]' not allowed in other than function prototype scope");
1605 }
1606
1607 #[test]
1608 fn a_deduced_type_on_a_parameter_names_nothing_and_says_where_it_was_written() {
1609 let mut fixture = Fixture::new();
1610 let specs = fixture.int_specs();
1613 let deduced = fixture.specs(TypeSpec::Auto(ast::Deduction::Auto), Quals::NONE);
1614 let parameter = fixture.declarator(Some("p"), &[]);
1615 let params = fixture.ast.add_param_list(&[ast::Param {
1616 specs: Some(deduced),
1617 declarator: parameter,
1618 attrs: rucc_ast::AttrList::EMPTY,
1619 span: Span::DUMMY,
1620 }]);
1621 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1622 let f = fixture.declarator(Some("f"), &[call]);
1623
1624 let mut checker = fixture.checker();
1625 let ty = checker.declared_type(specs, f);
1626 assert_eq!(spelled(&checker, ty), "int(int)");
1627 assert_eq!(message(&checker), "'auto' not allowed in function prototype");
1628 }
1629
1630 #[test]
1631 fn the_qualifiers_inside_a_parameters_brackets_are_the_object_s_and_not_the_type_s() {
1632 let mut fixture = Fixture::new();
1633 let specs = fixture.int_specs();
1634 let three = fixture.int(3);
1635 let qualified =
1636 Derived::Array { size: ArraySize::Expr(three), quals: Quals::CONST, has_static: true };
1637 let parameter = fixture.declarator(Some("a"), &[qualified]);
1638 let params = fixture.ast.add_param_list(&[ast::Param {
1639 specs: Some(specs),
1640 declarator: parameter,
1641 attrs: rucc_ast::AttrList::EMPTY,
1642 span: Span::DUMMY,
1643 }]);
1644 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1645 let f = fixture.declarator(Some("f"), &[call]);
1646
1647 let mut checker = fixture.checker();
1648 let ty = checker.declared_type(specs, f);
1654 assert_eq!(spelled(&checker, ty), "int(int *)");
1655 assert!(messages(&checker).is_empty());
1656
1657 checker.declared_type(specs, parameter);
1659 assert_eq!(
1660 message(&checker),
1661 "static or type qualifiers in non-parameter array declarator"
1662 );
1663 }
1664
1665 #[test]
1666 fn a_function_cannot_return_a_function_or_an_array_and_the_message_names_which() {
1667 let mut fixture = Fixture::new();
1668 let specs = fixture.int_specs();
1669 let params = fixture.ast.add_param_list(&[]);
1670 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1671 let three = fixed(&mut fixture, 3);
1672
1673 let returns_function = fixture.declarator(Some("f"), &[call, call]);
1674 let returns_array = fixture.declarator(Some("f"), &[call, three]);
1675 let anonymous = fixture.declarator(None, &[call, three]);
1676
1677 let mut checker = fixture.checker();
1678 checker.declared_type(specs, returns_function);
1679 checker.declared_type(specs, returns_array);
1680 checker.declared_type(specs, anonymous);
1681 assert_eq!(
1682 messages(&checker),
1683 [
1684 "'f' declared as function returning a function",
1685 "'f' declared as function returning an array",
1686 "type name declared as function returning an array",
1687 ]
1688 );
1689 }
1690
1691 #[test]
1692 fn an_empty_parameter_list_says_nothing_before_c23_and_says_none_from_it() {
1693 let mut fixture = Fixture::new();
1694 let specs = fixture.int_specs();
1695 let params = fixture.ast.add_param_list(&[]);
1696 let empty = Derived::Function { params, variadic: false, kind: ParamKind::Empty };
1697 let f = fixture.declarator(Some("f"), &[empty]);
1698
1699 let mut checker = fixture.checker();
1700 assert_eq!(built(&mut checker, specs, f), "int(void)");
1701
1702 let mut old = fixture.checker();
1703 old.cx.std = Std::C17;
1704 assert_eq!(built(&mut old, specs, f), "int()");
1705 assert!(messages(&old).is_empty());
1706 }
1707
1708 #[test]
1709 fn a_parameter_of_type_void_is_only_a_parameter_list_when_it_is_the_whole_of_one() {
1710 let mut fixture = Fixture::new();
1711 let int = fixture.int_specs();
1712 let void = fixture.keywords(&[BuiltinSet::VOID]);
1713 let named = fixture.declarator(Some("v"), &[]);
1714 let unnamed = fixture.declarator(None, &[]);
1715 let param = |declarator| ast::Param {
1716 specs: Some(void),
1717 declarator,
1718 attrs: rucc_ast::AttrList::EMPTY,
1719 span: Span::DUMMY,
1720 };
1721 let params = fixture.ast.add_param_list(&[param(named), param(unnamed)]);
1722 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1723 let f = fixture.declarator(Some("f"), &[call]);
1724
1725 let mut checker = fixture.checker();
1726 checker.declared_type(int, f);
1727 assert_eq!(
1728 messages(&checker),
1729 ["parameter 1 ('v') has void type", "'void' must be the only parameter"]
1730 );
1731 }
1732
1733 #[test]
1734 fn a_parameter_is_in_scope_for_the_parameters_after_it_and_gone_after_the_prototype() {
1735 let mut fixture = Fixture::new();
1736 let specs = fixture.int_specs();
1737 let n = fixture.declarator(Some("n"), &[]);
1738 let bound = fixture.use_name("n");
1739 let a = fixture.declarator(
1740 Some("a"),
1741 &[Derived::Array {
1742 size: ArraySize::Expr(bound),
1743 quals: Quals::NONE,
1744 has_static: false,
1745 }],
1746 );
1747 let param = |declarator| ast::Param {
1748 specs: Some(specs),
1749 declarator,
1750 attrs: rucc_ast::AttrList::EMPTY,
1751 span: Span::DUMMY,
1752 };
1753 let params = fixture.ast.add_param_list(&[param(n), param(a)]);
1754 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1755 let f = fixture.declarator(Some("f"), &[call]);
1756 let name = fixture.name("n");
1757
1758 let mut checker = fixture.checker();
1759 let ty = checker.declared_type(specs, f);
1762 assert_eq!(spelled(&checker, ty), "int(int, int *)");
1763 assert!(messages(&checker).is_empty());
1764 assert!(checker.scopes.lookup(name).is_none());
1765 }
1766
1767 #[test]
1768 fn a_parameter_declared_twice_in_one_prototype_is_reported_once() {
1769 let mut fixture = Fixture::new();
1770 let specs = fixture.int_specs();
1771 let a = fixture.declarator(Some("a"), &[]);
1772 let param = ast::Param {
1773 specs: Some(specs),
1774 declarator: a,
1775 attrs: rucc_ast::AttrList::EMPTY,
1776 span: Span::DUMMY,
1777 };
1778 let params = fixture.ast.add_param_list(&[param, param]);
1779 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1780 let f = fixture.declarator(Some("f"), &[call]);
1781
1782 let mut checker = fixture.checker();
1783 checker.declared_type(specs, f);
1784 assert_eq!(message(&checker), "redefinition of parameter 'a'");
1785 }
1786
1787 #[test]
1788 fn a_tag_names_the_same_type_every_time_and_one_kind_of_thing_only() {
1789 let mut fixture = Fixture::new();
1790 let tag = fixture.name("S");
1791 let record = |kind| TypeSpec::Record {
1792 kind,
1793 tag: Some(tag),
1794 fields: None,
1795 attrs: rucc_ast::AttrList::EMPTY,
1796 };
1797 let structure = fixture.specs(record(ast::RecordKind::Struct), Quals::NONE);
1798 let onion = fixture.specs(record(ast::RecordKind::Union), Quals::NONE);
1799 let plain = fixture.declarator(None, &[]);
1800
1801 let mut checker = fixture.checker();
1802 let first = checker.declared_type(structure, plain);
1803 let second = checker.declared_type(structure, plain);
1804 assert_eq!(first, second);
1805 assert!(messages(&checker).is_empty());
1806
1807 let wrong = checker.declared_type(onion, plain);
1808 assert_eq!(message(&checker), "'S' defined as wrong kind of tag");
1809 assert_ne!(wrong, first);
1812 assert_eq!(checker.declared_type(structure, plain), first);
1813 }
1814
1815 #[test]
1816 fn an_anonymous_tag_is_a_new_type_every_time_it_is_written() {
1817 let mut fixture = Fixture::new();
1818 let anonymous = |fixture: &mut Fixture| {
1819 fixture.specs(
1820 TypeSpec::Record {
1821 kind: ast::RecordKind::Struct,
1822 tag: None,
1823 fields: None,
1824 attrs: rucc_ast::AttrList::EMPTY,
1825 },
1826 Quals::NONE,
1827 )
1828 };
1829 let specs = anonymous(&mut fixture);
1830 let written_again = anonymous(&mut fixture);
1831 let plain = fixture.declarator(None, &[]);
1832
1833 let mut checker = fixture.checker();
1834 let first = checker.declared_type(specs, plain);
1835 let second = checker.declared_type(written_again, plain);
1836 assert_ne!(first, second);
1837 assert_eq!(checker.declared_type(specs, plain), first);
1840 }
1841
1842 #[test]
1843 fn an_enumeration_with_the_underlying_type_written_is_complete_from_there() {
1844 let mut fixture = Fixture::new();
1845 let long = fixture.keywords(&[BuiltinSet::LONG]);
1846 let long_name = fixture.type_name(long, &[]);
1847 let tag = fixture.name("E");
1848 let fixed_enum = fixture.specs(
1849 TypeSpec::Enum {
1850 tag: Some(tag),
1851 enumerators: None,
1852 underlying: Some(long_name),
1853 attrs: rucc_ast::AttrList::EMPTY,
1854 },
1855 Quals::NONE,
1856 );
1857 let plain = fixture.declarator(None, &[]);
1858
1859 let mut checker = fixture.checker();
1860 let ty = checker.declared_type(fixed_enum, plain);
1861 assert_eq!(spelled(&checker, ty), "enum E");
1862 assert!(is_complete(&checker.types, ty));
1863 assert!(messages(&checker).is_empty());
1864 }
1865
1866 #[test]
1867 fn an_enumeration_cannot_be_kept_in_something_that_is_not_an_integer_type() {
1868 let mut fixture = Fixture::new();
1869 let double = fixture.keywords(&[BuiltinSet::DOUBLE]);
1870 let double_name = fixture.type_name(double, &[]);
1871 let specs = fixture.specs(
1872 TypeSpec::Enum {
1873 tag: None,
1874 enumerators: None,
1875 underlying: Some(double_name),
1876 attrs: rucc_ast::AttrList::EMPTY,
1877 },
1878 Quals::NONE,
1879 );
1880 let plain = fixture.declarator(None, &[]);
1881
1882 let mut checker = fixture.checker();
1883 checker.declared_type(specs, plain);
1884 assert_eq!(message(&checker), "invalid 'enum' underlying type");
1885 }
1886
1887 #[test]
1888 fn atomic_is_a_type_and_not_a_qualifier_and_two_things_cannot_be_one() {
1889 let mut fixture = Fixture::new();
1890 let int = fixture.int_specs();
1891 let konst = fixture.specs(
1892 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
1893 Quals::CONST,
1894 );
1895 let plain_name = fixture.type_name(int, &[]);
1896 let three = fixed(&mut fixture, 3);
1897 let array_name = fixture.type_name(int, &[three]);
1898 let params = fixture.ast.add_param_list(&[]);
1899 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1900 let function_name = fixture.type_name(int, &[call]);
1901 let const_name = fixture.type_name(konst, &[]);
1902
1903 let atomic = |fixture: &mut Fixture, name| {
1904 let specs = fixture.specs(TypeSpec::Atomic(name), Quals::NONE);
1905 let declarator = fixture.declarator(None, &[]);
1906 (specs, declarator)
1907 };
1908 let (plain, hole) = atomic(&mut fixture, plain_name);
1909 let (array, _) = atomic(&mut fixture, array_name);
1910 let (function, _) = atomic(&mut fixture, function_name);
1911 let (qualified, _) = atomic(&mut fixture, const_name);
1912
1913 let mut checker = fixture.checker();
1914 assert_eq!(built(&mut checker, plain, hole), "_Atomic(int)");
1915 assert!(messages(&checker).is_empty());
1916
1917 checker.declared_type(array, hole);
1918 checker.declared_type(function, hole);
1919 checker.declared_type(qualified, hole);
1920 assert_eq!(
1921 messages(&checker),
1922 [
1923 "'_Atomic'-qualified array type",
1924 "'_Atomic'-qualified function type",
1925 "'_Atomic' applied to a qualified type",
1926 ]
1927 );
1928 }
1929
1930 #[test]
1931 fn a_bit_int_is_as_wide_as_it_says_within_the_range_there_is() {
1932 let mut fixture = Fixture::new();
1933 let widths = [37, 1, 200, 0];
1934 let specs: Vec<_> = widths
1935 .iter()
1936 .map(|&width| {
1937 let expr = fixture.int(width);
1938 fixture.specs(bit_int(expr, false), Quals::NONE)
1939 })
1940 .collect();
1941 let plain = fixture.declarator(None, &[]);
1942
1943 let mut checker = fixture.checker();
1944 assert_eq!(built(&mut checker, specs[0], plain), "_BitInt(37)");
1945 assert!(messages(&checker).is_empty());
1946
1947 checker.declared_type(specs[1], plain);
1948 checker.declared_type(specs[2], plain);
1949 checker.declared_type(specs[3], plain);
1950 assert_eq!(
1951 messages(&checker),
1952 [
1953 "'signed _BitInt' argument must be at least 2",
1954 "'_BitInt' argument '200' is larger than 'BITINT_MAXWIDTH' '128'",
1955 "'_BitInt' argument '0' is not a positive integer constant expression",
1956 ]
1957 );
1958 }
1959
1960 #[test]
1961 fn an_unsigned_bit_int_holds_one_bit_where_a_signed_one_cannot() {
1962 let mut fixture = Fixture::new();
1963 let one = fixture.int(1);
1964 let unsigned = fixture.specs(bit_int(one, true), Quals::NONE);
1965 let eight = fixture.int(8);
1966 let wide = fixture.specs(bit_int(eight, true), Quals::NONE);
1967 let plain = fixture.declarator(None, &[]);
1968
1969 let mut checker = fixture.checker();
1970 assert_eq!(built(&mut checker, unsigned, plain), "unsigned _BitInt(1)");
1971 assert_eq!(built(&mut checker, wide, plain), "unsigned _BitInt(8)");
1972 assert!(messages(&checker).is_empty());
1973 }
1974
1975 #[test]
1976 fn a_bit_int_next_to_anything_but_a_sign_names_no_type() {
1977 let mut fixture = Fixture::new();
1978 let width = fixture.int(8);
1979 let mut both = Builtin::NONE.add(BuiltinSet::LONG).expect("`long` rejected");
1980 both = both.add_bit_int(width).expect("`_BitInt` rejected");
1981 let specs = fixture.specs(TypeSpec::Builtin(both), Quals::NONE);
1982 let plain = fixture.declarator(None, &[]);
1983
1984 let mut checker = fixture.checker();
1985 checker.declared_type(specs, plain);
1986 assert_eq!(messages(&checker), ["two or more data types in declaration specifiers"]);
1987 }
1988
1989 #[test]
1990 fn a_typedef_name_is_the_type_it_was_declared_for_and_keeps_its_own_spelling() {
1991 let mut fixture = Fixture::new();
1992 let word = fixture.name("word");
1993 let specs = fixture.specs(TypeSpec::Typedef(word), Quals::CONST);
1994 let p = fixture.declarator(Some("p"), &[pointer()]);
1995
1996 let mut checker = fixture.checker();
1997 let long = checker.types.int(IntKind::Long);
1998 let alias = checker.types.typedef(word, long);
1999 checker.declare_typedef(word, alias);
2000
2001 let ty = checker.declared_type(specs, p);
2002 assert_eq!(spelled(&checker, ty), "const word *");
2003 assert!(messages(&checker).is_empty());
2004 }
2005
2006 #[test]
2007 fn typeof_takes_the_type_of_an_expression_it_does_not_evaluate() {
2008 let mut fixture = Fixture::new();
2009 let x = fixture.use_name("x");
2010 let plain = fixture
2011 .specs(TypeSpec::Typeof { unqual: false, operand: TypeofArg::Expr(x) }, Quals::NONE);
2012 let bare = fixture
2013 .specs(TypeSpec::Typeof { unqual: true, operand: TypeofArg::Expr(x) }, Quals::NONE);
2014 let hole = fixture.declarator(None, &[]);
2015 let name = fixture.name("x");
2016
2017 let mut checker = fixture.checker();
2018 let int = checker.int();
2019 let konst = checker.types.qualified(int, Qualifiers::CONST);
2020 checker.declare_object(name, konst, Span::DUMMY);
2021
2022 assert_eq!(built(&mut checker, plain, hole), "const int");
2023 assert_eq!(built(&mut checker, bare, hole), "int");
2025 assert!(messages(&checker).is_empty());
2026 }
2027}