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