1use rucc_ast::{self as ast, AlignSpec, FuncSpecs, StorageClass};
35use rucc_base::Symbol;
36use rucc_diag::{Diagnostic, Span};
37use rucc_types::{ArrayLen, Qualifiers, TypeId, TypeKind};
38use rucc_types::{compatible, composite, is_complete, is_function, is_void, layout};
39
40use crate::check::Checker;
41use crate::check::stmt::Enclosing;
42use crate::decl::{
43 Decl, DeclId, DeclKind, DeclList, Definition, InitList, Linkage, StorageDuration,
44};
45use crate::scope::Binding;
46
47#[derive(Debug, Clone, Copy)]
49struct Declared {
50 name: Symbol,
52 ty: TypeId,
54 kind: DeclKind,
56 linkage: Linkage,
58 duration: StorageDuration,
60 state: Definition,
62 initialized: bool,
66 alignment: Option<u32>,
68 constant: bool,
70 retained: bool,
72 takes_prior_linkage: bool,
77 span: Span,
79}
80
81impl Checker<'_> {
82 pub fn check_decl(&mut self, id: ast::DeclId) -> DeclList {
87 let span = self.ast.decl_span(id);
88 match self.ast[id] {
89 ast::Decl::Error => self.tast.add_decl_refs(&[]),
90 ast::Decl::Var { specs, declarators } => self.var(specs, declarators),
91 ast::Decl::StaticAssert { cond, message } => {
92 self.static_assert(cond, message, span);
93 self.tast.add_decl_refs(&[])
94 }
95 ast::Decl::Function { specs, declarator, params, body } => {
96 match self.function(specs, declarator, params, body) {
97 Some(id) => self.tast.add_decl_refs(&[id]),
98 None => self.tast.add_decl_refs(&[]),
99 }
100 }
101 ast::Decl::Asm(_) => {
102 self.declaration_unsupported("an assembler statement at file scope", span);
103 self.tast.add_decl_refs(&[])
104 }
105 ast::Decl::Attributes(_) => self.tast.add_decl_refs(&[]),
108 }
109 }
110
111 fn var(&mut self, specs: ast::DeclSpecsId, declarators: ast::InitDeclaratorList) -> DeclList {
113 let mut items = self.ast[declarators].to_vec();
114 if items.is_empty() {
115 self.empty_declaration(specs);
116 return self.tast.add_decl_refs(&[]);
117 }
118 let node = self.ast[specs];
119 if let Some(which) = node.deduces() {
120 if items.len() > 1 {
125 let spelled = which.spelling();
126 self.report(
127 Diagnostic::error(
128 format!("'{spelled}' may only be used with a single declarator"),
129 node.span,
130 )
131 .with_code("E0651"),
132 );
133 items.truncate(1);
134 }
135 }
136 let mut declared = Vec::with_capacity(items.len());
137 for item in items {
138 if let Some(id) = self.init_declarator(specs, item) {
139 declared.push(id);
140 }
141 }
142 self.tast.add_decl_refs(&declared)
143 }
144
145 fn function(
151 &mut self,
152 specs: ast::DeclSpecsId,
153 declarator: ast::DeclaratorId,
154 declarations: ast::DeclList,
155 body: ast::StmtId,
156 ) -> Option<DeclId> {
157 let node = self.ast[declarator];
158 let span = node.name_span;
159 let (params, kind) = match self.ast[node.derived].first() {
160 Some(&ast::Derived::Function { params, kind, .. }) => (params, kind),
161 _ => return None,
164 };
165 let nested = !self.scopes.at_file_scope();
175 if nested {
176 let note = "a nested function is called through a trampoline written on the stack, \
177 which no target that enforces an unexecutable stack allows, so this \
178 compiler does not have them and will not";
179 self.report(
180 Diagnostic::error("a function definition inside a function", span)
181 .with_code("E0676")
182 .note(note, span),
183 );
184 }
185 if let Some(which) = self.ast[specs].deduces() {
189 self.not_plain(which, span);
190 return None;
191 }
192 let ty = self.declared_type(specs, declarator);
193 let ty = if kind == ast::ParamKind::Identifiers {
198 self.identifier_list(params, declarations);
199 let taking = self.old_style_signature(node.name, params, span);
200 self.function_taking(ty, taking)
201 } else {
202 ty
203 };
204 let name = node.name?;
205 let specs = self.ast[specs];
206 if specs.is_typedef() {
207 self.report(
208 Diagnostic::error("function definition declared 'typedef'", span)
209 .with_code("E0589"),
210 );
211 return None;
212 }
213 let (linkage, duration) = self.placement(&specs, DeclKind::Function, name, span);
214 let alignment = match specs.align {
215 Some(align) => self.alignment(align, ty, DeclKind::Function, name, span),
216 None => None,
217 };
218 let declared = Declared {
219 name,
220 ty,
221 kind: DeclKind::Function,
222 linkage,
223 duration,
224 state: if nested { Definition::Declared } else { Definition::Defined },
225 initialized: false,
226 alignment,
227 constant: false,
228 retained: self.retains(specs.attrs),
229 takes_prior_linkage: takes_prior_linkage(&specs, DeclKind::Function),
230 span,
231 };
232 let id = self.merge(declared);
233 if nested {
234 return Some(id);
235 }
236 let (stmt, params) = self.function_body(ty, name, span, params, body);
237 let mut node = self.tast[id].clone();
238 node.params = params;
239 node.body = Some(stmt);
240 self.tast.set_decl(id, node);
241 Some(id)
242 }
243
244 fn old_style_signature(
255 &mut self,
256 name: Option<Symbol>,
257 params: ast::ParamList,
258 span: Span,
259 ) -> Vec<TypeId> {
260 let objects = self.prototype_params(params);
261 let written: Vec<TypeId> = objects.iter().map(|&id| self.tast[id].ty).collect();
262 let Some(prototype) = name.and_then(|name| self.prototype_in_scope(name)) else {
263 return written.iter().map(|&ty| self.default_promoted(ty)).collect();
264 };
265 if prototype.len() != written.len() {
266 return written.iter().map(|&ty| self.default_promoted(ty)).collect();
269 }
270 for (index, (&declared, &wanted)) in written.iter().zip(&prototype).enumerate() {
271 let promoted = self.default_promoted(declared);
272 if compatible(&self.types, declared, wanted)
273 || compatible(&self.types, promoted, wanted)
274 {
275 continue;
276 }
277 let at = objects.get(index).map_or(span, |&id| self.tast.decl_span(id));
278 let what = match objects.get(index).and_then(|&id| self.tast[id].name) {
279 Some(name) => format!("argument '{}' doesn't match prototype", self.text(name)),
280 None => "argument doesn't match prototype".to_string(),
281 };
282 self.report(Diagnostic::error(what, at).with_code("E0683"));
283 }
284 prototype
285 }
286
287 fn prototype_in_scope(&mut self, name: Symbol) -> Option<Vec<TypeId>> {
292 let Some(Binding::Decl(id)) = self.scopes.lookup(name) else { return None };
293 let canonical = self.types.canonical(self.tast[id].ty);
294 let TypeKind::Function(signature) = self.types.kind(canonical) else { return None };
295 let signature = self.types.signature(signature);
296 (signature.prototyped && !signature.variadic).then(|| signature.params.clone())
297 }
298
299 fn function_body(
307 &mut self,
308 ty: TypeId,
309 name: Symbol,
310 span: Span,
311 params: ast::ParamList,
312 body: ast::StmtId,
313 ) -> (crate::stmt::StmtId, DeclList) {
314 let (ret, variadic) = match self.types.kind(self.types.canonical(ty)) {
315 TypeKind::Function(signature) => {
316 let signature = self.types.signature(signature);
317 (signature.ret, signature.variadic)
318 }
319 _ => (self.int(), false),
322 };
323 self.scopes.push();
324 let params = self.prototype_params(params);
325 for &decl in ¶ms {
326 if let Some(name) = self.tast[decl].name {
327 self.scopes.declare(name, Binding::Decl(decl));
328 }
329 }
330 let last_param = params.last().copied();
331 let params = self.tast.add_decl_refs(¶ms);
332 let name = Some(name);
333 let previous =
334 self.open_body(Enclosing { ret, at: span, variadic, last_param, params, name });
335 let stmt = self.body_block(body);
336 self.close_body(previous);
337 self.scopes.pop();
338 (stmt, params)
339 }
340
341 fn empty_declaration(&mut self, specs: ast::DeclSpecsId) {
347 let node = self.ast[specs];
348 if matches!(node.ty, ast::TypeSpec::None) {
349 self.specifiers_alone(node);
354 return;
355 }
356 if let ast::TypeSpec::Auto(which) = node.ty {
357 let word = which.spelling();
361 self.report(
362 Diagnostic::error(format!("`{word}` in empty declaration"), node.span)
363 .with_code("E0669"),
364 );
365 return;
366 }
367 self.declared_specs(specs);
368 match node.ty {
369 ast::TypeSpec::Record { tag: None, fields: Some(_), .. } => {
372 self.report(
373 Diagnostic::warning(
374 "unnamed struct/union that defines no instances",
375 node.span,
376 )
377 .with_code("E0612"),
378 );
379 }
380 ast::TypeSpec::Record { .. } | ast::TypeSpec::Enum { .. } => {
381 if !node.quals.is_none() {
382 self.report(
383 Diagnostic::warning(
384 "useless type qualifier in empty declaration",
385 node.span,
386 )
387 .with_code("E0611"),
388 );
389 }
390 }
391 _ => {
392 self.report(
393 Diagnostic::warning("useless type name in empty declaration", node.span)
394 .with_code("E0610"),
395 );
396 }
397 }
398 }
399
400 fn specifiers_alone(&mut self, node: ast::DeclSpecs) {
408 if node.func.has(FuncSpecs::INLINE) {
412 self.report(
413 Diagnostic::error("`inline` in empty declaration", node.span).with_code("E0665"),
414 );
415 return;
416 }
417 if node.func.has(FuncSpecs::NORETURN) {
418 self.report(
419 Diagnostic::error("`_Noreturn` in empty declaration", node.span).with_code("E0666"),
420 );
421 return;
422 }
423 let automatic = matches!(node.storage, Some(StorageClass::Auto | StorageClass::Register));
426 if automatic && self.scopes.at_file_scope() {
427 let word = if node.storage == Some(StorageClass::Auto) { "auto" } else { "register" };
428 self.report(
429 Diagnostic::error(format!("`{word}` in file-scope empty declaration"), node.span)
430 .with_code("E0667"),
431 );
432 return;
433 }
434 let useless = if node.storage.is_some() {
435 "useless storage class specifier in empty declaration"
436 } else if node.thread_local {
437 "useless `_Thread_local` in empty declaration"
438 } else if !node.quals.is_none() {
439 "useless type qualifier in empty declaration"
440 } else {
441 return;
442 };
443 self.report(Diagnostic::warning(useless, node.span).with_code("E0611"));
444 self.report(Diagnostic::warning("empty declaration", node.span).with_code("E0668"));
445 }
446
447 fn init_declarator(
449 &mut self,
450 specs: ast::DeclSpecsId,
451 item: ast::InitDeclarator,
452 ) -> Option<DeclId> {
453 let deduces = self.ast[specs].deduces();
456 let deducible = deduces.is_some_and(|which| self.deducible(which, item));
457 let ty =
458 if deduces.is_some() { self.int() } else { self.declared_type(specs, item.declarator) };
459 let ty = if self.ast[specs].constexpr {
464 self.types.qualified(ty, Qualifiers::CONST)
465 } else {
466 ty
467 };
468 let node = self.ast[item.declarator];
469 let name = node.name?;
472 let span = node.name_span;
473 let specs = self.ast[specs];
474 if specs.is_typedef() {
475 self.typedef(name, ty, &specs, item, span);
476 return None;
477 }
478 let kind = if is_function(&self.types, ty) { DeclKind::Function } else { DeclKind::Object };
479 let (linkage, duration) = self.placement(&specs, kind, name, span);
480 let state = self.definition_state(&specs, kind, item.init.is_some());
481 self.check_initializer_placement(&specs, item.init.is_some(), name, span);
482 self.check_specifiers(&specs, kind, name, span);
483 let alignment = match specs.align {
484 Some(align) => self.alignment(align, ty, kind, name, span),
485 None => None,
486 };
487 let mut declared = Declared {
488 name,
489 ty,
490 kind,
491 linkage,
492 duration,
493 state,
494 initialized: item.init.is_some(),
495 alignment,
496 constant: specs.constexpr,
497 retained: self.retains(specs.attrs) || self.retains(item.attrs),
501 takes_prior_linkage: takes_prior_linkage(&specs, kind),
502 span,
503 };
504 let id = self.merge(declared);
505 let mut worked = true;
508 let init = if deduces.is_some() && !deducible { None } else { item.init };
511 if let Some(init) = init {
512 let constant = specs.constexpr;
513 if deduces.is_some() || constant {
517 self.underspecified.push(id);
518 }
519 let deduce = deduces.map(|_| specs.quals);
520 let result = self.initializer(id, init, constant, deduce, span);
521 if deduces.is_some() || constant {
522 self.underspecified.pop();
523 }
524 match result {
525 Some((entries, ty)) => {
526 let mut node = self.tast[id].clone();
529 node.init = Some(entries);
530 node.ty = ty;
531 self.tast.set_decl(id, node);
532 }
533 None => worked = false,
534 }
535 }
536 if kind == DeclKind::Object && worked {
537 declared.ty = self.tast[id].ty;
540 self.check_storage_size(&declared);
541 }
542 Some(id)
543 }
544
545 fn typedef(
547 &mut self,
548 name: Symbol,
549 ty: TypeId,
550 specs: &ast::DeclSpecs,
551 item: ast::InitDeclarator,
552 span: Span,
553 ) {
554 if item.init.is_some() {
555 let spelled = self.text(name).to_owned();
556 self.report(
557 Diagnostic::error(
558 format!("typedef '{spelled}' is initialized (use '__typeof__' instead)"),
559 span,
560 )
561 .with_code("E0600"),
562 );
563 }
564 if specs.align.is_some() {
565 let spelled = self.text(name).to_owned();
566 self.report(
567 Diagnostic::error(format!("alignment specified for typedef '{spelled}'"), span)
568 .with_code("E0604"),
569 );
570 }
571 match self.scopes.lookup_here(name) {
572 Some(Binding::Typedef(previous)) if compatible(&self.types, previous, ty) => {}
575 Some(Binding::Typedef(_)) => {
576 self.conflicting_types(name, ty, None, span);
577 return;
578 }
579 Some(Binding::Decl(previous)) => {
580 self.different_kind(name, Some(previous), span);
581 return;
582 }
583 Some(Binding::Enumerator { .. }) => {
584 self.different_kind(name, None, span);
585 return;
586 }
587 None => {}
588 }
589 self.declare_typedef(name, ty);
590 }
591
592 fn placement(
594 &mut self,
595 specs: &ast::DeclSpecs,
596 kind: DeclKind,
597 name: Symbol,
598 span: Span,
599 ) -> (Linkage, StorageDuration) {
600 let file_scope = self.scopes.at_file_scope();
601 let storage = specs.storage;
602 if kind == DeclKind::Function {
603 let invalid = match storage {
607 Some(StorageClass::Auto | StorageClass::Register) => true,
608 Some(StorageClass::Static) => !file_scope,
609 _ => false,
610 };
611 if invalid {
612 let spelled = self.text(name).to_owned();
613 self.report(
614 Diagnostic::error(
615 format!("invalid storage class for function '{spelled}'"),
616 span,
617 )
618 .with_code("E0596"),
619 );
620 }
621 let linkage = if storage == Some(StorageClass::Static) && file_scope {
622 Linkage::Internal
623 } else {
624 Linkage::External
625 };
626 return (linkage, StorageDuration::Static);
627 }
628 if file_scope {
629 let spelled = self.text(name).to_owned();
630 match storage {
631 Some(StorageClass::Auto) => {
632 self.report(
633 Diagnostic::error(
634 format!("file-scope declaration of '{spelled}' specifies 'auto'"),
635 span,
636 )
637 .with_code("E0594"),
638 );
639 }
640 Some(StorageClass::Register) => {
644 self.report(
645 Diagnostic::error(
646 format!("register name not specified for '{spelled}'"),
647 span,
648 )
649 .with_code("E0595"),
650 );
651 }
652 _ => {}
653 }
654 let linkage = match storage {
655 Some(StorageClass::Static) => Linkage::Internal,
656 _ if specs.constexpr => Linkage::Internal,
657 _ => Linkage::External,
658 };
659 let duration =
660 if specs.thread_local { StorageDuration::Thread } else { StorageDuration::Static };
661 return (linkage, duration);
662 }
663 let stored =
666 if specs.thread_local { StorageDuration::Thread } else { StorageDuration::Static };
667 match storage {
668 Some(StorageClass::Extern) => (Linkage::External, stored),
669 Some(StorageClass::Static) => (Linkage::None, stored),
670 _ if specs.thread_local => {
671 let spelled = self.text(name).to_owned();
672 self.report(
673 Diagnostic::error(
674 format!(
675 "function-scope '{spelled}' implicitly auto and declared \
676 '_Thread_local'"
677 ),
678 span,
679 )
680 .with_code("E0597"),
681 );
682 (Linkage::None, StorageDuration::Thread)
683 }
684 _ => (Linkage::None, StorageDuration::Automatic),
685 }
686 }
687
688 fn definition_state(
690 &mut self,
691 specs: &ast::DeclSpecs,
692 kind: DeclKind,
693 has_init: bool,
694 ) -> Definition {
695 if kind == DeclKind::Function {
696 return Definition::Declared;
697 }
698 if has_init {
699 return Definition::Defined;
700 }
701 if specs.storage == Some(StorageClass::Extern) {
702 return Definition::Declared;
703 }
704 if self.scopes.at_file_scope() { Definition::Tentative } else { Definition::Defined }
707 }
708
709 fn check_initializer_placement(
711 &mut self,
712 specs: &ast::DeclSpecs,
713 has_init: bool,
714 name: Symbol,
715 span: Span,
716 ) {
717 let spelled = self.text(name).to_owned();
718 if specs.storage == Some(StorageClass::Extern) && has_init {
719 let diagnostic = if self.scopes.at_file_scope() {
722 Diagnostic::warning(format!("'{spelled}' initialized and declared 'extern'"), span)
723 .with_code("E0599")
724 } else {
725 Diagnostic::error(format!("'{spelled}' has both 'extern' and initializer"), span)
726 .with_code("E0598")
727 };
728 self.report(diagnostic);
729 }
730 if specs.constexpr && !has_init {
731 self.report(
732 Diagnostic::error("'constexpr' requires an initialized data declaration", span)
733 .with_code("E0617"),
734 );
735 }
736 }
737
738 fn check_specifiers(
740 &mut self,
741 specs: &ast::DeclSpecs,
742 kind: DeclKind,
743 name: Symbol,
744 span: Span,
745 ) {
746 if kind == DeclKind::Function || specs.func.is_none() {
747 return;
748 }
749 let spelled = self.text(name).to_owned();
750 let word = if specs.func.has(FuncSpecs::INLINE) { "inline" } else { "_Noreturn" };
751 self.report(
752 Diagnostic::warning(format!("variable '{spelled}' declared '{word}'"), span)
753 .with_code("E0609"),
754 );
755 }
756
757 fn check_storage_size(&mut self, declared: &Declared) {
759 if declared.state == Definition::Declared {
762 return;
763 }
764 let spelled = self.text(declared.name).to_owned();
765 if self.is_variable_length(declared.ty) {
766 if declared.duration != StorageDuration::Automatic {
767 self.report(
768 Diagnostic::error(
769 format!("storage size of '{spelled}' isn't constant"),
770 declared.span,
771 )
772 .with_code("E0602"),
773 );
774 }
775 return;
776 }
777 if is_complete(&self.types, declared.ty) {
778 return;
779 }
780 if declared.state == Definition::Tentative && self.is_unsized_array(declared.ty) {
783 return;
784 }
785 let void = is_void(&self.types, declared.ty) && !self.scopes.at_file_scope();
788 let diagnostic = if void {
789 Diagnostic::error(format!("variable or field '{spelled}' declared void"), declared.span)
790 .with_code("E0603")
791 } else {
792 Diagnostic::error(format!("storage size of '{spelled}' isn't known"), declared.span)
793 .with_code("E0601")
794 };
795 self.report(diagnostic);
796 }
797
798 fn alignment(
800 &mut self,
801 align: AlignSpec,
802 ty: TypeId,
803 kind: DeclKind,
804 name: Symbol,
805 span: Span,
806 ) -> Option<u32> {
807 let spelled = self.text(name).to_owned();
808 if kind == DeclKind::Function {
809 self.report(
810 Diagnostic::error(format!("alignment specified for function '{spelled}'"), span)
811 .with_code("E0605"),
812 );
813 return None;
814 }
815 let requested = match align {
816 AlignSpec::Type(named) => {
817 let named = self.type_name(named);
818 i128::from(layout(&self.types, named, self.cx.target).ok()?.align)
819 }
820 AlignSpec::Expr(expr) => {
821 let value = self.expr(expr);
822 match self.eval_integer(value) {
823 Ok(value) => value,
824 Err(failed) => {
825 if !failed.poisoned {
826 self.report(
827 Diagnostic::error(
828 "requested alignment is not an integer constant",
829 self.tast.expr_span(failed.at),
830 )
831 .with_code("E0606"),
832 );
833 }
834 return None;
835 }
836 }
837 }
838 };
839 if requested == 0 {
842 return None;
843 }
844 if requested < 0 || requested & (requested - 1) != 0 {
845 self.report(
846 Diagnostic::error(
847 format!("requested alignment '{requested}' is not a positive power of 2"),
848 span,
849 )
850 .with_code("E0607"),
851 );
852 return None;
853 }
854 let natural = layout(&self.types, ty, self.cx.target).map_or(1, |l| l.align);
855 if requested < i128::from(natural) {
856 self.report(
857 Diagnostic::error(
858 format!("'_Alignas' specifiers cannot reduce alignment of '{spelled}'"),
859 span,
860 )
861 .with_code("E0608"),
862 );
863 return None;
864 }
865 u32::try_from(requested).ok()
866 }
867
868 fn merge(&mut self, declared: Declared) -> DeclId {
870 let binding = match self.scopes.lookup_here(declared.name) {
874 Some(binding) => Some(binding),
875 None if declared.linkage != Linkage::None => {
882 self.scopes.lookup_where(declared.name, |binding| match binding {
883 Binding::Decl(id) => self.tast[id].linkage != Linkage::None,
884 Binding::Typedef(_) | Binding::Enumerator { .. } => true,
885 })
886 }
887 None => None,
888 };
889 let previous = match binding {
890 Some(Binding::Decl(id)) => id,
891 Some(Binding::Typedef(_)) => {
892 self.different_kind(declared.name, None, declared.span);
893 return self.declare(declared);
894 }
895 Some(Binding::Enumerator { .. }) => {
896 self.different_kind(declared.name, None, declared.span);
897 return self.declare(declared);
898 }
899 None => return self.declare(declared),
900 };
901 let node = self.tast[previous].clone();
902 if node.kind != declared.kind {
903 self.different_kind(declared.name, Some(previous), declared.span);
904 return self.declare(declared);
905 }
906 if !self.check_linkage(&node, &declared, previous) {
907 return self.declare(declared);
908 }
909 if !compatible(&self.types, node.ty, declared.ty) {
910 self.conflicting_types(declared.name, declared.ty, Some(previous), declared.span);
911 return previous;
912 }
913 if node.state == Definition::Defined && declared.state == Definition::Defined {
914 let spelled = self.text(declared.name).to_owned();
915 let (note, at) = self.previous_note(previous);
916 self.report(
917 Diagnostic::error(format!("redefinition of '{spelled}'"), declared.span)
918 .with_code("E0588")
919 .note(note, at),
920 );
921 return previous;
922 }
923 let ty = composite(&mut self.types, node.ty, declared.ty).unwrap_or(declared.ty);
924 let merged = Decl {
925 ty,
926 linkage: if declared.takes_prior_linkage { node.linkage } else { declared.linkage },
929 state: stronger(node.state, declared.state),
930 alignment: node.alignment.max(declared.alignment),
931 retained: node.retained || declared.retained,
934 ..node
935 };
936 self.tast.set_decl(previous, merged);
937 self.scopes.declare(declared.name, Binding::Decl(previous));
938 previous
939 }
940
941 fn check_linkage(&mut self, node: &Decl, declared: &Declared, previous: DeclId) -> bool {
943 let spelled = self.text(declared.name).to_owned();
944 let message = match (node.linkage, declared.linkage) {
945 (Linkage::None, Linkage::None) if node.init.is_some() && declared.initialized => {
950 return true;
951 }
952 (Linkage::None, Linkage::None) => {
953 format!("redeclaration of '{spelled}' with no linkage")
954 }
955 (Linkage::None, _) => {
956 format!("extern declaration of '{spelled}' follows declaration with no linkage")
957 }
958 (_, Linkage::None) => {
959 format!("declaration of '{spelled}' with no linkage follows extern declaration")
960 }
961 (Linkage::External, Linkage::Internal) => {
962 format!("static declaration of '{spelled}' follows non-static declaration")
963 }
964 (Linkage::Internal, Linkage::External) if !declared.takes_prior_linkage => {
967 format!("non-static declaration of '{spelled}' follows static declaration")
968 }
969 _ => return true,
970 };
971 let (note, at) = self.previous_note(previous);
972 self.report(Diagnostic::error(message, declared.span).with_code("E0592").note(note, at));
973 false
974 }
975
976 fn declare(&mut self, declared: Declared) -> DeclId {
978 let node = Decl {
979 name: Some(declared.name),
980 ty: declared.ty,
981 kind: declared.kind,
982 linkage: declared.linkage,
983 duration: declared.duration,
984 state: declared.state,
985 alignment: declared.alignment,
986 constant: declared.constant,
987 retained: declared.retained,
988 init: None,
989 params: DeclList::EMPTY,
990 body: None,
991 };
992 let id = self.tast.decl(node, declared.span);
993 self.scopes.declare(declared.name, Binding::Decl(id));
994 if self.scopes.at_file_scope() {
995 self.tast.add_top_level(id);
996 }
997 id
998 }
999
1000 fn initializer(
1006 &mut self,
1007 decl: DeclId,
1008 init: ast::InitId,
1009 constant: bool,
1010 deduce: Option<ast::Quals>,
1011 span: Span,
1012 ) -> Option<(InitList, TypeId)> {
1013 let node = &self.tast[decl];
1014 let (ty, kind, name, duration) = (node.ty, node.kind, node.name, node.duration);
1015 if kind == DeclKind::Function {
1016 let spelled = name.map_or_else(String::new, |name| self.text(name).to_owned());
1017 self.report(
1018 Diagnostic::error(
1019 format!("function '{spelled}' is initialized like a variable"),
1020 span,
1021 )
1022 .with_code("E0615"),
1023 );
1024 return None;
1025 }
1026 let is_static = duration != StorageDuration::Automatic;
1027 match deduce {
1028 Some(quals) => self.init_deduced(name, is_static, init, constant, quals, span),
1029 None => self.init_object(ty, name, is_static, init, constant, span),
1030 }
1031 }
1032
1033 fn not_plain(&mut self, which: ast::Deduction, span: Span) {
1038 let spelled = which.spelling();
1039 let allowed = match which {
1040 ast::Deduction::Auto => ", possibly with attributes,",
1041 ast::Deduction::AutoType => "",
1042 };
1043 self.report(
1044 Diagnostic::error(
1045 format!("'{spelled}' requires a plain identifier{allowed} as declarator"),
1046 span,
1047 )
1048 .with_code("E0651"),
1049 );
1050 }
1051
1052 fn deducible(&mut self, which: ast::Deduction, item: ast::InitDeclarator) -> bool {
1059 let spelled = which.spelling();
1060 let node = self.ast[item.declarator];
1061 let span = if node.name.is_some() { node.name_span } else { node.span };
1062 if !self.ast[node.derived].is_empty() {
1063 self.not_plain(which, span);
1064 return false;
1065 }
1066 if item.init.is_none() {
1067 self.report(
1068 Diagnostic::error(
1069 format!("'{spelled}' requires an initialized data declaration"),
1070 span,
1071 )
1072 .with_code("E0651"),
1073 );
1074 return false;
1075 }
1076 true
1077 }
1078
1079 fn static_assert(&mut self, cond: ast::ExprId, message: Option<ast::StrId>, span: Span) {
1081 let cond = self.expr(cond);
1082 let cond = self.value(cond);
1083 if self.is_poisoned(cond) {
1084 return;
1085 }
1086 let value = match self.eval_integer(cond) {
1087 Ok(value) => value,
1088 Err(failed) => {
1089 if !failed.poisoned {
1090 self.report(
1091 Diagnostic::error(
1092 "expression in static assertion is not constant",
1093 self.tast.expr_span(failed.at),
1094 )
1095 .with_code("E0614"),
1096 );
1097 }
1098 return;
1099 }
1100 };
1101 if value != 0 {
1102 return;
1103 }
1104 let message = match message {
1105 Some(id) => format!("static assertion failed: {}", self.quoted(id)),
1106 None => "static assertion failed".to_owned(),
1107 };
1108 self.report(Diagnostic::error(message, span).with_code("E0613"));
1109 }
1110
1111 fn conflicting_types(
1113 &mut self,
1114 name: Symbol,
1115 ty: TypeId,
1116 previous: Option<DeclId>,
1117 span: Span,
1118 ) {
1119 let spelled = self.text(name).to_owned();
1120 let written = self.spell(ty);
1121 let mut diagnostic =
1122 Diagnostic::error(format!("conflicting types for '{spelled}'; have '{written}'"), span)
1123 .with_code("E0586");
1124 if let Some(previous) = previous {
1125 let (note, at) = self.previous_note(previous);
1126 diagnostic = diagnostic.note(note, at);
1127 }
1128 self.report(diagnostic);
1129 }
1130
1131 fn different_kind(&mut self, name: Symbol, previous: Option<DeclId>, span: Span) {
1133 let spelled = self.text(name).to_owned();
1134 let mut diagnostic =
1135 Diagnostic::error(format!("'{spelled}' redeclared as different kind of symbol"), span)
1136 .with_code("E0587");
1137 if let Some(previous) = previous {
1138 let (note, at) = self.previous_note(previous);
1139 diagnostic = diagnostic.note(note, at);
1140 }
1141 self.report(diagnostic);
1142 }
1143
1144 fn previous_note(&self, id: DeclId) -> (String, Span) {
1150 let node = &self.tast[id];
1151 let word = if node.state == Definition::Defined { "definition" } else { "declaration" };
1152 let name = node.name.map_or("", |name| self.text(name));
1153 let ty = self.spell(node.ty);
1154 (format!("previous {word} of '{name}' with type '{ty}'"), self.tast.decl_span(id))
1155 }
1156
1157 fn quoted(&self, id: ast::StrId) -> String {
1159 let mut out = String::from("\"");
1160 for &element in &self.ast[id].elements {
1161 match char::from_u32(element) {
1162 Some('"') => out.push_str("\\\""),
1163 Some('\\') => out.push_str("\\\\"),
1164 Some('\n') => out.push_str("\\n"),
1165 Some(c) if !c.is_control() => out.push(c),
1166 _ => out.push_str(&format!("\\x{element:x}")),
1167 }
1168 }
1169 out.push('"');
1170 out
1171 }
1172
1173 pub(in crate::check) fn is_unsized_array(&self, ty: TypeId) -> bool {
1175 matches!(
1176 self.types.kind(self.types.canonical(ty)),
1177 TypeKind::Array { len: ArrayLen::Unknown, .. }
1178 )
1179 }
1180
1181 fn declaration_unsupported(&mut self, what: &str, span: Span) {
1183 self.report(
1184 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1185 );
1186 }
1187}
1188
1189fn takes_prior_linkage(specs: &ast::DeclSpecs, kind: DeclKind) -> bool {
1200 match specs.storage {
1201 Some(StorageClass::Extern) => true,
1202 None => kind == DeclKind::Function,
1203 _ => false,
1204 }
1205}
1206
1207fn stronger(a: Definition, b: Definition) -> Definition {
1209 let rank = |state| match state {
1210 Definition::Declared => 0,
1211 Definition::Tentative => 1,
1212 Definition::Defined => 2,
1213 };
1214 if rank(a) >= rank(b) { a } else { b }
1215}
1216
1217#[cfg(test)]
1218mod tests {
1219 use rucc_ast::{
1220 ArraySize, AttrList, Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId,
1221 Derived, ParamKind, ParamList, Quals, RecordKind, TypeSpec,
1222 };
1223 use rucc_base::Interner;
1224 use rucc_diag::{Severity, Span};
1225 use rucc_lex::{Encoding, IntConstant, IntConstantType, Remarks, StringLiteral};
1226 use rucc_session::Std;
1227 use rucc_target::{TargetInfo, Triple};
1228 use rucc_types::IntKind;
1229
1230 use super::*;
1231 use crate::check::Context;
1232 use crate::print::Printer;
1233
1234 struct Fixture {
1239 ast: rucc_ast::Ast,
1240 names: Interner,
1241 target: TargetInfo,
1242 }
1243
1244 impl Fixture {
1245 fn new() -> Fixture {
1246 let target =
1247 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
1248 Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1249 }
1250
1251 fn name(&mut self, text: &str) -> Symbol {
1252 self.names.intern(text)
1253 }
1254
1255 fn int_specs(&self) -> DeclSpecs {
1257 self.builtin(BuiltinSet::INT)
1258 }
1259
1260 fn deduced(&self, which: ast::Deduction) -> DeclSpecs {
1262 let mut specs = DeclSpecs::empty(Span::DUMMY);
1263 specs.ty = TypeSpec::Auto(which);
1264 specs
1265 }
1266
1267 fn builtin(&self, keyword: BuiltinSet) -> DeclSpecs {
1268 let mut specs = DeclSpecs::empty(Span::DUMMY);
1269 let builtin = Builtin::NONE.add(keyword).expect("a keyword written once");
1270 specs.ty = TypeSpec::Builtin(builtin);
1271 specs
1272 }
1273
1274 fn record(&mut self, tag: Option<&str>, fields: bool) -> DeclSpecs {
1276 let tag = tag.map(|tag| self.name(tag));
1277 let fields = fields.then(|| self.ast.add_member_list(&[]));
1278 let mut specs = DeclSpecs::empty(Span::DUMMY);
1279 specs.ty = TypeSpec::Record {
1280 kind: RecordKind::Struct,
1281 tag,
1282 fields,
1283 attrs: AttrList::EMPTY,
1284 pack: None,
1285 };
1286 specs
1287 }
1288
1289 fn declarator(&mut self, name: &str, derived: &[Derived]) -> DeclaratorId {
1290 let name = self.name(name);
1291 let derived = self.ast.add_derived_list(derived);
1292 self.ast.add_declarator(Declarator {
1293 name: Some(name),
1294 name_span: Span::DUMMY,
1295 derived,
1296 span: Span::DUMMY,
1297 })
1298 }
1299
1300 fn int(&mut self, value: u128) -> ast::ExprId {
1301 let ty = IntConstantType::Standard(IntKind::Int);
1302 let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1303 self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1304 }
1305
1306 fn use_name(&mut self, text: &str) -> ast::ExprId {
1307 let name = self.name(text);
1308 self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1309 }
1310
1311 fn string(&mut self, text: &str) -> ast::StrId {
1312 let elements = text.chars().map(|c| c as u32).collect();
1313 self.ast.add_string(StringLiteral {
1314 elements,
1315 encoding: Encoding::Plain,
1316 remarks: Remarks::default(),
1317 })
1318 }
1319
1320 fn var(
1322 &mut self,
1323 specs: DeclSpecs,
1324 name: &str,
1325 derived: &[Derived],
1326 init: Option<ast::ExprId>,
1327 ) -> ast::DeclId {
1328 let declarator = self.declarator(name, derived);
1329 let init = init.map(|expr| self.ast.add_init(ast::Init::Expr(expr)));
1330 let item = ast::InitDeclarator {
1331 declarator,
1332 init,
1333 asm_label: None,
1334 attrs: AttrList::EMPTY,
1335 span: Span::DUMMY,
1336 };
1337 let declarators = self.ast.add_init_declarator_list(&[item]);
1338 let specs = self.specs(specs);
1339 self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1340 }
1341
1342 fn object(&mut self, specs: DeclSpecs, name: &str) -> ast::DeclId {
1344 self.var(specs, name, &[], None)
1345 }
1346
1347 fn bare(&mut self, specs: DeclSpecs) -> ast::DeclId {
1349 let specs = self.specs(specs);
1350 let declarators = self.ast.add_init_declarator_list(&[]);
1351 self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1352 }
1353
1354 fn specs(&mut self, specs: DeclSpecs) -> DeclSpecsId {
1355 self.ast.add_specs(specs)
1356 }
1357
1358 fn param(
1360 &mut self,
1361 specs: DeclSpecs,
1362 name: Option<&str>,
1363 derived: &[Derived],
1364 ) -> ast::Param {
1365 let declarator = match name {
1366 Some(name) => self.declarator(name, derived),
1367 None => {
1368 let derived = self.ast.add_derived_list(derived);
1369 self.ast.add_declarator(Declarator {
1370 name: None,
1371 name_span: Span::DUMMY,
1372 derived,
1373 span: Span::DUMMY,
1374 })
1375 }
1376 };
1377 let specs = self.specs(specs);
1378 ast::Param { specs: Some(specs), declarator, attrs: AttrList::EMPTY, span: Span::DUMMY }
1379 }
1380
1381 fn takes(&mut self, params: &[ast::Param]) -> Derived {
1383 let params = self.ast.add_param_list(params);
1384 Derived::Function { params, variadic: false, kind: ParamKind::Prototype }
1385 }
1386
1387 fn stmt(&mut self, stmt: ast::Stmt) -> ast::StmtId {
1388 self.ast.stmt(stmt, Span::DUMMY)
1389 }
1390
1391 fn block(&mut self, body: &[ast::StmtId]) -> ast::StmtId {
1393 let body = self.ast.add_stmt_list(body);
1394 self.stmt(ast::Stmt::Compound(body))
1395 }
1396
1397 fn define(
1399 &mut self,
1400 specs: DeclSpecs,
1401 name: &str,
1402 derived: &[Derived],
1403 body: ast::StmtId,
1404 ) -> ast::DeclId {
1405 self.define_taking(specs, name, derived, &[], body)
1406 }
1407
1408 fn define_taking(
1411 &mut self,
1412 specs: DeclSpecs,
1413 name: &str,
1414 derived: &[Derived],
1415 declarations: &[ast::DeclId],
1416 body: ast::StmtId,
1417 ) -> ast::DeclId {
1418 let declarator = self.declarator(name, derived);
1419 let specs = self.specs(specs);
1420 let params = self.ast.add_decl_list(declarations);
1421 self.ast.decl(ast::Decl::Function { specs, declarator, params, body }, Span::DUMMY)
1422 }
1423
1424 fn checker(&self) -> Checker<'_> {
1425 Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1426 }
1427 }
1428
1429 fn pointer() -> Derived {
1431 Derived::Pointer { quals: Quals::NONE, attrs: AttrList::EMPTY }
1432 }
1433
1434 fn function() -> Derived {
1436 Derived::Function { params: ParamList::EMPTY, variadic: false, kind: ParamKind::Void }
1437 }
1438
1439 fn array(size: ast::ExprId) -> Derived {
1441 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1442 }
1443
1444 fn only(checker: &Checker<'_>, list: DeclList) -> DeclId {
1446 let declared = &checker.tast[list];
1447 assert_eq!(declared.len(), 1, "expected exactly one declaration, got {declared:?}");
1448 declared[0]
1449 }
1450
1451 fn dump(checker: &Checker<'_>, id: DeclId) -> String {
1453 let mut printer = Printer::new(&checker.tast, &checker.types, checker.cx.names);
1454 printer.decl(id);
1455 printer.finish()
1456 }
1457
1458 fn messages(checker: &Checker<'_>) -> Vec<String> {
1460 checker
1461 .errors
1462 .diagnostics()
1463 .iter()
1464 .flat_map(|d| {
1465 std::iter::once(d.message.clone())
1466 .chain(d.children.iter().map(|n| n.message.clone()))
1467 })
1468 .collect()
1469 }
1470
1471 fn severities(checker: &Checker<'_>) -> Vec<Severity> {
1475 checker.errors.diagnostics().iter().map(|d| d.severity).collect()
1476 }
1477
1478 fn message(checker: &Checker<'_>) -> String {
1479 let mut reported = messages(checker);
1480 assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1481 reported.pop().expect("one message")
1482 }
1483
1484 #[test]
1485 fn a_file_scope_object_is_external_and_static_and_defines_nothing_by_itself() {
1486 let mut f = Fixture::new();
1487 let specs = f.int_specs();
1488 let decl = f.object(specs, "x");
1489
1490 let mut c = f.checker();
1491 let list = c.check_decl(decl);
1492
1493 let id = only(&c, list);
1494 assert_eq!(dump(&c, id), "decl #0 x : int object external static tentative\n");
1495 assert_eq!(c.tast.top_level(), [id]);
1496 assert!(c.errors.is_empty());
1497 }
1498
1499 #[test]
1500 fn the_same_three_words_in_a_block_are_a_local_with_no_linkage() {
1501 let mut f = Fixture::new();
1502 let specs = f.int_specs();
1503 let decl = f.object(specs, "x");
1504
1505 let mut c = f.checker();
1506 c.scopes.push();
1507 let list = c.check_decl(decl);
1508
1509 let id = only(&c, list);
1510 assert_eq!(dump(&c, id), "decl #0 x : int object automatic defined\n");
1511 assert!(c.tast.top_level().is_empty());
1512 assert!(c.errors.is_empty());
1513 }
1514
1515 #[test]
1516 fn static_at_file_scope_hides_the_name_and_in_a_block_only_lengthens_the_lifetime() {
1517 let mut f = Fixture::new();
1518 let mut specs = f.int_specs();
1519 specs.storage = Some(StorageClass::Static);
1520 let outer = f.object(specs, "x");
1521 let inner = f.object(specs, "y");
1522
1523 let mut c = f.checker();
1524 let list = c.check_decl(outer);
1525 let outer = only(&c, list);
1526 c.scopes.push();
1527 let list = c.check_decl(inner);
1528 let inner = only(&c, list);
1529
1530 assert_eq!(dump(&c, outer), "decl #0 x : int object internal static tentative\n");
1531 assert_eq!(dump(&c, inner), "decl #1 y : int object static defined\n");
1532 assert!(c.errors.is_empty());
1533 }
1534
1535 #[test]
1536 fn extern_in_a_block_names_the_object_the_file_scope_declaration_named() {
1537 let mut f = Fixture::new();
1538 let specs = f.int_specs();
1539 let outer = f.object(specs, "x");
1540 let mut specs = f.int_specs();
1541 specs.storage = Some(StorageClass::Extern);
1542 let inner = f.object(specs, "x");
1543
1544 let mut c = f.checker();
1545 let list = c.check_decl(outer);
1546 let first = only(&c, list);
1547 c.scopes.push();
1548 let list = c.check_decl(inner);
1549
1550 assert_eq!(only(&c, list), first, "the block-scope declaration is the same object");
1551 assert_eq!(dump(&c, first), "decl #0 x : int object external static tentative\n");
1552 assert!(c.errors.is_empty());
1553 }
1554
1555 #[test]
1556 fn a_declaration_and_a_definition_of_one_name_are_one_declaration() {
1557 let mut f = Fixture::new();
1558 let mut specs = f.int_specs();
1559 specs.storage = Some(StorageClass::Extern);
1560 let declared = f.object(specs, "x");
1561 let specs = f.int_specs();
1562 let one = f.int(1);
1563 let defined = f.var(specs, "x", &[], Some(one));
1564
1565 let mut c = f.checker();
1566 let list = c.check_decl(declared);
1567 let first = only(&c, list);
1568 let list = c.check_decl(defined);
1569
1570 assert_eq!(only(&c, list), first);
1571 assert_eq!(
1572 dump(&c, first),
1573 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
1574 );
1575 assert!(c.errors.is_empty());
1576 }
1577
1578 #[test]
1579 fn two_definitions_of_one_name_are_refused_and_the_first_one_is_pointed_at() {
1580 let mut f = Fixture::new();
1581 let specs = f.int_specs();
1582 let one = f.int(1);
1583 let first = f.var(specs, "x", &[], Some(one));
1584 let two = f.int(2);
1585 let second = f.var(specs, "x", &[], Some(two));
1586
1587 let mut c = f.checker();
1588 c.check_decl(first);
1589 c.check_decl(second);
1590
1591 assert_eq!(
1592 messages(&c),
1593 ["redefinition of 'x'", "previous definition of 'x' with type 'int'"]
1594 );
1595 }
1596
1597 #[test]
1598 fn a_redeclaration_with_another_type_says_which_type_this_one_has() {
1599 let mut f = Fixture::new();
1600 let specs = f.int_specs();
1601 let first = f.object(specs, "x");
1602 let specs = f.builtin(BuiltinSet::CHAR);
1603 let second = f.object(specs, "x");
1604
1605 let mut c = f.checker();
1606 c.check_decl(first);
1607 c.check_decl(second);
1608
1609 assert_eq!(
1610 messages(&c),
1611 [
1612 "conflicting types for 'x'; have 'char'",
1613 "previous declaration of 'x' with type 'int'"
1614 ]
1615 );
1616 }
1617
1618 #[test]
1619 fn two_declarations_of_an_array_leave_the_one_that_gave_a_bound() {
1620 let mut f = Fixture::new();
1621 let specs = f.int_specs();
1622 let first = f.var(
1623 specs,
1624 "a",
1625 &[Derived::Array {
1626 size: ArraySize::Unspecified,
1627 quals: Quals::NONE,
1628 has_static: false,
1629 }],
1630 None,
1631 );
1632 let three = f.int(3);
1633 let second = f.var(specs, "a", &[array(three)], None);
1634
1635 let mut c = f.checker();
1636 let list = c.check_decl(first);
1637 let id = only(&c, list);
1638 c.check_decl(second);
1639
1640 assert_eq!(dump(&c, id), "decl #0 a : int[3] object external static tentative\n");
1641 assert!(c.errors.is_empty());
1642 }
1643
1644 #[test]
1645 fn static_and_non_static_declarations_of_one_name_contradict_each_other_both_ways() {
1646 let mut f = Fixture::new();
1647 let plain = f.int_specs();
1648 let mut hidden = f.int_specs();
1649 hidden.storage = Some(StorageClass::Static);
1650 let (a, b) = (f.object(plain, "x"), f.object(hidden, "x"));
1651 let (c1, d) = (f.object(hidden, "y"), f.object(plain, "y"));
1652
1653 let mut c = f.checker();
1654 c.check_decl(a);
1655 c.check_decl(b);
1656 c.check_decl(c1);
1657 c.check_decl(d);
1658
1659 assert_eq!(
1660 messages(&c),
1661 [
1662 "static declaration of 'x' follows non-static declaration",
1663 "previous declaration of 'x' with type 'int'",
1664 "non-static declaration of 'y' follows static declaration",
1665 "previous declaration of 'y' with type 'int'",
1666 ]
1667 );
1668 }
1669
1670 #[test]
1671 fn extern_after_static_keeps_the_linkage_the_first_declaration_gave_the_name() {
1672 let mut f = Fixture::new();
1673 let mut specs = f.int_specs();
1674 specs.storage = Some(StorageClass::Static);
1675 let first = f.object(specs, "x");
1676 let mut specs = f.int_specs();
1677 specs.storage = Some(StorageClass::Extern);
1678 let second = f.object(specs, "x");
1679
1680 let mut c = f.checker();
1681 let list = c.check_decl(first);
1682 let id = only(&c, list);
1683 c.check_decl(second);
1684
1685 assert_eq!(dump(&c, id), "decl #0 x : int object internal static tentative\n");
1686 assert!(c.errors.is_empty());
1687 }
1688
1689 #[test]
1690 fn a_function_defined_with_no_keyword_after_a_static_declaration_is_still_static() {
1691 let mut f = Fixture::new();
1692 let mut specs = f.int_specs();
1693 specs.storage = Some(StorageClass::Static);
1694 let first = f.var(specs, "f", &[function()], None);
1695 let body = f.block(&[]);
1696 let specs = f.int_specs();
1697 let second = f.define(specs, "f", &[function()], body);
1698
1699 let mut c = f.checker();
1700 let list = c.check_decl(first);
1701 let id = only(&c, list);
1702 c.check_decl(second);
1703
1704 assert_eq!(
1708 dump(&c, id),
1709 "decl #0 f : int(void) function internal defined\n body\n block\n"
1710 );
1711 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1712 }
1713
1714 #[test]
1715 fn two_locals_of_one_name_in_one_block_are_refused_as_having_no_linkage() {
1716 let mut f = Fixture::new();
1717 let specs = f.int_specs();
1718 let first = f.object(specs, "x");
1719 let second = f.object(specs, "x");
1720
1721 let mut c = f.checker();
1722 c.scopes.push();
1723 c.check_decl(first);
1724 c.check_decl(second);
1725
1726 assert_eq!(
1727 messages(&c),
1728 ["redeclaration of 'x' with no linkage", "previous definition of 'x' with type 'int'"]
1729 );
1730 }
1731
1732 #[test]
1733 fn an_extern_declaration_looks_past_a_local_of_the_same_name_in_the_block_outside_it() {
1734 let mut f = Fixture::new();
1740 let specs = f.int_specs();
1741 let file = f.object(specs, "v");
1742 let specs = f.int_specs();
1743 let local = f.object(specs, "v");
1744 let mut specs = f.int_specs();
1745 specs.storage = Some(StorageClass::Extern);
1746 let outward = f.object(specs, "v");
1747
1748 let mut c = f.checker();
1749 let list = c.check_decl(file);
1750 let first = only(&c, list);
1751 c.scopes.push();
1752 c.check_decl(local);
1753 c.scopes.push();
1754 let list = c.check_decl(outward);
1755
1756 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1757 assert_eq!(only(&c, list), first, "it names the object at file scope");
1758 }
1759
1760 #[test]
1761 fn a_name_that_already_means_a_type_is_redeclared_as_a_different_kind_of_symbol() {
1762 let mut f = Fixture::new();
1763 let mut specs = f.int_specs();
1764 specs.storage = Some(StorageClass::Typedef);
1765 let named = f.object(specs, "T");
1766 let specs = f.int_specs();
1767 let object = f.object(specs, "T");
1768
1769 let mut c = f.checker();
1770 c.check_decl(named);
1771 c.check_decl(object);
1772
1773 assert_eq!(message(&c), "'T' redeclared as different kind of symbol");
1774 }
1775
1776 #[test]
1777 fn a_typedef_may_be_written_twice_for_one_type_and_not_for_two() {
1778 let mut f = Fixture::new();
1779 let mut specs = f.int_specs();
1780 specs.storage = Some(StorageClass::Typedef);
1781 let first = f.object(specs, "T");
1782 let again = f.object(specs, "T");
1783 let mut specs = f.builtin(BuiltinSet::CHAR);
1784 specs.storage = Some(StorageClass::Typedef);
1785 let other = f.object(specs, "T");
1786
1787 let mut c = f.checker();
1788 let declared = c.check_decl(first);
1789 assert!(c.tast[declared].is_empty(), "a typedef declares nothing at run time");
1790 c.check_decl(again);
1791 assert!(c.errors.is_empty(), "the same type twice is what two headers do");
1792 c.check_decl(other);
1793
1794 assert_eq!(message(&c), "conflicting types for 'T'; have 'char'");
1795 }
1796
1797 #[test]
1798 fn a_typedef_with_an_initializer_names_the_operator_that_was_wanted_instead() {
1799 let mut f = Fixture::new();
1800 let mut specs = f.int_specs();
1801 specs.storage = Some(StorageClass::Typedef);
1802 let one = f.int(1);
1803 let decl = f.var(specs, "T", &[], Some(one));
1804
1805 let mut c = f.checker();
1806 c.check_decl(decl);
1807
1808 assert_eq!(message(&c), "typedef 'T' is initialized (use '__typeof__' instead)");
1809 }
1810
1811 #[test]
1812 fn an_object_of_a_type_with_no_size_is_refused_and_a_local_void_is_worded_apart() {
1813 let mut f = Fixture::new();
1814 let incomplete = f.record(Some("S"), false);
1815 let hidden = f.object(incomplete, "s");
1816 let void = f.builtin(BuiltinSet::VOID);
1817 let nothing = f.object(void, "x");
1818
1819 let mut c = f.checker();
1820 c.scopes.push();
1821 c.check_decl(hidden);
1822 c.check_decl(nothing);
1823
1824 assert_eq!(
1825 messages(&c),
1826 ["storage size of 's' isn't known", "variable or field 'x' declared void"]
1827 );
1828 }
1829
1830 #[test]
1831 fn an_array_with_no_bound_at_file_scope_waits_for_a_declaration_that_gives_one() {
1832 let mut f = Fixture::new();
1833 let specs = f.int_specs();
1834 let decl = f.var(
1835 specs,
1836 "a",
1837 &[Derived::Array {
1838 size: ArraySize::Unspecified,
1839 quals: Quals::NONE,
1840 has_static: false,
1841 }],
1842 None,
1843 );
1844
1845 let mut c = f.checker();
1846 let list = c.check_decl(decl);
1847
1848 assert_eq!(
1849 dump(&c, only(&c, list)),
1850 "decl #0 a : int[] object external static tentative\n"
1851 );
1852 assert!(c.errors.is_empty(), "the end of the translation unit is what decides this one");
1853 }
1854
1855 #[test]
1856 fn a_variable_length_array_may_be_automatic_and_may_not_outlive_the_block() {
1857 let mut f = Fixture::new();
1858 let specs = f.int_specs();
1859 let n = f.use_name("n");
1860 let automatic = f.var(specs, "a", &[array(n)], None);
1861 let mut specs = f.int_specs();
1862 specs.storage = Some(StorageClass::Static);
1863 let n = f.use_name("n");
1864 let stored = f.var(specs, "b", &[array(n)], None);
1865 let n = f.name("n");
1866
1867 let mut c = f.checker();
1868 c.scopes.push();
1869 let int = c.types.int(IntKind::Int);
1870 c.declare_object(n, int, Span::DUMMY);
1871 c.check_decl(automatic);
1872 assert!(c.errors.is_empty());
1873 c.check_decl(stored);
1874
1875 assert_eq!(message(&c), "storage size of 'b' isn't constant");
1876 }
1877
1878 #[test]
1879 fn auto_and_register_at_file_scope_are_each_refused_in_the_words_gcc_uses() {
1880 let mut f = Fixture::new();
1881 let mut specs = f.int_specs();
1882 specs.storage = Some(StorageClass::Auto);
1883 let automatic = f.object(specs, "x");
1884 let mut specs = f.int_specs();
1885 specs.storage = Some(StorageClass::Register);
1886 let in_a_register = f.object(specs, "y");
1887
1888 let mut c = f.checker();
1889 c.check_decl(automatic);
1890 c.check_decl(in_a_register);
1891
1892 assert_eq!(
1893 messages(&c),
1894 [
1895 "file-scope declaration of 'x' specifies 'auto'",
1896 "register name not specified for 'y'",
1897 ]
1898 );
1899 }
1900
1901 #[test]
1902 fn a_function_takes_static_at_file_scope_and_no_storage_class_anywhere_else() {
1903 let mut f = Fixture::new();
1904 let mut specs = f.int_specs();
1905 specs.storage = Some(StorageClass::Static);
1906 let hidden = f.var(specs, "f", &[function()], None);
1907 let inner = f.var(specs, "g", &[function()], None);
1908
1909 let mut c = f.checker();
1910 let list = c.check_decl(hidden);
1911 assert_eq!(dump(&c, only(&c, list)), "decl #0 f : int(void) function internal declared\n");
1912 assert!(c.errors.is_empty());
1913 c.scopes.push();
1914 c.check_decl(inner);
1915
1916 assert_eq!(message(&c), "invalid storage class for function 'g'");
1917 }
1918
1919 #[test]
1920 fn a_scalar_initializer_is_converted_to_the_type_of_the_object_it_initializes() {
1921 let mut f = Fixture::new();
1922 let specs = f.builtin(BuiltinSet::DOUBLE);
1923 let one = f.int(1);
1924 let decl = f.var(specs, "d", &[], Some(one));
1925
1926 let mut c = f.checker();
1927 c.scopes.push();
1928 let list = c.check_decl(decl);
1929
1930 assert_eq!(
1931 dump(&c, only(&c, list)),
1932 "decl #0 d : double object automatic defined\n init\n +0\n \
1933 convert arithmetic : double\n const 1 : int\n"
1934 );
1935 assert!(c.errors.is_empty());
1936 }
1937
1938 #[test]
1939 fn an_initializer_of_the_wrong_kind_names_the_conversion_it_would_have_taken() {
1940 let mut f = Fixture::new();
1941 let specs = f.int_specs();
1942 let one = f.int(1);
1943 let from_an_integer = f.var(specs, "p", &[pointer()], None.or(Some(one)));
1944 let specs = f.builtin(BuiltinSet::CHAR);
1945 let q = f.use_name("q");
1946 let from_a_pointer = f.var(specs, "r", &[pointer()], Some(q));
1947 let q = f.name("q");
1948
1949 let mut c = f.checker();
1950 c.scopes.push();
1951 let int = c.types.int(IntKind::Int);
1952 let to_int = c.types.pointer(int);
1953 c.declare_object(q, to_int, Span::DUMMY);
1954 c.check_decl(from_an_integer);
1955 c.check_decl(from_a_pointer);
1956
1957 assert_eq!(
1958 messages(&c),
1959 [
1960 "initialization of 'int *' from 'int' makes pointer from integer without a cast",
1961 "initialization of 'char *' from incompatible pointer type 'int *'",
1962 ]
1963 );
1964 }
1965
1966 #[test]
1967 fn an_array_and_a_structure_each_refuse_a_value_as_an_initializer() {
1968 let mut f = Fixture::new();
1969 let specs = f.int_specs();
1970 let two = f.int(2);
1971 let one = f.int(1);
1972 let an_array = f.var(specs, "a", &[array(two)], Some(one));
1973 let specs = f.record(Some("S"), true);
1974 let one = f.int(1);
1975 let a_record = f.var(specs, "s", &[], Some(one));
1976
1977 let mut c = f.checker();
1978 c.scopes.push();
1979 c.check_decl(an_array);
1980 c.check_decl(a_record);
1981
1982 assert_eq!(messages(&c), ["invalid initializer", "invalid initializer"]);
1983 }
1984
1985 #[test]
1986 fn extern_with_an_initializer_is_an_error_in_a_block_and_a_warning_at_file_scope() {
1987 let mut f = Fixture::new();
1988 let mut specs = f.int_specs();
1989 specs.storage = Some(StorageClass::Extern);
1990 let one = f.int(1);
1991 let outer = f.var(specs, "x", &[], Some(one));
1992 let one = f.int(1);
1993 let inner = f.var(specs, "y", &[], Some(one));
1994
1995 let mut c = f.checker();
1996 c.check_decl(outer);
1997 c.scopes.push();
1998 c.check_decl(inner);
1999
2000 assert_eq!(
2001 messages(&c),
2002 ["'x' initialized and declared 'extern'", "'y' has both 'extern' and initializer"]
2003 );
2004 }
2005
2006 #[test]
2007 fn alignas_raises_the_alignment_and_refuses_to_lower_it_or_to_take_a_number_that_is_not_one() {
2008 let mut f = Fixture::new();
2009 let sixteen = f.int(16);
2010 let mut specs = f.int_specs();
2011 specs.align = Some(AlignSpec::Expr(sixteen));
2012 let raised = f.object(specs, "x");
2013 let one = f.int(1);
2014 let mut specs = f.int_specs();
2015 specs.align = Some(AlignSpec::Expr(one));
2016 let lowered = f.object(specs, "y");
2017 let three = f.int(3);
2018 let mut specs = f.int_specs();
2019 specs.align = Some(AlignSpec::Expr(three));
2020 let odd = f.object(specs, "z");
2021
2022 let mut c = f.checker();
2023 let list = c.check_decl(raised);
2024 assert_eq!(
2025 dump(&c, only(&c, list)),
2026 "decl #0 x : int object external static tentative alignas 16\n"
2027 );
2028 c.check_decl(lowered);
2029 c.check_decl(odd);
2030
2031 assert_eq!(
2032 messages(&c),
2033 [
2034 "'_Alignas' specifiers cannot reduce alignment of 'y'",
2035 "requested alignment '3' is not a positive power of 2",
2036 ]
2037 );
2038 }
2039
2040 #[test]
2041 fn alignment_asked_for_on_a_typedef_and_on_a_function_is_refused_on_each() {
2042 let mut f = Fixture::new();
2043 let sixteen = f.int(16);
2044 let mut specs = f.int_specs();
2045 specs.align = Some(AlignSpec::Expr(sixteen));
2046 specs.storage = Some(StorageClass::Typedef);
2047 let named = f.object(specs, "T");
2048 let mut specs = f.int_specs();
2049 specs.align = Some(AlignSpec::Expr(sixteen));
2050 let called = f.var(specs, "g", &[function()], None);
2051
2052 let mut c = f.checker();
2053 c.check_decl(named);
2054 c.check_decl(called);
2055
2056 assert_eq!(
2057 messages(&c),
2058 ["alignment specified for typedef 'T'", "alignment specified for function 'g'"]
2059 );
2060 }
2061
2062 #[test]
2063 fn a_static_assertion_that_holds_says_nothing_and_one_that_fails_quotes_its_message() {
2064 let mut f = Fixture::new();
2065 let one = f.int(1);
2066 let holds = f.ast.decl(ast::Decl::StaticAssert { cond: one, message: None }, Span::DUMMY);
2067 let zero = f.int(0);
2068 let boom = f.string("boom");
2069 let fails =
2070 f.ast.decl(ast::Decl::StaticAssert { cond: zero, message: Some(boom) }, Span::DUMMY);
2071
2072 let mut c = f.checker();
2073 c.check_decl(holds);
2074 assert!(c.errors.is_empty());
2075 c.check_decl(fails);
2076
2077 assert_eq!(message(&c), "static assertion failed: \"boom\"");
2078 }
2079
2080 #[test]
2081 fn an_empty_declaration_says_what_about_it_was_useless() {
2082 let mut f = Fixture::new();
2083 let specs = f.int_specs();
2084 let a_type_name = f.bare(specs);
2085 let mut specs = f.record(Some("S"), false);
2086 specs.quals = Quals::CONST;
2087 let a_qualifier = f.bare(specs);
2088 let unnamed = f.record(None, true);
2089 let no_instances = f.bare(unnamed);
2090
2091 let mut c = f.checker();
2092 c.check_decl(a_type_name);
2093 c.check_decl(a_qualifier);
2094 c.check_decl(no_instances);
2095
2096 assert_eq!(
2097 messages(&c),
2098 [
2099 "useless type name in empty declaration",
2100 "useless type qualifier in empty declaration",
2101 "unnamed struct/union that defines no instances",
2102 ]
2103 );
2104 }
2105
2106 #[test]
2109 fn a_semicolon_on_its_own_is_a_declaration_of_nothing_and_says_nothing() {
2110 let mut f = Fixture::new();
2111 let nothing = f.bare(DeclSpecs::empty(Span::DUMMY));
2112
2113 let mut c = f.checker();
2114 c.check_decl(nothing);
2115
2116 assert!(messages(&c).is_empty(), "{:?}", messages(&c));
2117 }
2118
2119 #[test]
2124 fn a_specifier_with_nothing_to_apply_to_is_named_in_the_message() {
2125 let mut f = Fixture::new();
2126 let mut specs = DeclSpecs::empty(Span::DUMMY);
2127 specs.storage = Some(StorageClass::Extern);
2128 let storage = f.bare(specs);
2129 let mut specs = DeclSpecs::empty(Span::DUMMY);
2130 specs.thread_local = true;
2131 let thread = f.bare(specs);
2132 let mut specs = DeclSpecs::empty(Span::DUMMY);
2133 specs.quals = Quals::CONST;
2134 let qualifier = f.bare(specs);
2135
2136 let mut c = f.checker();
2137 c.check_decl(storage);
2138 c.check_decl(thread);
2139 c.check_decl(qualifier);
2140
2141 assert_eq!(
2142 messages(&c),
2143 [
2144 "useless storage class specifier in empty declaration",
2145 "empty declaration",
2146 "useless `_Thread_local` in empty declaration",
2147 "empty declaration",
2148 "useless type qualifier in empty declaration",
2149 "empty declaration",
2150 ]
2151 );
2152 assert!(severities(&c).iter().all(|s| *s == Severity::Warning), "all six are warnings");
2153 }
2154
2155 #[test]
2159 fn the_specifiers_that_cannot_be_ignored_in_an_empty_declaration_are_errors() {
2160 let mut f = Fixture::new();
2161 let mut specs = DeclSpecs::empty(Span::DUMMY);
2162 specs.func = FuncSpecs::INLINE;
2163 let inline = f.bare(specs);
2164 let mut specs = DeclSpecs::empty(Span::DUMMY);
2165 specs.func = FuncSpecs::NORETURN;
2166 let noreturn = f.bare(specs);
2167 let mut specs = DeclSpecs::empty(Span::DUMMY);
2168 specs.storage = Some(StorageClass::Register);
2169 let register = f.bare(specs);
2170 let specs = f.deduced(ast::Deduction::Auto);
2171 let deduced = f.bare(specs);
2172
2173 let mut c = f.checker();
2174 c.check_decl(inline);
2175 c.check_decl(noreturn);
2176 c.check_decl(register);
2177 c.check_decl(deduced);
2178
2179 assert_eq!(
2180 messages(&c),
2181 [
2182 "`inline` in empty declaration",
2183 "`_Noreturn` in empty declaration",
2184 "`register` in file-scope empty declaration",
2185 "`auto` in empty declaration",
2186 ]
2187 );
2188 assert!(severities(&c).iter().all(|s| *s == Severity::Error), "all four are errors");
2189 }
2190
2191 #[test]
2192 fn a_specifier_that_only_a_function_takes_is_warned_about_on_a_variable() {
2193 let mut f = Fixture::new();
2194 let mut specs = f.int_specs();
2195 specs.func = FuncSpecs::INLINE;
2196 let decl = f.object(specs, "x");
2197
2198 let mut c = f.checker();
2199 c.check_decl(decl);
2200
2201 assert_eq!(message(&c), "variable 'x' declared 'inline'");
2202 }
2203
2204 #[test]
2205 fn thread_local_in_a_block_needs_a_storage_class_that_gives_it_somewhere_to_live() {
2206 let mut f = Fixture::new();
2207 let mut specs = f.int_specs();
2208 specs.thread_local = true;
2209 let alone = f.object(specs, "x");
2210 let mut specs = f.int_specs();
2211 specs.thread_local = true;
2212 specs.storage = Some(StorageClass::Static);
2213 let stored = f.object(specs, "y");
2214
2215 let mut c = f.checker();
2216 c.scopes.push();
2217 c.check_decl(alone);
2218 assert_eq!(message(&c), "function-scope 'x' implicitly auto and declared '_Thread_local'");
2219 let list = c.check_decl(stored);
2220
2221 assert_eq!(dump(&c, only(&c, list)), "decl #1 y : int object thread defined\n");
2222 }
2223
2224 #[test]
2225 fn a_function_definition_is_a_declaration_with_its_body_under_it() {
2226 let mut f = Fixture::new();
2227 let specs = f.builtin(BuiltinSet::VOID);
2228 let body = f.block(&[]);
2229 let decl = f.define(specs, "f", &[function()], body);
2230
2231 let mut c = f.checker();
2232 let list = c.check_decl(decl);
2233
2234 let id = only(&c, list);
2235 assert_eq!(
2236 dump(&c, id),
2237 "decl #0 f : void(void) function external defined\n body\n block\n"
2238 );
2239 assert!(c.errors.is_empty());
2240 }
2241
2242 #[test]
2243 fn a_parameter_is_declared_once_and_the_body_names_that_declaration() {
2244 let mut f = Fixture::new();
2245 let int = f.int_specs();
2246 let n = f.param(int, Some("n"), &[]);
2247 let takes = f.takes(&[n]);
2248 let use_n = f.use_name("n");
2249 let ret = f.stmt(ast::Stmt::Return(Some(use_n)));
2250 let body = f.block(&[ret]);
2251 let specs = f.int_specs();
2252 let decl = f.define(specs, "f", &[takes], body);
2253
2254 let mut c = f.checker();
2255 let list = c.check_decl(decl);
2256
2257 let id = only(&c, list);
2258 assert_eq!(
2259 dump(&c, id),
2260 "decl #1 f : int(int) function external defined\n params\n decl #0 n : int \
2261 object automatic defined\n body\n block\n return\n convert lvalue \
2262 : int\n decl #0 n : int lvalue\n"
2263 );
2264 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2265 }
2266
2267 #[test]
2268 fn a_parameter_a_definition_left_unnamed_is_still_one_of_the_parameters() {
2269 let mut f = Fixture::new();
2270 let int = f.int_specs();
2271 let a = f.param(int, Some("a"), &[]);
2272 let int = f.int_specs();
2273 let anonymous = f.param(int, None, &[]);
2274 let takes = f.takes(&[a, anonymous]);
2275 let use_a = f.use_name("a");
2276 let ret = f.stmt(ast::Stmt::Return(Some(use_a)));
2277 let body = f.block(&[ret]);
2278 let specs = f.int_specs();
2279 let decl = f.define(specs, "f", &[takes], body);
2280
2281 let mut c = f.checker();
2282 let list = c.check_decl(decl);
2283
2284 let id = only(&c, list);
2288 assert_eq!(
2289 dump(&c, id),
2290 "decl #2 f : int(int, int) function external defined\n params\n decl #0 a : int \
2291 object automatic defined\n decl #1 : int object automatic defined\n body\n \
2292 block\n return\n convert lvalue : int\n decl #0 a : int \
2293 lvalue\n"
2294 );
2295 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2296 }
2297
2298 #[test]
2299 fn a_name_declared_in_the_body_meets_the_parameter_of_the_same_name() {
2300 let mut f = Fixture::new();
2301 let int = f.int_specs();
2302 let a = f.param(int, Some("a"), &[]);
2303 let takes = f.takes(&[a]);
2304 let specs = f.int_specs();
2305 let shadow = f.object(specs, "a");
2306 let shadow = f.stmt(ast::Stmt::Decl(shadow));
2307 let body = f.block(&[shadow]);
2308 let specs = f.builtin(BuiltinSet::VOID);
2309 let decl = f.define(specs, "f", &[takes], body);
2310
2311 let mut c = f.checker();
2312 c.check_decl(decl);
2313
2314 assert_eq!(
2315 messages(&c),
2316 ["redeclaration of 'a' with no linkage", "previous definition of 'a' with type 'int'"]
2317 );
2318 }
2319
2320 #[test]
2321 fn a_block_inside_the_body_may_shadow_a_parameter() {
2322 let mut f = Fixture::new();
2323 let int = f.int_specs();
2324 let a = f.param(int, Some("a"), &[]);
2325 let takes = f.takes(&[a]);
2326 let specs = f.int_specs();
2327 let shadow = f.object(specs, "a");
2328 let shadow = f.stmt(ast::Stmt::Decl(shadow));
2329 let inner = f.block(&[shadow]);
2330 let body = f.block(&[inner]);
2331 let specs = f.builtin(BuiltinSet::VOID);
2332 let decl = f.define(specs, "f", &[takes], body);
2333
2334 let mut c = f.checker();
2335 c.check_decl(decl);
2336
2337 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2338 }
2339
2340 #[test]
2341 fn an_array_parameter_is_a_pointer_in_the_body_as_well_as_in_the_type() {
2342 let mut f = Fixture::new();
2343 let int = f.int_specs();
2344 let three = f.int(3);
2345 let a = f.param(int, Some("a"), &[array(three)]);
2346 let takes = f.takes(&[a]);
2347 let use_a = f.use_name("a");
2348 let stmt = f.stmt(ast::Stmt::Expr(use_a));
2349 let body = f.block(&[stmt]);
2350 let specs = f.builtin(BuiltinSet::VOID);
2351 let decl = f.define(specs, "f", &[takes], body);
2352
2353 let mut c = f.checker();
2354 let list = c.check_decl(decl);
2355
2356 let id = only(&c, list);
2357 assert_eq!(
2358 dump(&c, id),
2359 "decl #1 f : void(int *) function external defined\n params\n decl #0 a : \
2360 int * object automatic defined\n body\n block\n expr\n convert \
2361 lvalue : int *\n decl #0 a : int * lvalue\n"
2362 );
2363 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2364 }
2365
2366 #[test]
2367 fn a_qualifier_on_a_parameter_is_the_object_s_and_not_the_function_type_s() {
2368 let mut f = Fixture::new();
2369 let mut int = f.int_specs();
2370 int.quals = Quals::CONST;
2371 let a = f.param(int, Some("a"), &[]);
2372 let takes = f.takes(&[a]);
2373 let use_a = f.use_name("a");
2374 let stmt = f.stmt(ast::Stmt::Expr(use_a));
2375 let body = f.block(&[stmt]);
2376 let specs = f.builtin(BuiltinSet::VOID);
2377 let decl = f.define(specs, "f", &[takes], body);
2378
2379 let mut c = f.checker();
2380 let list = c.check_decl(decl);
2381
2382 let id = only(&c, list);
2385 assert_eq!(
2386 dump(&c, id),
2387 "decl #1 f : void(int) function external defined\n params\n decl #0 a : \
2388 const int object automatic defined\n body\n block\n expr\n \
2389 convert lvalue : int\n decl #0 a : const int lvalue\n"
2390 );
2391 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2392 }
2393
2394 #[test]
2395 fn the_body_answers_to_the_return_type_the_definition_was_written_with() {
2396 let mut f = Fixture::new();
2397 let ret = f.stmt(ast::Stmt::Return(None));
2398 let body = f.block(&[ret]);
2399 let specs = f.int_specs();
2400 let decl = f.define(specs, "f", &[function()], body);
2401
2402 let mut c = f.checker();
2403 c.check_decl(decl);
2404
2405 assert_eq!(
2406 messages(&c),
2407 ["'return' with no value, in function returning non-void", "declared here"]
2408 );
2409 }
2410
2411 #[test]
2412 fn a_declaration_and_a_definition_of_one_function_are_one_declaration() {
2413 let mut f = Fixture::new();
2414 let specs = f.builtin(BuiltinSet::VOID);
2415 let declared = f.var(specs, "f", &[function()], None);
2416 let body = f.block(&[]);
2417 let specs = f.builtin(BuiltinSet::VOID);
2418 let defined = f.define(specs, "f", &[function()], body);
2419
2420 let mut c = f.checker();
2421 let list = c.check_decl(declared);
2422 let first = only(&c, list);
2423 let list = c.check_decl(defined);
2424
2425 assert_eq!(only(&c, list), first);
2426 assert_eq!(
2427 dump(&c, first),
2428 "decl #0 f : void(void) function external defined\n body\n block\n"
2429 );
2430 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2431 }
2432
2433 #[test]
2434 fn a_function_definition_declared_typedef_is_an_error() {
2435 let mut f = Fixture::new();
2436 let mut specs = f.builtin(BuiltinSet::VOID);
2437 specs.storage = Some(StorageClass::Typedef);
2438 let body = f.block(&[]);
2439 let decl = f.define(specs, "f", &[function()], body);
2440
2441 let mut c = f.checker();
2442 c.check_decl(decl);
2443
2444 assert_eq!(message(&c), "function definition declared 'typedef'");
2445 }
2446
2447 #[test]
2448 fn a_function_definition_inside_a_function_is_refused_and_the_name_still_declared() {
2449 let mut f = Fixture::new();
2450 let empty = f.block(&[]);
2451 let specs = f.builtin(BuiltinSet::VOID);
2452 let nested = f.define(specs, "g", &[function()], empty);
2453 let nested = f.stmt(ast::Stmt::Decl(nested));
2454 let call = f.use_name("g");
2455 let call = f.stmt(ast::Stmt::Expr(call));
2456 let body = f.block(&[nested, call]);
2457 let specs = f.builtin(BuiltinSet::VOID);
2458 let decl = f.define(specs, "f", &[function()], body);
2459
2460 let mut c = f.checker();
2461 c.check_decl(decl);
2462
2463 assert_eq!(
2467 messages(&c),
2468 [
2469 "a function definition inside a function",
2470 "a nested function is called through a trampoline written on the stack, which no \
2471 target that enforces an unexecutable stack allows, so this compiler does not \
2472 have them and will not"
2473 ],
2474 "the mention of 'g' under the definition has to resolve, so that one definition is \
2475 one error"
2476 );
2477 }
2478
2479 #[test]
2483 fn an_old_style_definition_reads_the_declarations_written_under_its_list() {
2484 let mut f = Fixture::new();
2485 let int = f.int_specs();
2486 let a = f.param(int, Some("a"), &[]);
2487 let params = f.ast.add_param_list(&[a]);
2488 let old = Derived::Function { params, variadic: false, kind: ParamKind::Identifiers };
2489 let char_specs = f.builtin(BuiltinSet::CHAR);
2490 let written = f.object(char_specs, "a");
2491 let body = f.block(&[]);
2492 let specs = f.builtin(BuiltinSet::VOID);
2493 let decl = f.define_taking(specs, "f", &[old], &[written], body);
2494
2495 let mut c = f.checker();
2496 let list = c.check_decl(decl);
2497
2498 assert_eq!(messages(&c), Vec::<String>::new());
2499 let text = dump(&c, only(&c, list));
2500 assert!(text.contains("f : void(int) function"), "{text}");
2501 assert!(text.contains("a : char object automatic defined"), "{text}");
2503 }
2504
2505 #[test]
2508 fn a_name_in_an_identifier_list_that_nothing_declares_says_so() {
2509 let mut f = Fixture::new();
2510 let int = f.int_specs();
2511 let a = f.param(int, Some("a"), &[]);
2512 let params = f.ast.add_param_list(&[a]);
2513 let old = Derived::Function { params, variadic: false, kind: ParamKind::Identifiers };
2514 let body = f.block(&[]);
2515 let specs = f.builtin(BuiltinSet::VOID);
2516 let decl = f.define(specs, "f", &[old], body);
2517
2518 let mut c = f.checker();
2519 c.check_decl(decl);
2520
2521 assert_eq!(message(&c), "type of 'a' defaults to 'int'");
2522 }
2523
2524 #[test]
2525 fn a_deduced_type_is_the_type_the_initializer_would_have_where_it_is_used() {
2526 let mut f = Fixture::new();
2527 let one = f.int(1);
2528 let decl = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(one));
2529
2530 let mut c = f.checker();
2531 let list = c.check_decl(decl);
2532
2533 let id = only(&c, list);
2534 assert_eq!(
2535 dump(&c, id),
2536 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
2537 );
2538 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2539 }
2540
2541 #[test]
2542 fn a_deduced_type_is_the_one_a_use_has_so_an_array_deduces_a_pointer() {
2543 let mut f = Fixture::new();
2544 let three = f.int(3);
2545 let ints = f.int_specs();
2546 let array = f.var(ints, "a", &[array(three)], None);
2547 let a = f.use_name("a");
2548 let decl = f.var(f.deduced(ast::Deduction::AutoType), "p", &[], Some(a));
2549
2550 let mut c = f.checker();
2551 c.check_decl(array);
2552 c.scopes.push();
2553 let list = c.check_decl(decl);
2554
2555 let id = only(&c, list);
2556 assert!(dump(&c, id).starts_with("decl #1 p : int *"), "{}", dump(&c, id));
2557 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2558 }
2559
2560 #[test]
2561 fn a_deduced_type_drops_the_initializers_qualifiers_and_takes_the_declarations() {
2562 let mut f = Fixture::new();
2563 let mut ints = f.int_specs();
2564 ints.quals = Quals::CONST;
2565 let one = f.int(1);
2566 let source = f.var(ints, "c", &[], Some(one));
2567 let c1 = f.use_name("c");
2569 let plain = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(c1));
2570 let c2 = f.use_name("c");
2571 let mut qualified = f.deduced(ast::Deduction::Auto);
2572 qualified.quals = Quals::CONST;
2573 let kept = f.var(qualified, "y", &[], Some(c2));
2574
2575 let mut c = f.checker();
2576 c.check_decl(source);
2577 c.scopes.push();
2578 let list = c.check_decl(plain);
2579 let plain = only(&c, list);
2580 let list = c.check_decl(kept);
2581 let kept = only(&c, list);
2582
2583 assert!(dump(&c, plain).starts_with("decl #1 x : int "), "{}", dump(&c, plain));
2584 assert!(dump(&c, kept).starts_with("decl #2 y : const int "), "{}", dump(&c, kept));
2585 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2586 }
2587
2588 #[test]
2589 fn a_deduced_type_needs_a_declarator_that_is_no_more_than_a_name() {
2590 let mut f = Fixture::new();
2591 let one = f.int(1);
2593 let c23 = f.var(f.deduced(ast::Deduction::Auto), "p", &[pointer()], Some(one));
2594 let two = f.int(2);
2595 let gnu = f.var(f.deduced(ast::Deduction::AutoType), "q", &[pointer()], Some(two));
2596
2597 let mut c = f.checker();
2598 c.check_decl(c23);
2599 c.check_decl(gnu);
2600
2601 assert_eq!(
2603 messages(&c),
2604 [
2605 "'auto' requires a plain identifier, possibly with attributes, as declarator",
2606 "'__auto_type' requires a plain identifier as declarator",
2607 ]
2608 );
2609 }
2610
2611 #[test]
2612 fn a_deduced_type_needs_something_to_deduce_from() {
2613 let mut f = Fixture::new();
2614 let decl = f.var(f.deduced(ast::Deduction::AutoType), "x", &[], None);
2615
2616 let mut c = f.checker();
2617 c.check_decl(decl);
2618
2619 assert_eq!(message(&c), "'__auto_type' requires an initialized data declaration");
2620 }
2621
2622 #[test]
2623 fn one_initializer_deduces_one_type_so_a_second_declarator_is_refused() {
2624 let mut f = Fixture::new();
2625 let one = f.int(1);
2628 let two = f.int(2);
2629 let x = f.declarator("x", &[]);
2630 let y = f.declarator("y", &[]);
2631 let items: Vec<ast::InitDeclarator> = [(x, one), (y, two)]
2632 .into_iter()
2633 .map(|(declarator, value)| ast::InitDeclarator {
2634 declarator,
2635 init: Some(f.ast.add_init(ast::Init::Expr(value))),
2636 asm_label: None,
2637 attrs: AttrList::EMPTY,
2638 span: Span::DUMMY,
2639 })
2640 .collect();
2641 let declarators = f.ast.add_init_declarator_list(&items);
2642 let specs = f.specs(f.deduced(ast::Deduction::Auto));
2643 let decl = f.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY);
2644
2645 let mut c = f.checker();
2646 let list = c.check_decl(decl);
2647
2648 let id = only(&c, list);
2649 assert_eq!(
2650 dump(&c, id),
2651 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
2652 );
2653 assert_eq!(message(&c), "'auto' may only be used with a single declarator");
2654 }
2655
2656 #[test]
2657 fn a_function_definition_deduces_nothing_because_it_has_no_initializer() {
2658 let mut f = Fixture::new();
2659 let body = f.block(&[]);
2660 let decl = f.define(f.deduced(ast::Deduction::Auto), "f", &[function()], body);
2661
2662 let mut c = f.checker();
2663 let list = c.check_decl(decl);
2664
2665 assert!(c.tast[list].is_empty());
2666 assert_eq!(
2667 message(&c),
2668 "'auto' requires a plain identifier, possibly with attributes, as declarator"
2669 );
2670 }
2671
2672 #[test]
2673 fn a_name_with_no_type_until_its_initializer_is_checked_may_not_be_used_in_it() {
2674 let mut f = Fixture::new();
2675 let x = f.use_name("x");
2678 let deduced = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(x));
2679 let y = f.use_name("y");
2680 let mut ints = f.int_specs();
2681 ints.constexpr = true;
2682 let constant = f.var(ints, "y", &[], Some(y));
2683
2684 let mut c = f.checker();
2685 c.scopes.push();
2686 c.check_decl(deduced);
2687 c.check_decl(constant);
2688
2689 assert_eq!(
2692 messages(&c),
2693 [
2694 "underspecified 'x' referenced in its initializer",
2695 "underspecified 'y' referenced in its initializer",
2696 ]
2697 );
2698 }
2699}