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};
41use rucc_diag::{Diagnostic, Span};
42use rucc_session::Std;
43use rucc_target::TargetInfo;
44use rucc_types::{
45 ArrayLen, FloatKind, FunctionType, IntKind, Qualifiers, RecordKind, TypeId, adjust_parameter,
46 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}
98
99#[derive(Debug, Clone, Copy)]
106struct Subject {
107 name: Option<Symbol>,
109 span: Span,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115enum TagUse {
116 Known(TypeId),
118 New,
120 Anonymous,
122 Wrong,
124}
125
126#[derive(Debug, Clone, Copy, Default)]
128pub(in crate::check) struct Place {
129 parameter: bool,
132 member: bool,
135 prototype: bool,
138}
139
140pub(in crate::check) const MEMBER: Place =
142 Place { parameter: false, member: true, prototype: false };
143
144impl Checker<'_> {
145 pub fn type_name(&mut self, id: ast::TypeNameId) -> TypeId {
147 let name = self.ast[id];
148 self.declared_type(name.specs, name.declarator)
149 }
150
151 pub fn declared_type(
157 &mut self,
158 specs: ast::DeclSpecsId,
159 declarator: ast::DeclaratorId,
160 ) -> TypeId {
161 self.build_type(specs, declarator, Place::default())
162 }
163
164 pub(in crate::check) fn declared_specs(&mut self, specs: ast::DeclSpecsId) -> TypeId {
169 let span = self.ast[specs].span;
170 self.specified_type(specs, Subject { name: None, span }, Place::default())
171 }
172
173 pub fn declare_typedef(&mut self, name: Symbol, ty: TypeId) {
179 self.scopes.declare(name, Binding::Typedef(ty));
180 }
181
182 fn build_type(
184 &mut self,
185 specs: ast::DeclSpecsId,
186 declarator: ast::DeclaratorId,
187 place: Place,
188 ) -> TypeId {
189 let node = self.ast[declarator];
190 let subject = Subject {
191 name: node.name,
192 span: if node.name.is_some() { node.name_span } else { node.span },
193 };
194 let base = self.specified_type(specs, subject, place);
195 self.derive(base, declarator, subject, place)
196 }
197
198 fn specified_type(&mut self, id: ast::DeclSpecsId, subject: Subject, place: Place) -> TypeId {
205 if let Some(&ty) = self.built.specified.get(&id) {
206 return ty;
207 }
208 let specs = self.ast[id];
209 let base = self.type_spec(specs.ty, specs.span, subject, place);
210 let ty = self.qualify(base, specs.quals, specs.span);
211 self.built.specified.insert(id, ty);
212 ty
213 }
214
215 fn type_spec(&mut self, spec: TypeSpec, span: Span, subject: Subject, place: Place) -> TypeId {
217 match spec {
218 TypeSpec::None => {
219 let what = match subject.name {
220 Some(name) => format!("in declaration of '{}'", self.text(name)),
221 None => String::new(),
222 };
223 let message = format!("type defaults to 'int' {what}");
224 self.report(
225 Diagnostic::error(message.trim_end().to_string(), subject.span)
226 .with_code("E0526"),
227 );
228 self.int()
229 }
230 TypeSpec::Builtin(builtin) => match builtin.resolve() {
231 Some(basic) => self.basic_type(basic.scalar, basic.complexity, span),
232 None => {
233 self.report(
234 Diagnostic::error(
235 "two or more data types in declaration specifiers".to_string(),
236 span,
237 )
238 .with_code("E0525"),
239 );
240 self.int()
241 }
242 },
243 TypeSpec::Record { kind, tag, fields, .. } => self.record_spec(kind, tag, fields, span),
244 TypeSpec::Enum { tag, enumerators, underlying, .. } => {
245 self.enum_spec(tag, enumerators, underlying, span)
246 }
247 TypeSpec::Typedef(name) => match self.scopes.lookup(name) {
248 Some(Binding::Typedef(ty)) => ty,
249 _ => {
254 let name = self.text(name).to_owned();
255 self.report(
256 Diagnostic::error(format!("unknown type name '{name}'"), span)
257 .with_code("E0546"),
258 );
259 self.int()
260 }
261 },
262 TypeSpec::Typeof { unqual, operand } => self.typeof_type(unqual, operand),
263 TypeSpec::Atomic(inner) => {
264 let inner = self.type_name(inner);
265 self.atomic_type(inner, span)
266 }
267 TypeSpec::Auto(which) => {
268 let spelled = which.spelling();
276 let place = if place.member { "struct member" } else { "function prototype" };
277 self.report(
278 Diagnostic::error(format!("'{spelled}' not allowed in {place}"), span)
279 .with_code("E0651"),
280 );
281 self.int()
282 }
283 }
284 }
285
286 fn basic_type(&mut self, scalar: Scalar, complexity: Complexity, span: Span) -> TypeId {
288 let kind = int_kind(scalar);
289 let float = float_kind(scalar, self.cx.target);
290
291 match complexity {
292 Complexity::Real => match (scalar, kind, float) {
293 (Scalar::Void, _, _) => self.types.void(),
294 (Scalar::Bool, _, _) => self.types.boolean(),
295 (Scalar::BitInt { width, unsigned }, _, _) => self.bit_int_type(width, !unsigned),
296 (_, Some(kind), _) => self.types.int(kind),
297 (_, _, Some(kind)) => self.types.float(kind),
298 (Scalar::Float128x | Scalar::Float80, _, _) => {
302 self.unavailable_type(spell_scalar(scalar), span);
303 self.types.float(FloatKind::Double)
304 }
305 _ => {
309 self.unsupported_type(&format!("the type `{}`", spell_scalar(scalar)), span);
310 self.types.float(FloatKind::Double)
311 }
312 },
313 Complexity::Complex => match float {
314 Some(kind) => self.types.complex(kind),
315 None => {
319 let what = format!("`_Complex` on the type `{}`", spell_scalar(scalar));
320 self.unsupported_type(&what, span);
321 self.types.complex(FloatKind::Double)
322 }
323 },
324 Complexity::Imaginary => {
326 self.unsupported_type("`_Imaginary`", span);
327 self.types.complex(float.unwrap_or(FloatKind::Double))
328 }
329 }
330 }
331
332 fn typeof_type(&mut self, unqual: bool, operand: TypeofArg) -> TypeId {
334 let ty = match operand {
338 TypeofArg::Expr(expr) => {
339 let node = self.expr(expr);
340 self.tast[node].ty
341 }
342 TypeofArg::Type(name) => self.type_name(name),
343 };
344 if !unqual {
345 return ty;
346 }
347 let bare = match self.types.kind(self.types.canonical(ty)) {
350 rucc_types::TypeKind::Atomic(inner) => inner,
351 _ => ty,
352 };
353 self.types.unqualified(bare)
354 }
355
356 fn bit_int_type(&mut self, width: ast::ExprId, signed: bool) -> TypeId {
362 let value = self.expr(width);
363 let span = self.tast.expr_span(value);
364 let Ok(bits) = self.eval_integer(value) else {
365 if !self.is_poisoned(value) {
368 self.report(
369 Diagnostic::error(
370 "'_BitInt' argument is not an integer constant expression".to_string(),
371 span,
372 )
373 .with_code("E0529"),
374 );
375 }
376 return self.int();
377 };
378 if bits <= 0 {
379 let message = format!(
380 "'_BitInt' argument '{bits}' is not a positive integer constant expression"
381 );
382 self.report(Diagnostic::error(message, span).with_code("E0529"));
383 return self.int();
384 }
385 if signed && bits < 2 {
386 let message = "'signed _BitInt' argument must be at least 2".to_string();
387 self.report(Diagnostic::error(message, span).with_code("E0529"));
388 return self.int();
389 }
390 if bits > i128::from(MAX_BIT_INT_WIDTH) {
391 let message = format!(
392 "'_BitInt' argument '{bits}' is larger than 'BITINT_MAXWIDTH' '{MAX_BIT_INT_WIDTH}'"
393 );
394 self.report(Diagnostic::error(message, span).with_code("E0529"));
395 return self.int();
396 }
397 let bits = u32::try_from(bits).unwrap_or(MAX_BIT_INT_WIDTH);
398 self.types.bit_int(signed, bits)
399 }
400
401 fn atomic_type(&mut self, inner: TypeId, span: Span) -> TypeId {
403 let canonical = self.types.canonical(inner);
404 let what = if rucc_types::is_array(&self.types, canonical) {
405 "'_Atomic'-qualified array type"
406 } else if is_function(&self.types, canonical) {
407 "'_Atomic'-qualified function type"
408 } else if !self.types.quals(inner).is_none() {
409 "'_Atomic' applied to a qualified type"
410 } else {
411 return self.types.atomic(inner);
412 };
413 self.report(Diagnostic::error(what.to_string(), span).with_code("E0527"));
414 inner
415 }
416
417 fn record_spec(
419 &mut self,
420 kind: ast::RecordKind,
421 tag: Option<Symbol>,
422 fields: Option<ast::MemberList>,
423 span: Span,
424 ) -> TypeId {
425 let (kind, tag_kind) = match kind {
426 ast::RecordKind::Struct => (RecordKind::Struct, TagKind::Struct),
427 ast::RecordKind::Union => (RecordKind::Union, TagKind::Union),
428 };
429 let Some(members) = fields else {
430 return match self.tag_use(tag, tag_kind, span) {
431 TagUse::Known(ty) => ty,
432 found => {
433 let id = self.types.declare_record(kind, tag);
434 let ty = self.types.record(id);
435 self.bind_tag(found, tag, tag_kind, ty);
436 ty
437 }
438 };
439 };
440 let (id, ty) = self.record_defined(kind, tag, tag_kind, span);
444 self.built.defined.insert(ty);
445 self.record_body(id, kind, members, span);
446 ty
447 }
448
449 fn enum_spec(
451 &mut self,
452 tag: Option<Symbol>,
453 enumerators: Option<ast::EnumeratorList>,
454 underlying: Option<ast::TypeNameId>,
455 span: Span,
456 ) -> TypeId {
457 let underlying = underlying.map(|name| {
458 let ty = self.type_name(name);
459 if is_integer(&self.types, self.types.canonical(ty)) {
460 return ty;
461 }
462 self.report(
463 Diagnostic::error("invalid 'enum' underlying type".to_string(), span)
464 .with_code("E0530"),
465 );
466 self.int()
467 });
468
469 let Some(list) = enumerators else {
470 return match self.tag_use(tag, TagKind::Enum, span) {
471 TagUse::Known(ty) => ty,
472 found => {
473 let id = self.types.declare_enum(tag);
474 if let Some(underlying) = underlying {
478 self.types.complete_enum(id, underlying, true);
479 }
480 let ty = self.types.enumeration(id);
481 self.bind_tag(found, tag, TagKind::Enum, ty);
482 ty
483 }
484 };
485 };
486 let (id, ty) = self.enum_defined(tag, span);
487 self.built.defined.insert(ty);
488 self.enum_body(id, list, underlying, span);
489 ty
490 }
491
492 fn tag_use(&mut self, tag: Option<Symbol>, kind: TagKind, span: Span) -> TagUse {
501 let Some(name) = tag else { return TagUse::Anonymous };
504 match self.scopes.tag(name) {
505 Some(found) if found.kind == kind => TagUse::Known(found.ty),
506 Some(_) => {
507 let spelled = self.text(name).to_owned();
508 self.report(
509 Diagnostic::error(format!("'{spelled}' defined as wrong kind of tag"), span)
510 .with_code("E0531"),
511 );
512 TagUse::Wrong
513 }
514 None => TagUse::New,
515 }
516 }
517
518 fn bind_tag(&mut self, found: TagUse, tag: Option<Symbol>, kind: TagKind, ty: TypeId) {
520 if !matches!(found, TagUse::New) {
524 return;
525 }
526 if let Some(name) = tag {
527 self.scopes.declare_tag(name, Tag { kind, ty });
528 }
529 }
530
531 pub(in crate::check) fn qualify(
533 &mut self,
534 ty: TypeId,
535 quals: ast::Quals,
536 span: Span,
537 ) -> TypeId {
538 let ty = if quals.has(ast::Quals::ATOMIC) { self.atomic_type(ty, span) } else { ty };
542 let mut result = Qualifiers::NONE;
543 if quals.has(ast::Quals::CONST) {
544 result = result.with(Qualifiers::CONST);
545 }
546 if quals.has(ast::Quals::VOLATILE) {
547 result = result.with(Qualifiers::VOLATILE);
548 }
549 if quals.has(ast::Quals::RESTRICT) {
550 if is_pointer(&self.types, self.types.canonical(ty)) {
551 result = result.with(Qualifiers::RESTRICT);
552 } else {
553 self.report(
554 Diagnostic::error("invalid use of 'restrict'".to_string(), span)
555 .with_code("E0528"),
556 );
557 }
558 }
559 self.types.qualified(ty, result)
560 }
561
562 fn derive(
564 &mut self,
565 base: TypeId,
566 declarator: ast::DeclaratorId,
567 subject: Subject,
568 place: Place,
569 ) -> TypeId {
570 let ast = self.ast;
573 let steps = &ast[ast[declarator].derived];
574 let mut ty = base;
575 for (index, step) in steps.iter().enumerate().rev() {
576 let nearest = index == 0;
579 ty = match *step {
580 Derived::Pointer { quals, .. } => {
581 let pointer = self.types.pointer(ty);
582 self.qualify(pointer, quals, subject.span)
583 }
584 Derived::Array { size, quals, has_static } => {
585 if (!quals.is_none() || has_static) && !(place.parameter && nearest) {
586 self.report(
587 Diagnostic::error(
588 "static or type qualifiers in non-parameter array declarator"
589 .to_string(),
590 subject.span,
591 )
592 .with_code("E0540"),
593 );
594 }
595 self.array_of(ty, size, subject, place)
596 }
597 Derived::Function { params, variadic, kind } => {
598 self.function_of(ty, params, variadic, kind, subject)
599 }
600 };
601 }
602 ty
603 }
604
605 fn array_of(
607 &mut self,
608 elem: TypeId,
609 size: ArraySize,
610 subject: Subject,
611 place: Place,
612 ) -> TypeId {
613 let canonical = self.types.canonical(elem);
614 let bad = if is_void(&self.types, canonical) {
615 Some(("as array of voids", "E0532"))
616 } else if is_function(&self.types, canonical) {
617 Some(("as array of functions", "E0533"))
618 } else {
619 None
620 };
621 if let Some((what, code)) = bad {
622 let who = self.declaration_of(subject);
623 self.report(Diagnostic::error(format!("{who} {what}"), subject.span).with_code(code));
624 return elem;
625 }
626 if !is_complete(&self.types, canonical) {
627 let spelled = self.spell(elem);
628 self.report(
629 Diagnostic::error(
630 format!("array type has incomplete element type '{spelled}'"),
631 subject.span,
632 )
633 .with_code("E0534"),
634 );
635 return elem;
636 }
637 let len = self.array_len(elem, size, subject, place);
638 self.types.array(elem, len)
639 }
640
641 fn array_len(
643 &mut self,
644 elem: TypeId,
645 size: ArraySize,
646 subject: Subject,
647 place: Place,
648 ) -> ArrayLen {
649 let expr = match size {
650 ArraySize::Unspecified => return ArrayLen::Unknown,
651 ArraySize::Star if place.prototype => return ArrayLen::Star,
652 ArraySize::Star => {
653 self.report(
654 Diagnostic::error(
655 "'[*]' not allowed in other than function prototype scope".to_string(),
656 subject.span,
657 )
658 .with_code("E0539"),
659 );
660 return ArrayLen::Unknown;
661 }
662 ArraySize::Expr(expr) => expr,
663 };
664
665 let value = self.expr(expr);
666 if self.is_poisoned(value) {
667 return ArrayLen::Unknown;
668 }
669 let span = self.tast.expr_span(value);
670 if !is_integer(&self.types, self.types.canonical(self.tast[value].ty)) {
671 self.report(
672 Diagnostic::error("size of array has non-integer type".to_string(), span)
673 .with_code("E0535"),
674 );
675 return ArrayLen::Unknown;
676 }
677
678 match self.eval_integer(value) {
679 Ok(count) if count < 0 => {
680 let who = self.array_named(subject);
681 self.report(
682 Diagnostic::error(format!("size of {who} is negative"), span)
683 .with_code("E0536"),
684 );
685 ArrayLen::Unknown
686 }
687 Ok(count) => {
688 let count = u64::try_from(count).unwrap_or(u64::MAX);
689 if self.too_large(elem, count) {
690 let who = self.array_named(subject);
691 let message =
692 format!("size of {who} exceeds maximum object size '{MAX_OBJECT_SIZE}'");
693 self.report(Diagnostic::error(message, span).with_code("E0537"));
694 return ArrayLen::Unknown;
695 }
696 ArrayLen::Fixed(count)
697 }
698 Err(failure) => {
701 if failure.poisoned {
702 return ArrayLen::Unknown;
703 }
704 if self.scopes.at_file_scope() {
705 let who = match subject.name {
706 Some(name) => format!("'{}'", self.text(name)),
707 None => "type name".to_string(),
708 };
709 self.report(
710 Diagnostic::error(
711 format!("variably modified {who} at file scope"),
712 subject.span,
713 )
714 .with_code("E0538"),
715 );
716 return ArrayLen::Unknown;
717 }
718 ArrayLen::Variable(self.tast.add_vla(value))
719 }
720 }
721 }
722
723 fn too_large(&self, elem: TypeId, count: u64) -> bool {
725 let Ok(elem) = layout(&self.types, elem, self.cx.target) else {
726 return false;
727 };
728 elem.size != 0 && count > MAX_OBJECT_SIZE / elem.size
730 }
731
732 fn function_of(
734 &mut self,
735 ret: TypeId,
736 params: ast::ParamList,
737 variadic: bool,
738 kind: ParamKind,
739 subject: Subject,
740 ) -> TypeId {
741 let canonical = self.types.canonical(ret);
742 let bad = if rucc_types::is_array(&self.types, canonical) {
743 Some(("an array", "E0542"))
744 } else if is_function(&self.types, canonical) {
745 Some(("a function", "E0541"))
746 } else {
747 None
748 };
749 let ret = match bad {
750 Some((what, code)) => {
751 let who = self.declared_as(subject);
752 self.report(
753 Diagnostic::error(format!("{who} as function returning {what}"), subject.span)
754 .with_code(code),
755 );
756 self.int()
757 }
758 None => ret,
759 };
760
761 let (params, prototyped) = match kind {
762 ParamKind::Void => (Vec::new(), true),
763 ParamKind::Empty => (Vec::new(), self.cx.std == Std::C23),
766 ParamKind::Identifiers => (Vec::new(), false),
770 ParamKind::Prototype => (self.prototype(params), true),
771 };
772 self.types.function(FunctionType { ret, params, variadic, prototyped })
773 }
774
775 fn prototype(&mut self, params: ast::ParamList) -> Vec<TypeId> {
777 let ast = self.ast;
778 let list = &ast[params];
779 self.scopes.push();
784 let mut types = Vec::with_capacity(list.len());
785 let mut declared = Vec::new();
786 for (index, param) in list.iter().enumerate() {
787 let ty = match param.specs {
788 Some(specs) => self.build_type(
789 specs,
790 param.declarator,
791 Place { parameter: true, member: false, prototype: true },
792 ),
793 None => self.int(),
796 };
797 let declarator = ast[param.declarator];
798 let span = if declarator.name.is_some() { declarator.name_span } else { param.span };
799 self.check_void_parameter(ty, declarator.name, index, span);
800
801 let adjusted = adjust_parameter(&mut self.types, ty);
802 let adjusted = match ast[declarator.derived].first() {
805 Some(&Derived::Array { quals, .. }) => self.qualify(adjusted, quals, span),
806 _ => adjusted,
807 };
808 types.push(adjusted);
809
810 if let Some(name) = declarator.name {
811 if self.scopes.lookup_here(name).is_some() {
812 let spelled = self.text(name).to_owned();
813 self.report(
814 Diagnostic::error(format!("redefinition of parameter '{spelled}'"), span)
815 .with_code("E0545"),
816 );
817 } else {
818 declared.push(self.declare_object(name, adjusted, span));
822 }
823 }
824 }
825 self.scopes.pop();
826 if let Some(first) = params.iter().next() {
827 self.built.params.insert(first, declared);
828 }
829 types
830 }
831
832 pub(in crate::check) fn prototype_params(&self, params: ast::ParamList) -> Vec<DeclId> {
836 params
837 .iter()
838 .next()
839 .and_then(|first| self.built.params.get(&first))
840 .cloned()
841 .unwrap_or_default()
842 }
843
844 fn check_void_parameter(&mut self, ty: TypeId, name: Option<Symbol>, index: usize, span: Span) {
847 if !is_void(&self.types, self.types.canonical(ty)) {
848 return;
849 }
850 let position = index + 1;
851 match name {
852 Some(name) => {
853 let spelled = self.text(name).to_owned();
854 self.report(
855 Diagnostic::warning(
856 format!("parameter {position} ('{spelled}') has void type"),
857 span,
858 )
859 .with_code("E0544"),
860 );
861 }
862 None => {
865 self.report(
866 Diagnostic::error("'void' must be the only parameter".to_string(), span)
867 .with_code("E0543"),
868 );
869 }
870 }
871 }
872
873 fn declaration_of(&self, subject: Subject) -> String {
875 match subject.name {
876 Some(name) => format!("declaration of '{}'", self.text(name)),
877 None => "declaration of type name".to_string(),
878 }
879 }
880
881 fn declared_as(&self, subject: Subject) -> String {
883 match subject.name {
884 Some(name) => format!("'{}' declared", self.text(name)),
885 None => "type name declared".to_string(),
886 }
887 }
888
889 fn array_named(&self, subject: Subject) -> String {
891 match subject.name {
892 Some(name) => format!("array '{}'", self.text(name)),
893 None => "unnamed array".to_string(),
894 }
895 }
896
897 fn unsupported_type(&mut self, what: &str, span: Span) {
899 self.report(
900 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
901 );
902 }
903
904 fn unavailable_type(&mut self, name: &str, span: Span) {
906 self.report(
907 Diagnostic::error(format!("'{name}' is not supported on this target"), span)
908 .with_code("E0589"),
909 );
910 }
911}
912
913fn int_kind(scalar: Scalar) -> Option<IntKind> {
915 let kind = match scalar {
918 Scalar::Char => IntKind::Char,
919 Scalar::SignedChar => IntKind::SChar,
920 Scalar::UnsignedChar => IntKind::UChar,
921 Scalar::Short => IntKind::Short,
922 Scalar::UnsignedShort => IntKind::UShort,
923 Scalar::Int => IntKind::Int,
924 Scalar::UnsignedInt => IntKind::UInt,
925 Scalar::Long => IntKind::Long,
926 Scalar::UnsignedLong => IntKind::ULong,
927 Scalar::LongLong => IntKind::LongLong,
928 Scalar::UnsignedLongLong => IntKind::ULongLong,
929 Scalar::Int128 => IntKind::Int128,
930 Scalar::UnsignedInt128 => IntKind::UInt128,
931 _ => return None,
932 };
933 Some(kind)
934}
935
936fn float_kind(scalar: Scalar, target: &TargetInfo) -> Option<FloatKind> {
944 match scalar {
945 Scalar::Float => Some(FloatKind::Float),
946 Scalar::Double => Some(FloatKind::Double),
947 Scalar::LongDouble => Some(FloatKind::LongDouble),
948 Scalar::Float16 => Some(FloatKind::Float16),
949 Scalar::Float32 => Some(FloatKind::Float32),
950 Scalar::Float64 => Some(FloatKind::Float64),
951 Scalar::Float128 => Some(FloatKind::Float128),
952 Scalar::Float32x => Some(FloatKind::Float32x),
953 Scalar::Float64x => Some(FloatKind::Float64x),
954 Scalar::Float80 if target.long_double_format == Format::X87Extended => {
955 Some(FloatKind::LongDouble)
956 }
957 _ => None,
958 }
959}
960
961fn spell_scalar(scalar: Scalar) -> &'static str {
963 match scalar {
964 Scalar::Void => "void",
965 Scalar::Bool => "bool",
966 Scalar::Char => "char",
967 Scalar::SignedChar => "signed char",
968 Scalar::UnsignedChar => "unsigned char",
969 Scalar::Short => "short",
970 Scalar::UnsignedShort => "unsigned short",
971 Scalar::Int => "int",
972 Scalar::UnsignedInt => "unsigned int",
973 Scalar::Long => "long",
974 Scalar::UnsignedLong => "unsigned long",
975 Scalar::LongLong => "long long",
976 Scalar::UnsignedLongLong => "unsigned long long",
977 Scalar::Int128 => "__int128",
978 Scalar::UnsignedInt128 => "unsigned __int128",
979 Scalar::BitInt { unsigned: false, .. } => "_BitInt",
982 Scalar::BitInt { unsigned: true, .. } => "unsigned _BitInt",
983 Scalar::Float => "float",
984 Scalar::Double => "double",
985 Scalar::LongDouble => "long double",
986 Scalar::Float16 => "_Float16",
987 Scalar::Float32 => "_Float32",
988 Scalar::Float64 => "_Float64",
989 Scalar::Float128 => "_Float128",
990 Scalar::Float32x => "_Float32x",
991 Scalar::Float64x => "_Float64x",
992 Scalar::Float128x => "_Float128x",
993 Scalar::Float80 => "__float80",
994 Scalar::Decimal32 => "_Decimal32",
995 Scalar::Decimal64 => "_Decimal64",
996 Scalar::Decimal128 => "_Decimal128",
997 }
998}
999
1000#[cfg(test)]
1003mod tests {
1004 use rucc_ast::{Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId, Quals};
1005 use rucc_base::Interner;
1006 use rucc_lex::{IntConstant, IntConstantType, Remarks};
1007 use rucc_target::{TargetInfo, Triple};
1008 use rucc_types::{TypeKind, spell};
1009
1010 use super::*;
1011 use crate::check::Context;
1012
1013 pub(super) struct Fixture {
1019 pub(super) ast: rucc_ast::Ast,
1020 names: Interner,
1021 target: TargetInfo,
1022 }
1023
1024 impl Fixture {
1025 pub(super) fn new() -> Fixture {
1026 Fixture::for_target("x86_64-unknown-linux-gnu")
1027 }
1028
1029 pub(super) fn for_target(triple: &str) -> Fixture {
1031 let target = TargetInfo::new(triple.parse::<Triple>().expect("a triple"));
1032 Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1033 }
1034
1035 pub(super) fn name(&mut self, text: &str) -> Symbol {
1036 self.names.intern(text)
1037 }
1038
1039 pub(super) fn keywords(&mut self, written: &[BuiltinSet]) -> DeclSpecsId {
1041 let mut builtin = Builtin::NONE;
1042 for &keyword in written {
1043 builtin = builtin.add(keyword).expect("a keyword written once");
1044 }
1045 self.specs(TypeSpec::Builtin(builtin), Quals::NONE)
1046 }
1047
1048 pub(super) fn int_specs(&mut self) -> DeclSpecsId {
1050 self.keywords(&[BuiltinSet::INT])
1051 }
1052
1053 pub(super) fn specs(&mut self, ty: TypeSpec, quals: Quals) -> DeclSpecsId {
1054 let mut specs = DeclSpecs::empty(Span::DUMMY);
1055 specs.ty = ty;
1056 specs.quals = quals;
1057 self.ast.add_specs(specs)
1058 }
1059
1060 pub(super) fn declarator(
1061 &mut self,
1062 name: Option<&str>,
1063 derived: &[Derived],
1064 ) -> DeclaratorId {
1065 let name = name.map(|text| self.name(text));
1066 let derived = self.ast.add_derived_list(derived);
1067 self.ast.add_declarator(Declarator {
1068 name,
1069 name_span: Span::DUMMY,
1070 derived,
1071 span: Span::DUMMY,
1072 })
1073 }
1074
1075 pub(super) fn type_name(
1077 &mut self,
1078 specs: DeclSpecsId,
1079 derived: &[Derived],
1080 ) -> ast::TypeNameId {
1081 let declarator = self.declarator(None, derived);
1082 self.ast.add_type_name(ast::TypeName { specs, declarator, span: Span::DUMMY })
1083 }
1084
1085 pub(super) fn int(&mut self, value: u128) -> ast::ExprId {
1087 let ty = IntConstantType::Standard(IntKind::Int);
1088 let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1089 self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1090 }
1091
1092 fn use_name(&mut self, text: &str) -> ast::ExprId {
1093 let name = self.name(text);
1094 self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1095 }
1096
1097 pub(super) fn checker(&self) -> Checker<'_> {
1098 Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1099 }
1100 }
1101
1102 fn fixed(fixture: &mut Fixture, count: u128) -> Derived {
1104 let size = fixture.int(count);
1105 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1106 }
1107
1108 fn pointer() -> Derived {
1110 Derived::Pointer { quals: Quals::NONE, attrs: rucc_ast::AttrList::EMPTY }
1111 }
1112
1113 fn bit_int(width: ast::ExprId, unsigned: bool) -> TypeSpec {
1115 let mut builtin = Builtin::NONE.add_bit_int(width).expect("`_BitInt` rejected");
1116 if unsigned {
1117 builtin = builtin.add(BuiltinSet::UNSIGNED).expect("`unsigned` rejected");
1118 }
1119 TypeSpec::Builtin(builtin)
1120 }
1121
1122 pub(super) fn spelled(checker: &Checker<'_>, ty: TypeId) -> String {
1124 spell(&checker.types, checker.cx.names, ty)
1125 }
1126
1127 fn built(checker: &mut Checker<'_>, specs: DeclSpecsId, declarator: DeclaratorId) -> String {
1129 let ty = checker.declared_type(specs, declarator);
1130 spelled(checker, ty)
1131 }
1132
1133 pub(super) fn messages(checker: &Checker<'_>) -> Vec<String> {
1135 checker.errors.diagnostics().iter().map(|d| d.message.clone()).collect()
1136 }
1137
1138 pub(super) fn message(checker: &Checker<'_>) -> String {
1140 let mut reported = messages(checker);
1141 assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1142 reported.pop().expect("one message")
1143 }
1144
1145 #[test]
1146 fn the_keywords_of_a_specifier_list_name_one_type_between_them() {
1147 let mut fixture = Fixture::new();
1148 let long = fixture.keywords(&[BuiltinSet::UNSIGNED, BuiltinSet::LONG, BuiltinSet::INT]);
1149 let double = fixture.keywords(&[BuiltinSet::LONG, BuiltinSet::DOUBLE]);
1150 let void = fixture.keywords(&[BuiltinSet::VOID]);
1151 let plain = fixture.declarator(Some("x"), &[]);
1152
1153 let mut checker = fixture.checker();
1154 assert_eq!(built(&mut checker, long, plain), "unsigned long");
1155 assert_eq!(built(&mut checker, double, plain), "long double");
1156 assert_eq!(built(&mut checker, void, plain), "void");
1157 assert!(messages(&checker).is_empty());
1158 }
1159
1160 #[test]
1161 fn each_spelling_of_a_floating_type_names_a_type_of_its_own() {
1162 let mut fixture = Fixture::new();
1163 let written = [
1164 (BuiltinSet::FLOAT16, "_Float16"),
1165 (BuiltinSet::FLOAT32, "_Float32"),
1166 (BuiltinSet::FLOAT64, "_Float64"),
1167 (BuiltinSet::FLOAT128, "_Float128"),
1168 (BuiltinSet::FLOAT32X, "_Float32x"),
1169 (BuiltinSet::FLOAT64X, "_Float64x"),
1170 ];
1171 let specs: Vec<_> =
1172 written.iter().map(|&(keyword, _)| fixture.keywords(&[keyword])).collect();
1173 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1176 let plain = fixture.declarator(Some("x"), &[]);
1177
1178 let mut checker = fixture.checker();
1179 for (specs, expected) in specs.into_iter().zip(written.iter().map(|&(_, name)| name)) {
1180 assert_eq!(built(&mut checker, specs, plain), expected);
1181 }
1182 assert_eq!(built(&mut checker, float80, plain), "long double");
1183 assert!(messages(&checker).is_empty());
1184 }
1185
1186 #[test]
1187 fn a_floating_type_the_target_does_not_have_is_refused_rather_than_given_another_one() {
1188 let mut fixture = Fixture::for_target("aarch64-apple-darwin");
1193 let float128x = fixture.keywords(&[BuiltinSet::FLOAT128X]);
1194 let float80 = fixture.keywords(&[BuiltinSet::FLOAT80]);
1195 let plain = fixture.declarator(Some("x"), &[]);
1196
1197 let mut checker = fixture.checker();
1198 assert_eq!(built(&mut checker, float128x, plain), "double");
1201 assert_eq!(built(&mut checker, float80, plain), "double");
1202 assert_eq!(
1203 messages(&checker),
1204 [
1205 "'_Float128x' is not supported on this target",
1206 "'__float80' is not supported on this target",
1207 ]
1208 );
1209 }
1210
1211 #[test]
1212 fn a_decimal_floating_type_is_recognised_and_says_it_is_not_written_yet() {
1213 let mut fixture = Fixture::new();
1217 let specs = fixture.keywords(&[BuiltinSet::DECIMAL64]);
1218 let plain = fixture.declarator(Some("x"), &[]);
1219
1220 let mut checker = fixture.checker();
1221 assert_eq!(built(&mut checker, specs, plain), "double");
1222 assert_eq!(message(&checker), "the type `_Decimal64` is not supported yet");
1223 }
1224
1225 #[test]
1226 fn keywords_that_name_no_type_between_them_are_one_message_and_not_one_per_keyword() {
1227 let mut fixture = Fixture::new();
1228 let specs = fixture.keywords(&[BuiltinSet::SHORT, BuiltinSet::DOUBLE]);
1231 let plain = fixture.declarator(Some("x"), &[]);
1232
1233 let mut checker = fixture.checker();
1234 let ty = checker.declared_type(specs, plain);
1235 assert_eq!(spelled(&checker, ty), "int");
1236 assert_eq!(message(&checker), "two or more data types in declaration specifiers");
1237 }
1238
1239 #[test]
1240 fn a_declaration_with_no_type_at_all_is_an_int_and_a_warning_that_says_whose() {
1241 let mut fixture = Fixture::new();
1242 let specs = fixture.specs(TypeSpec::None, Quals::CONST);
1245 let again = fixture.specs(TypeSpec::None, Quals::NONE);
1246 let named = fixture.declarator(Some("x"), &[]);
1247 let abstracted = fixture.declarator(None, &[]);
1248
1249 let mut checker = fixture.checker();
1250 let ty = checker.declared_type(specs, named);
1251 assert_eq!(spelled(&checker, ty), "const int");
1252 checker.declared_type(again, abstracted);
1253 assert_eq!(
1254 messages(&checker),
1255 ["type defaults to 'int' in declaration of 'x'", "type defaults to 'int'"]
1256 );
1257 }
1258
1259 #[test]
1260 fn a_declarator_is_folded_from_the_far_end_so_the_step_nearest_the_name_wins() {
1261 let mut fixture = Fixture::new();
1262 let specs = fixture.int_specs();
1263 let char_specs = fixture.keywords(&[BuiltinSet::CHAR]);
1264 let parameter = fixture.declarator(None, &[]);
1265 let params = fixture.ast.add_param_list(&[ast::Param {
1266 specs: Some(char_specs),
1267 declarator: parameter,
1268 attrs: rucc_ast::AttrList::EMPTY,
1269 span: Span::DUMMY,
1270 }]);
1271 let three = fixed(&mut fixture, 3);
1274 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1275 let f = fixture.declarator(Some("f"), &[three, pointer(), call]);
1276
1277 let mut checker = fixture.checker();
1278 let ty = checker.declared_type(specs, f);
1279 assert_eq!(spelled(&checker, ty), "int (*[3])(char)");
1280 assert!(messages(&checker).is_empty());
1281 }
1282
1283 #[test]
1284 fn the_qualifiers_of_a_pointer_are_the_pointers_and_not_the_pointees() {
1285 let mut fixture = Fixture::new();
1286 let konst = fixture.specs(
1287 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
1288 Quals::CONST,
1289 );
1290 let plain = fixture.int_specs();
1291 let to_const = fixture.declarator(Some("p"), &[pointer()]);
1293 let const_pointer = fixture.declarator(
1295 Some("p"),
1296 &[Derived::Pointer { quals: Quals::CONST, attrs: rucc_ast::AttrList::EMPTY }],
1297 );
1298
1299 let mut checker = fixture.checker();
1300 assert_eq!(built(&mut checker, konst, to_const), "const int *");
1301 assert_eq!(built(&mut checker, plain, const_pointer), "int *const");
1302 assert!(messages(&checker).is_empty());
1303 }
1304
1305 #[test]
1306 fn restrict_is_only_for_a_pointer_and_says_so_where_it_is_not() {
1307 let mut fixture = Fixture::new();
1308 let specs = fixture.specs(TypeSpec::None, Quals::RESTRICT);
1309 let plain = fixture.declarator(Some("x"), &[]);
1310 let restricted =
1311 Derived::Pointer { quals: Quals::RESTRICT, attrs: rucc_ast::AttrList::EMPTY };
1312 let int_specs = fixture.int_specs();
1313 let p = fixture.declarator(Some("p"), &[restricted]);
1314
1315 let mut checker = fixture.checker();
1316 assert_eq!(built(&mut checker, int_specs, p), "int *restrict");
1317 checker.declared_type(specs, plain);
1318 assert!(
1319 messages(&checker).contains(&"invalid use of 'restrict'".to_string()),
1320 "got {:?}",
1321 messages(&checker)
1322 );
1323 }
1324
1325 #[test]
1326 fn an_array_of_something_there_can_be_no_array_of_says_which_it_was() {
1327 let mut fixture = Fixture::new();
1328 let void = fixture.keywords(&[BuiltinSet::VOID]);
1329 let int = fixture.int_specs();
1330 let three = fixed(&mut fixture, 3);
1331 let params = fixture.ast.add_param_list(&[]);
1332 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1333
1334 let voids = fixture.declarator(Some("a"), &[three]);
1335 let functions = fixture.declarator(Some("a"), &[three, call]);
1336 let anonymous = fixture.declarator(None, &[three]);
1337
1338 let mut checker = fixture.checker();
1339 checker.declared_type(void, voids);
1340 checker.declared_type(int, functions);
1341 checker.declared_type(void, anonymous);
1342 assert_eq!(
1343 messages(&checker),
1344 [
1345 "declaration of 'a' as array of voids",
1346 "declaration of 'a' as array of functions",
1347 "declaration of type name as array of voids",
1348 ]
1349 );
1350 }
1351
1352 #[test]
1353 fn an_array_of_a_tag_that_has_no_definition_yet_names_the_type_it_cannot_size() {
1354 let mut fixture = Fixture::new();
1355 let tag = fixture.name("S");
1356 let specs = fixture.specs(
1357 TypeSpec::Record {
1358 kind: ast::RecordKind::Struct,
1359 tag: Some(tag),
1360 fields: None,
1361 attrs: rucc_ast::AttrList::EMPTY,
1362 },
1363 Quals::NONE,
1364 );
1365 let three = fixed(&mut fixture, 3);
1366 let array = fixture.declarator(Some("a"), &[three]);
1367 let star = fixture.declarator(Some("p"), &[pointer()]);
1368
1369 let mut checker = fixture.checker();
1370 let pointer_ty = checker.declared_type(specs, star);
1373 assert_eq!(spelled(&checker, pointer_ty), "struct S *");
1374 checker.declared_type(specs, array);
1375 assert_eq!(message(&checker), "array type has incomplete element type 'struct S'");
1376 }
1377
1378 #[test]
1379 fn an_array_bound_is_folded_and_a_negative_one_is_refused() {
1380 let mut fixture = Fixture::new();
1381 let specs = fixture.int_specs();
1382 let zero = fixed(&mut fixture, 0);
1383 let four = fixed(&mut fixture, 4);
1384 let negative = {
1385 let one = fixture.int(1);
1386 let size = fixture
1387 .ast
1388 .expr(ast::Expr::Unary { op: rucc_ast::UnaryOp::Minus, operand: one }, Span::DUMMY);
1389 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1390 };
1391 let sized = fixture.declarator(Some("a"), &[four]);
1392 let empty = fixture.declarator(Some("a"), &[zero]);
1395 let unspecified = fixture.declarator(
1396 Some("a"),
1397 &[Derived::Array {
1398 size: ArraySize::Unspecified,
1399 quals: Quals::NONE,
1400 has_static: false,
1401 }],
1402 );
1403 let backwards = fixture.declarator(Some("a"), &[negative]);
1404
1405 let mut checker = fixture.checker();
1406 assert_eq!(built(&mut checker, specs, sized), "int [4]");
1407 assert_eq!(built(&mut checker, specs, empty), "int [0]");
1408 assert_eq!(built(&mut checker, specs, unspecified), "int []");
1409 assert!(messages(&checker).is_empty());
1410
1411 checker.declared_type(specs, backwards);
1412 assert_eq!(message(&checker), "size of array 'a' is negative");
1413 }
1414
1415 #[test]
1416 fn an_array_too_large_to_be_an_object_is_measured_in_its_elements() {
1417 let mut fixture = Fixture::new();
1418 let specs = fixture.int_specs();
1419 let count = u128::from(MAX_OBJECT_SIZE / 4 + 1);
1422 let huge = fixed(&mut fixture, count);
1423 let a = fixture.declarator(Some("a"), &[huge]);
1424
1425 let mut checker = fixture.checker();
1426 checker.declared_type(specs, a);
1427 assert_eq!(
1428 message(&checker),
1429 "size of array 'a' exceeds maximum object size '9223372036854775807'"
1430 );
1431 }
1432
1433 #[test]
1434 fn a_bound_that_is_not_a_constant_is_a_variable_length_array_where_there_is_a_run_time() {
1435 let mut fixture = Fixture::new();
1436 let specs = fixture.int_specs();
1437 let n = fixture.use_name("n");
1438 let variable =
1439 Derived::Array { size: ArraySize::Expr(n), quals: Quals::NONE, has_static: false };
1440 let a = fixture.declarator(Some("a"), &[variable]);
1441 let name = fixture.name("n");
1442
1443 let mut checker = fixture.checker();
1444 let int = checker.int();
1445 checker.declare_object(name, int, Span::DUMMY);
1446 checker.declared_type(specs, a);
1449 assert_eq!(message(&checker), "variably modified 'a' at file scope");
1450
1451 checker.scopes.push();
1452 let ty = checker.declared_type(specs, a);
1453 assert_eq!(spelled(&checker, ty), "int [*]");
1454 let again = checker.declared_type(specs, a);
1457 assert_ne!(ty, again);
1458 assert_eq!(
1459 checker.tast.vla_size(vla_id(&checker, ty)),
1460 checker.tast.vla_size(vla_id(&checker, ty))
1461 );
1462 }
1463
1464 fn vla_id(checker: &Checker<'_>, ty: TypeId) -> rucc_types::VlaId {
1466 match checker.types.kind(checker.types.canonical(ty)) {
1467 TypeKind::Array { len: ArrayLen::Variable(id), .. } => id,
1468 other => panic!("expected a variable length array, got {other:?}"),
1469 }
1470 }
1471
1472 #[test]
1473 fn a_star_bound_is_only_a_type_inside_a_prototype() {
1474 let mut fixture = Fixture::new();
1475 let specs = fixture.int_specs();
1476 let star = Derived::Array { size: ArraySize::Star, quals: Quals::NONE, has_static: false };
1477 let parameter = fixture.declarator(Some("a"), &[star]);
1478 let params = fixture.ast.add_param_list(&[ast::Param {
1479 specs: Some(specs),
1480 declarator: parameter,
1481 attrs: rucc_ast::AttrList::EMPTY,
1482 span: Span::DUMMY,
1483 }]);
1484 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1485 let f = fixture.declarator(Some("f"), &[call]);
1486
1487 let mut checker = fixture.checker();
1488 let ty = checker.declared_type(specs, f);
1491 assert_eq!(spelled(&checker, ty), "int (int *)");
1492 assert!(messages(&checker).is_empty());
1493
1494 checker.declared_type(specs, parameter);
1495 assert_eq!(message(&checker), "'[*]' not allowed in other than function prototype scope");
1496 }
1497
1498 #[test]
1499 fn a_deduced_type_on_a_parameter_names_nothing_and_says_where_it_was_written() {
1500 let mut fixture = Fixture::new();
1501 let specs = fixture.int_specs();
1504 let deduced = fixture.specs(TypeSpec::Auto(ast::Deduction::Auto), Quals::NONE);
1505 let parameter = fixture.declarator(Some("p"), &[]);
1506 let params = fixture.ast.add_param_list(&[ast::Param {
1507 specs: Some(deduced),
1508 declarator: parameter,
1509 attrs: rucc_ast::AttrList::EMPTY,
1510 span: Span::DUMMY,
1511 }]);
1512 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1513 let f = fixture.declarator(Some("f"), &[call]);
1514
1515 let mut checker = fixture.checker();
1516 let ty = checker.declared_type(specs, f);
1517 assert_eq!(spelled(&checker, ty), "int (int)");
1518 assert_eq!(message(&checker), "'auto' not allowed in function prototype");
1519 }
1520
1521 #[test]
1522 fn the_qualifiers_inside_a_parameters_brackets_end_up_on_the_pointer_it_becomes() {
1523 let mut fixture = Fixture::new();
1524 let specs = fixture.int_specs();
1525 let three = fixture.int(3);
1526 let qualified =
1527 Derived::Array { size: ArraySize::Expr(three), quals: Quals::CONST, has_static: true };
1528 let parameter = fixture.declarator(Some("a"), &[qualified]);
1529 let params = fixture.ast.add_param_list(&[ast::Param {
1530 specs: Some(specs),
1531 declarator: parameter,
1532 attrs: rucc_ast::AttrList::EMPTY,
1533 span: Span::DUMMY,
1534 }]);
1535 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1536 let f = fixture.declarator(Some("f"), &[call]);
1537
1538 let mut checker = fixture.checker();
1539 let ty = checker.declared_type(specs, f);
1541 assert_eq!(spelled(&checker, ty), "int (int *const)");
1542 assert!(messages(&checker).is_empty());
1543
1544 checker.declared_type(specs, parameter);
1546 assert_eq!(
1547 message(&checker),
1548 "static or type qualifiers in non-parameter array declarator"
1549 );
1550 }
1551
1552 #[test]
1553 fn a_function_cannot_return_a_function_or_an_array_and_the_message_names_which() {
1554 let mut fixture = Fixture::new();
1555 let specs = fixture.int_specs();
1556 let params = fixture.ast.add_param_list(&[]);
1557 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1558 let three = fixed(&mut fixture, 3);
1559
1560 let returns_function = fixture.declarator(Some("f"), &[call, call]);
1561 let returns_array = fixture.declarator(Some("f"), &[call, three]);
1562 let anonymous = fixture.declarator(None, &[call, three]);
1563
1564 let mut checker = fixture.checker();
1565 checker.declared_type(specs, returns_function);
1566 checker.declared_type(specs, returns_array);
1567 checker.declared_type(specs, anonymous);
1568 assert_eq!(
1569 messages(&checker),
1570 [
1571 "'f' declared as function returning a function",
1572 "'f' declared as function returning an array",
1573 "type name declared as function returning an array",
1574 ]
1575 );
1576 }
1577
1578 #[test]
1579 fn an_empty_parameter_list_says_nothing_before_c23_and_says_none_from_it() {
1580 let mut fixture = Fixture::new();
1581 let specs = fixture.int_specs();
1582 let params = fixture.ast.add_param_list(&[]);
1583 let empty = Derived::Function { params, variadic: false, kind: ParamKind::Empty };
1584 let f = fixture.declarator(Some("f"), &[empty]);
1585
1586 let mut checker = fixture.checker();
1587 assert_eq!(built(&mut checker, specs, f), "int (void)");
1588
1589 let mut old = fixture.checker();
1590 old.cx.std = Std::C17;
1591 assert_eq!(built(&mut old, specs, f), "int ()");
1592 assert!(messages(&old).is_empty());
1593 }
1594
1595 #[test]
1596 fn a_parameter_of_type_void_is_only_a_parameter_list_when_it_is_the_whole_of_one() {
1597 let mut fixture = Fixture::new();
1598 let int = fixture.int_specs();
1599 let void = fixture.keywords(&[BuiltinSet::VOID]);
1600 let named = fixture.declarator(Some("v"), &[]);
1601 let unnamed = fixture.declarator(None, &[]);
1602 let param = |declarator| ast::Param {
1603 specs: Some(void),
1604 declarator,
1605 attrs: rucc_ast::AttrList::EMPTY,
1606 span: Span::DUMMY,
1607 };
1608 let params = fixture.ast.add_param_list(&[param(named), param(unnamed)]);
1609 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1610 let f = fixture.declarator(Some("f"), &[call]);
1611
1612 let mut checker = fixture.checker();
1613 checker.declared_type(int, f);
1614 assert_eq!(
1615 messages(&checker),
1616 ["parameter 1 ('v') has void type", "'void' must be the only parameter"]
1617 );
1618 }
1619
1620 #[test]
1621 fn a_parameter_is_in_scope_for_the_parameters_after_it_and_gone_after_the_prototype() {
1622 let mut fixture = Fixture::new();
1623 let specs = fixture.int_specs();
1624 let n = fixture.declarator(Some("n"), &[]);
1625 let bound = fixture.use_name("n");
1626 let a = fixture.declarator(
1627 Some("a"),
1628 &[Derived::Array {
1629 size: ArraySize::Expr(bound),
1630 quals: Quals::NONE,
1631 has_static: false,
1632 }],
1633 );
1634 let param = |declarator| ast::Param {
1635 specs: Some(specs),
1636 declarator,
1637 attrs: rucc_ast::AttrList::EMPTY,
1638 span: Span::DUMMY,
1639 };
1640 let params = fixture.ast.add_param_list(&[param(n), param(a)]);
1641 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1642 let f = fixture.declarator(Some("f"), &[call]);
1643 let name = fixture.name("n");
1644
1645 let mut checker = fixture.checker();
1646 let ty = checker.declared_type(specs, f);
1649 assert_eq!(spelled(&checker, ty), "int (int, int *)");
1650 assert!(messages(&checker).is_empty());
1651 assert!(checker.scopes.lookup(name).is_none());
1652 }
1653
1654 #[test]
1655 fn a_parameter_declared_twice_in_one_prototype_is_reported_once() {
1656 let mut fixture = Fixture::new();
1657 let specs = fixture.int_specs();
1658 let a = fixture.declarator(Some("a"), &[]);
1659 let param = ast::Param {
1660 specs: Some(specs),
1661 declarator: a,
1662 attrs: rucc_ast::AttrList::EMPTY,
1663 span: Span::DUMMY,
1664 };
1665 let params = fixture.ast.add_param_list(&[param, param]);
1666 let call = Derived::Function { params, variadic: false, kind: ParamKind::Prototype };
1667 let f = fixture.declarator(Some("f"), &[call]);
1668
1669 let mut checker = fixture.checker();
1670 checker.declared_type(specs, f);
1671 assert_eq!(message(&checker), "redefinition of parameter 'a'");
1672 }
1673
1674 #[test]
1675 fn a_tag_names_the_same_type_every_time_and_one_kind_of_thing_only() {
1676 let mut fixture = Fixture::new();
1677 let tag = fixture.name("S");
1678 let record = |kind| TypeSpec::Record {
1679 kind,
1680 tag: Some(tag),
1681 fields: None,
1682 attrs: rucc_ast::AttrList::EMPTY,
1683 };
1684 let structure = fixture.specs(record(ast::RecordKind::Struct), Quals::NONE);
1685 let onion = fixture.specs(record(ast::RecordKind::Union), Quals::NONE);
1686 let plain = fixture.declarator(None, &[]);
1687
1688 let mut checker = fixture.checker();
1689 let first = checker.declared_type(structure, plain);
1690 let second = checker.declared_type(structure, plain);
1691 assert_eq!(first, second);
1692 assert!(messages(&checker).is_empty());
1693
1694 let wrong = checker.declared_type(onion, plain);
1695 assert_eq!(message(&checker), "'S' defined as wrong kind of tag");
1696 assert_ne!(wrong, first);
1699 assert_eq!(checker.declared_type(structure, plain), first);
1700 }
1701
1702 #[test]
1703 fn an_anonymous_tag_is_a_new_type_every_time_it_is_written() {
1704 let mut fixture = Fixture::new();
1705 let anonymous = |fixture: &mut Fixture| {
1706 fixture.specs(
1707 TypeSpec::Record {
1708 kind: ast::RecordKind::Struct,
1709 tag: None,
1710 fields: None,
1711 attrs: rucc_ast::AttrList::EMPTY,
1712 },
1713 Quals::NONE,
1714 )
1715 };
1716 let specs = anonymous(&mut fixture);
1717 let written_again = anonymous(&mut fixture);
1718 let plain = fixture.declarator(None, &[]);
1719
1720 let mut checker = fixture.checker();
1721 let first = checker.declared_type(specs, plain);
1722 let second = checker.declared_type(written_again, plain);
1723 assert_ne!(first, second);
1724 assert_eq!(checker.declared_type(specs, plain), first);
1727 }
1728
1729 #[test]
1730 fn an_enumeration_with_the_underlying_type_written_is_complete_from_there() {
1731 let mut fixture = Fixture::new();
1732 let long = fixture.keywords(&[BuiltinSet::LONG]);
1733 let long_name = fixture.type_name(long, &[]);
1734 let tag = fixture.name("E");
1735 let fixed_enum = fixture.specs(
1736 TypeSpec::Enum {
1737 tag: Some(tag),
1738 enumerators: None,
1739 underlying: Some(long_name),
1740 attrs: rucc_ast::AttrList::EMPTY,
1741 },
1742 Quals::NONE,
1743 );
1744 let plain = fixture.declarator(None, &[]);
1745
1746 let mut checker = fixture.checker();
1747 let ty = checker.declared_type(fixed_enum, plain);
1748 assert_eq!(spelled(&checker, ty), "enum E");
1749 assert!(is_complete(&checker.types, ty));
1750 assert!(messages(&checker).is_empty());
1751 }
1752
1753 #[test]
1754 fn an_enumeration_cannot_be_kept_in_something_that_is_not_an_integer_type() {
1755 let mut fixture = Fixture::new();
1756 let double = fixture.keywords(&[BuiltinSet::DOUBLE]);
1757 let double_name = fixture.type_name(double, &[]);
1758 let specs = fixture.specs(
1759 TypeSpec::Enum {
1760 tag: None,
1761 enumerators: None,
1762 underlying: Some(double_name),
1763 attrs: rucc_ast::AttrList::EMPTY,
1764 },
1765 Quals::NONE,
1766 );
1767 let plain = fixture.declarator(None, &[]);
1768
1769 let mut checker = fixture.checker();
1770 checker.declared_type(specs, plain);
1771 assert_eq!(message(&checker), "invalid 'enum' underlying type");
1772 }
1773
1774 #[test]
1775 fn atomic_is_a_type_and_not_a_qualifier_and_two_things_cannot_be_one() {
1776 let mut fixture = Fixture::new();
1777 let int = fixture.int_specs();
1778 let konst = fixture.specs(
1779 TypeSpec::Builtin(Builtin::NONE.add(BuiltinSet::INT).expect("int")),
1780 Quals::CONST,
1781 );
1782 let plain_name = fixture.type_name(int, &[]);
1783 let three = fixed(&mut fixture, 3);
1784 let array_name = fixture.type_name(int, &[three]);
1785 let params = fixture.ast.add_param_list(&[]);
1786 let call = Derived::Function { params, variadic: false, kind: ParamKind::Void };
1787 let function_name = fixture.type_name(int, &[call]);
1788 let const_name = fixture.type_name(konst, &[]);
1789
1790 let atomic = |fixture: &mut Fixture, name| {
1791 let specs = fixture.specs(TypeSpec::Atomic(name), Quals::NONE);
1792 let declarator = fixture.declarator(None, &[]);
1793 (specs, declarator)
1794 };
1795 let (plain, hole) = atomic(&mut fixture, plain_name);
1796 let (array, _) = atomic(&mut fixture, array_name);
1797 let (function, _) = atomic(&mut fixture, function_name);
1798 let (qualified, _) = atomic(&mut fixture, const_name);
1799
1800 let mut checker = fixture.checker();
1801 assert_eq!(built(&mut checker, plain, hole), "_Atomic(int)");
1802 assert!(messages(&checker).is_empty());
1803
1804 checker.declared_type(array, hole);
1805 checker.declared_type(function, hole);
1806 checker.declared_type(qualified, hole);
1807 assert_eq!(
1808 messages(&checker),
1809 [
1810 "'_Atomic'-qualified array type",
1811 "'_Atomic'-qualified function type",
1812 "'_Atomic' applied to a qualified type",
1813 ]
1814 );
1815 }
1816
1817 #[test]
1818 fn a_bit_int_is_as_wide_as_it_says_within_the_range_there_is() {
1819 let mut fixture = Fixture::new();
1820 let widths = [37, 1, 200, 0];
1821 let specs: Vec<_> = widths
1822 .iter()
1823 .map(|&width| {
1824 let expr = fixture.int(width);
1825 fixture.specs(bit_int(expr, false), Quals::NONE)
1826 })
1827 .collect();
1828 let plain = fixture.declarator(None, &[]);
1829
1830 let mut checker = fixture.checker();
1831 assert_eq!(built(&mut checker, specs[0], plain), "_BitInt(37)");
1832 assert!(messages(&checker).is_empty());
1833
1834 checker.declared_type(specs[1], plain);
1835 checker.declared_type(specs[2], plain);
1836 checker.declared_type(specs[3], plain);
1837 assert_eq!(
1838 messages(&checker),
1839 [
1840 "'signed _BitInt' argument must be at least 2",
1841 "'_BitInt' argument '200' is larger than 'BITINT_MAXWIDTH' '128'",
1842 "'_BitInt' argument '0' is not a positive integer constant expression",
1843 ]
1844 );
1845 }
1846
1847 #[test]
1848 fn an_unsigned_bit_int_holds_one_bit_where_a_signed_one_cannot() {
1849 let mut fixture = Fixture::new();
1850 let one = fixture.int(1);
1851 let unsigned = fixture.specs(bit_int(one, true), Quals::NONE);
1852 let eight = fixture.int(8);
1853 let wide = fixture.specs(bit_int(eight, true), Quals::NONE);
1854 let plain = fixture.declarator(None, &[]);
1855
1856 let mut checker = fixture.checker();
1857 assert_eq!(built(&mut checker, unsigned, plain), "unsigned _BitInt(1)");
1858 assert_eq!(built(&mut checker, wide, plain), "unsigned _BitInt(8)");
1859 assert!(messages(&checker).is_empty());
1860 }
1861
1862 #[test]
1863 fn a_bit_int_next_to_anything_but_a_sign_names_no_type() {
1864 let mut fixture = Fixture::new();
1865 let width = fixture.int(8);
1866 let mut both = Builtin::NONE.add(BuiltinSet::LONG).expect("`long` rejected");
1867 both = both.add_bit_int(width).expect("`_BitInt` rejected");
1868 let specs = fixture.specs(TypeSpec::Builtin(both), Quals::NONE);
1869 let plain = fixture.declarator(None, &[]);
1870
1871 let mut checker = fixture.checker();
1872 checker.declared_type(specs, plain);
1873 assert_eq!(messages(&checker), ["two or more data types in declaration specifiers"]);
1874 }
1875
1876 #[test]
1877 fn a_typedef_name_is_the_type_it_was_declared_for_and_keeps_its_own_spelling() {
1878 let mut fixture = Fixture::new();
1879 let word = fixture.name("word");
1880 let specs = fixture.specs(TypeSpec::Typedef(word), Quals::CONST);
1881 let p = fixture.declarator(Some("p"), &[pointer()]);
1882
1883 let mut checker = fixture.checker();
1884 let long = checker.types.int(IntKind::Long);
1885 let alias = checker.types.typedef(word, long);
1886 checker.declare_typedef(word, alias);
1887
1888 let ty = checker.declared_type(specs, p);
1889 assert_eq!(spelled(&checker, ty), "const word *");
1890 assert!(messages(&checker).is_empty());
1891 }
1892
1893 #[test]
1894 fn typeof_takes_the_type_of_an_expression_it_does_not_evaluate() {
1895 let mut fixture = Fixture::new();
1896 let x = fixture.use_name("x");
1897 let plain = fixture
1898 .specs(TypeSpec::Typeof { unqual: false, operand: TypeofArg::Expr(x) }, Quals::NONE);
1899 let bare = fixture
1900 .specs(TypeSpec::Typeof { unqual: true, operand: TypeofArg::Expr(x) }, Quals::NONE);
1901 let hole = fixture.declarator(None, &[]);
1902 let name = fixture.name("x");
1903
1904 let mut checker = fixture.checker();
1905 let int = checker.int();
1906 let konst = checker.types.qualified(int, Qualifiers::CONST);
1907 checker.declare_object(name, konst, Span::DUMMY);
1908
1909 assert_eq!(built(&mut checker, plain, hole), "const int");
1910 assert_eq!(built(&mut checker, bare, hole), "int");
1912 assert!(messages(&checker).is_empty());
1913 }
1914}