1use rucc_ast::{self as ast, AlignSpec, FuncSpecs, StorageClass};
35use rucc_base::Symbol;
36use rucc_diag::{Diagnostic, Span};
37use rucc_types::{ArrayLen, TypeId, TypeKind};
38use rucc_types::{compatible, composite, is_complete, is_function, is_void, layout};
39
40use crate::check::Checker;
41use crate::decl::{
42 Decl, DeclId, DeclKind, DeclList, Definition, InitList, Linkage, StorageDuration,
43};
44use crate::scope::Binding;
45
46#[derive(Debug, Clone, Copy)]
48struct Declared {
49 name: Symbol,
51 ty: TypeId,
53 kind: DeclKind,
55 linkage: Linkage,
57 duration: StorageDuration,
59 state: Definition,
61 alignment: Option<u32>,
63 is_extern: bool,
67 span: Span,
69}
70
71impl Checker<'_> {
72 pub fn check_decl(&mut self, id: ast::DeclId) -> DeclList {
77 let span = self.ast.decl_span(id);
78 match self.ast[id] {
79 ast::Decl::Error => self.tast.add_decl_refs(&[]),
80 ast::Decl::Var { specs, declarators } => self.var(specs, declarators),
81 ast::Decl::StaticAssert { cond, message } => {
82 self.static_assert(cond, message, span);
83 self.tast.add_decl_refs(&[])
84 }
85 ast::Decl::Function { specs, declarator, params, body } => {
86 match self.function(specs, declarator, params, body) {
87 Some(id) => self.tast.add_decl_refs(&[id]),
88 None => self.tast.add_decl_refs(&[]),
89 }
90 }
91 ast::Decl::Asm(_) => {
92 self.declaration_unsupported("an assembler statement at file scope", span);
93 self.tast.add_decl_refs(&[])
94 }
95 ast::Decl::Attributes(_) => self.tast.add_decl_refs(&[]),
98 }
99 }
100
101 fn var(&mut self, specs: ast::DeclSpecsId, declarators: ast::InitDeclaratorList) -> DeclList {
103 let mut items = self.ast[declarators].to_vec();
104 if items.is_empty() {
105 self.empty_declaration(specs);
106 return self.tast.add_decl_refs(&[]);
107 }
108 let node = self.ast[specs];
109 if let Some(which) = node.deduces() {
110 if items.len() > 1 {
115 let spelled = which.spelling();
116 self.report(
117 Diagnostic::error(
118 format!("'{spelled}' may only be used with a single declarator"),
119 node.span,
120 )
121 .with_code("E0651"),
122 );
123 items.truncate(1);
124 }
125 }
126 let mut declared = Vec::with_capacity(items.len());
127 for item in items {
128 if let Some(id) = self.init_declarator(specs, item) {
129 declared.push(id);
130 }
131 }
132 self.tast.add_decl_refs(&declared)
133 }
134
135 fn function(
141 &mut self,
142 specs: ast::DeclSpecsId,
143 declarator: ast::DeclaratorId,
144 declarations: ast::DeclList,
145 body: ast::StmtId,
146 ) -> Option<DeclId> {
147 let node = self.ast[declarator];
148 let span = node.name_span;
149 let (params, kind) = match self.ast[node.derived].first() {
150 Some(&ast::Derived::Function { params, kind, .. }) => (params, kind),
151 _ => return None,
154 };
155 if kind == ast::ParamKind::Identifiers && !(params.is_empty() && declarations.is_empty()) {
159 self.declaration_unsupported("an old-style function definition", span);
160 return None;
161 }
162 if let Some(which) = self.ast[specs].deduces() {
166 self.not_plain(which, span);
167 return None;
168 }
169 let ty = self.declared_type(specs, declarator);
170 let name = node.name?;
171 let specs = self.ast[specs];
172 if specs.is_typedef() {
173 self.report(
174 Diagnostic::error("function definition declared 'typedef'", span)
175 .with_code("E0589"),
176 );
177 return None;
178 }
179 let (linkage, duration) = self.placement(&specs, DeclKind::Function, name, span);
180 let alignment = match specs.align {
181 Some(align) => self.alignment(align, ty, DeclKind::Function, name, span),
182 None => None,
183 };
184 let declared = Declared {
185 name,
186 ty,
187 kind: DeclKind::Function,
188 linkage,
189 duration,
190 state: Definition::Defined,
191 alignment,
192 is_extern: specs.storage == Some(StorageClass::Extern),
193 span,
194 };
195 let id = self.merge(declared);
196 let (stmt, params) = self.function_body(ty, span, params, body);
197 let mut node = self.tast[id].clone();
198 node.params = params;
199 node.body = Some(stmt);
200 self.tast.set_decl(id, node);
201 Some(id)
202 }
203
204 fn function_body(
212 &mut self,
213 ty: TypeId,
214 span: Span,
215 params: ast::ParamList,
216 body: ast::StmtId,
217 ) -> (crate::stmt::StmtId, DeclList) {
218 let ret = match self.types.kind(self.types.canonical(ty)) {
219 TypeKind::Function(signature) => self.types.signature(signature).ret,
220 _ => self.int(),
223 };
224 self.scopes.push();
225 let params = self.prototype_params(params);
226 for &decl in ¶ms {
227 if let Some(name) = self.tast[decl].name {
228 self.scopes.declare(name, Binding::Decl(decl));
229 }
230 }
231 let params = self.tast.add_decl_refs(¶ms);
232 let previous = self.open_body(ret, span);
233 let stmt = self.body_block(body);
234 self.close_body(previous);
235 self.scopes.pop();
236 (stmt, params)
237 }
238
239 fn empty_declaration(&mut self, specs: ast::DeclSpecsId) {
245 self.declared_specs(specs);
246 let node = self.ast[specs];
247 match node.ty {
248 ast::TypeSpec::Record { tag: None, fields: Some(_), .. } => {
251 self.report(
252 Diagnostic::warning(
253 "unnamed struct/union that defines no instances",
254 node.span,
255 )
256 .with_code("E0612"),
257 );
258 }
259 ast::TypeSpec::Record { .. } | ast::TypeSpec::Enum { .. } => {
260 if !node.quals.is_none() {
261 self.report(
262 Diagnostic::warning(
263 "useless type qualifier in empty declaration",
264 node.span,
265 )
266 .with_code("E0611"),
267 );
268 }
269 }
270 _ => {
271 self.report(
272 Diagnostic::warning("useless type name in empty declaration", node.span)
273 .with_code("E0610"),
274 );
275 }
276 }
277 }
278
279 fn init_declarator(
281 &mut self,
282 specs: ast::DeclSpecsId,
283 item: ast::InitDeclarator,
284 ) -> Option<DeclId> {
285 let deduces = self.ast[specs].deduces();
288 let deducible = deduces.is_some_and(|which| self.deducible(which, item));
289 let ty =
290 if deduces.is_some() { self.int() } else { self.declared_type(specs, item.declarator) };
291 let node = self.ast[item.declarator];
292 let name = node.name?;
295 let span = node.name_span;
296 let specs = self.ast[specs];
297 if specs.is_typedef() {
298 self.typedef(name, ty, &specs, item, span);
299 return None;
300 }
301 let kind = if is_function(&self.types, ty) { DeclKind::Function } else { DeclKind::Object };
302 let (linkage, duration) = self.placement(&specs, kind, name, span);
303 let state = self.definition_state(&specs, kind, item.init.is_some());
304 self.check_initializer_placement(&specs, item.init.is_some(), name, span);
305 self.check_specifiers(&specs, kind, name, span);
306 let alignment = match specs.align {
307 Some(align) => self.alignment(align, ty, kind, name, span),
308 None => None,
309 };
310 let mut declared = Declared {
311 name,
312 ty,
313 kind,
314 linkage,
315 duration,
316 state,
317 alignment,
318 is_extern: specs.storage == Some(StorageClass::Extern),
319 span,
320 };
321 let id = self.merge(declared);
322 let mut worked = true;
325 let init = if deduces.is_some() && !deducible { None } else { item.init };
328 if let Some(init) = init {
329 let constant = specs.storage == Some(StorageClass::Constexpr);
330 if deduces.is_some() || constant {
334 self.underspecified.push(id);
335 }
336 let deduce = deduces.map(|_| specs.quals);
337 let result = self.initializer(id, init, constant, deduce, span);
338 if deduces.is_some() || constant {
339 self.underspecified.pop();
340 }
341 match result {
342 Some((entries, ty)) => {
343 let mut node = self.tast[id].clone();
346 node.init = Some(entries);
347 node.ty = ty;
348 self.tast.set_decl(id, node);
349 }
350 None => worked = false,
351 }
352 }
353 if kind == DeclKind::Object && worked {
354 declared.ty = self.tast[id].ty;
357 self.check_storage_size(&declared);
358 }
359 Some(id)
360 }
361
362 fn typedef(
364 &mut self,
365 name: Symbol,
366 ty: TypeId,
367 specs: &ast::DeclSpecs,
368 item: ast::InitDeclarator,
369 span: Span,
370 ) {
371 if item.init.is_some() {
372 let spelled = self.text(name).to_owned();
373 self.report(
374 Diagnostic::error(
375 format!("typedef '{spelled}' is initialized (use '__typeof__' instead)"),
376 span,
377 )
378 .with_code("E0600"),
379 );
380 }
381 if specs.align.is_some() {
382 let spelled = self.text(name).to_owned();
383 self.report(
384 Diagnostic::error(format!("alignment specified for typedef '{spelled}'"), span)
385 .with_code("E0604"),
386 );
387 }
388 match self.scopes.lookup_here(name) {
389 Some(Binding::Typedef(previous)) if compatible(&self.types, previous, ty) => {}
392 Some(Binding::Typedef(_)) => {
393 self.conflicting_types(name, ty, None, span);
394 return;
395 }
396 Some(Binding::Decl(previous)) => {
397 self.different_kind(name, Some(previous), span);
398 return;
399 }
400 Some(Binding::Enumerator { .. }) => {
401 self.different_kind(name, None, span);
402 return;
403 }
404 None => {}
405 }
406 self.declare_typedef(name, ty);
407 }
408
409 fn placement(
411 &mut self,
412 specs: &ast::DeclSpecs,
413 kind: DeclKind,
414 name: Symbol,
415 span: Span,
416 ) -> (Linkage, StorageDuration) {
417 let file_scope = self.scopes.at_file_scope();
418 let storage = specs.storage;
419 if kind == DeclKind::Function {
420 let invalid = match storage {
424 Some(StorageClass::Auto | StorageClass::Register | StorageClass::Constexpr) => true,
425 Some(StorageClass::Static) => !file_scope,
426 _ => false,
427 };
428 if invalid {
429 let spelled = self.text(name).to_owned();
430 self.report(
431 Diagnostic::error(
432 format!("invalid storage class for function '{spelled}'"),
433 span,
434 )
435 .with_code("E0596"),
436 );
437 }
438 let linkage = if storage == Some(StorageClass::Static) && file_scope {
439 Linkage::Internal
440 } else {
441 Linkage::External
442 };
443 return (linkage, StorageDuration::Static);
444 }
445 if file_scope {
446 let spelled = self.text(name).to_owned();
447 match storage {
448 Some(StorageClass::Auto) => {
449 self.report(
450 Diagnostic::error(
451 format!("file-scope declaration of '{spelled}' specifies 'auto'"),
452 span,
453 )
454 .with_code("E0594"),
455 );
456 }
457 Some(StorageClass::Register) => {
461 self.report(
462 Diagnostic::error(
463 format!("register name not specified for '{spelled}'"),
464 span,
465 )
466 .with_code("E0595"),
467 );
468 }
469 _ => {}
470 }
471 let linkage = match storage {
472 Some(StorageClass::Static | StorageClass::Constexpr) => Linkage::Internal,
473 _ => Linkage::External,
474 };
475 let duration =
476 if specs.thread_local { StorageDuration::Thread } else { StorageDuration::Static };
477 return (linkage, duration);
478 }
479 let stored =
482 if specs.thread_local { StorageDuration::Thread } else { StorageDuration::Static };
483 match storage {
484 Some(StorageClass::Extern) => (Linkage::External, stored),
485 Some(StorageClass::Static) => (Linkage::None, stored),
486 _ if specs.thread_local => {
487 let spelled = self.text(name).to_owned();
488 self.report(
489 Diagnostic::error(
490 format!(
491 "function-scope '{spelled}' implicitly auto and declared \
492 '_Thread_local'"
493 ),
494 span,
495 )
496 .with_code("E0597"),
497 );
498 (Linkage::None, StorageDuration::Thread)
499 }
500 _ => (Linkage::None, StorageDuration::Automatic),
501 }
502 }
503
504 fn definition_state(
506 &mut self,
507 specs: &ast::DeclSpecs,
508 kind: DeclKind,
509 has_init: bool,
510 ) -> Definition {
511 if kind == DeclKind::Function {
512 return Definition::Declared;
513 }
514 if has_init {
515 return Definition::Defined;
516 }
517 if specs.storage == Some(StorageClass::Extern) {
518 return Definition::Declared;
519 }
520 if self.scopes.at_file_scope() { Definition::Tentative } else { Definition::Defined }
523 }
524
525 fn check_initializer_placement(
527 &mut self,
528 specs: &ast::DeclSpecs,
529 has_init: bool,
530 name: Symbol,
531 span: Span,
532 ) {
533 let spelled = self.text(name).to_owned();
534 if specs.storage == Some(StorageClass::Extern) && has_init {
535 let diagnostic = if self.scopes.at_file_scope() {
538 Diagnostic::warning(format!("'{spelled}' initialized and declared 'extern'"), span)
539 .with_code("E0599")
540 } else {
541 Diagnostic::error(format!("'{spelled}' has both 'extern' and initializer"), span)
542 .with_code("E0598")
543 };
544 self.report(diagnostic);
545 }
546 if specs.storage == Some(StorageClass::Constexpr) && !has_init {
547 self.report(
548 Diagnostic::error("'constexpr' requires an initialized data declaration", span)
549 .with_code("E0617"),
550 );
551 }
552 }
553
554 fn check_specifiers(
556 &mut self,
557 specs: &ast::DeclSpecs,
558 kind: DeclKind,
559 name: Symbol,
560 span: Span,
561 ) {
562 if kind == DeclKind::Function || specs.func.is_none() {
563 return;
564 }
565 let spelled = self.text(name).to_owned();
566 let word = if specs.func.has(FuncSpecs::INLINE) { "inline" } else { "_Noreturn" };
567 self.report(
568 Diagnostic::warning(format!("variable '{spelled}' declared '{word}'"), span)
569 .with_code("E0609"),
570 );
571 }
572
573 fn check_storage_size(&mut self, declared: &Declared) {
575 if declared.state == Definition::Declared {
578 return;
579 }
580 let spelled = self.text(declared.name).to_owned();
581 if self.is_variable_length(declared.ty) {
582 if declared.duration != StorageDuration::Automatic {
583 self.report(
584 Diagnostic::error(
585 format!("storage size of '{spelled}' isn't constant"),
586 declared.span,
587 )
588 .with_code("E0602"),
589 );
590 }
591 return;
592 }
593 if is_complete(&self.types, declared.ty) {
594 return;
595 }
596 if declared.state == Definition::Tentative && self.is_unsized_array(declared.ty) {
599 return;
600 }
601 let void = is_void(&self.types, declared.ty) && !self.scopes.at_file_scope();
604 let diagnostic = if void {
605 Diagnostic::error(format!("variable or field '{spelled}' declared void"), declared.span)
606 .with_code("E0603")
607 } else {
608 Diagnostic::error(format!("storage size of '{spelled}' isn't known"), declared.span)
609 .with_code("E0601")
610 };
611 self.report(diagnostic);
612 }
613
614 fn alignment(
616 &mut self,
617 align: AlignSpec,
618 ty: TypeId,
619 kind: DeclKind,
620 name: Symbol,
621 span: Span,
622 ) -> Option<u32> {
623 let spelled = self.text(name).to_owned();
624 if kind == DeclKind::Function {
625 self.report(
626 Diagnostic::error(format!("alignment specified for function '{spelled}'"), span)
627 .with_code("E0605"),
628 );
629 return None;
630 }
631 let requested = match align {
632 AlignSpec::Type(named) => {
633 let named = self.type_name(named);
634 i128::from(layout(&self.types, named, self.cx.target).ok()?.align)
635 }
636 AlignSpec::Expr(expr) => {
637 let value = self.expr(expr);
638 match self.eval_integer(value) {
639 Ok(value) => value,
640 Err(failed) => {
641 if !failed.poisoned {
642 self.report(
643 Diagnostic::error(
644 "requested alignment is not an integer constant",
645 self.tast.expr_span(failed.at),
646 )
647 .with_code("E0606"),
648 );
649 }
650 return None;
651 }
652 }
653 }
654 };
655 if requested == 0 {
658 return None;
659 }
660 if requested < 0 || requested & (requested - 1) != 0 {
661 self.report(
662 Diagnostic::error(
663 format!("requested alignment '{requested}' is not a positive power of 2"),
664 span,
665 )
666 .with_code("E0607"),
667 );
668 return None;
669 }
670 let natural = layout(&self.types, ty, self.cx.target).map_or(1, |l| l.align);
671 if requested < i128::from(natural) {
672 self.report(
673 Diagnostic::error(
674 format!("'_Alignas' specifiers cannot reduce alignment of '{spelled}'"),
675 span,
676 )
677 .with_code("E0608"),
678 );
679 return None;
680 }
681 u32::try_from(requested).ok()
682 }
683
684 fn merge(&mut self, declared: Declared) -> DeclId {
686 let binding = match self.scopes.lookup_here(declared.name) {
690 Some(binding) => Some(binding),
691 None if declared.linkage != Linkage::None => self.scopes.lookup(declared.name),
692 None => None,
693 };
694 let previous = match binding {
695 Some(Binding::Decl(id)) => id,
696 Some(Binding::Typedef(_)) => {
697 self.different_kind(declared.name, None, declared.span);
698 return self.declare(declared);
699 }
700 Some(Binding::Enumerator { .. }) => {
701 self.different_kind(declared.name, None, declared.span);
702 return self.declare(declared);
703 }
704 None => return self.declare(declared),
705 };
706 let node = self.tast[previous].clone();
707 if node.kind != declared.kind {
708 self.different_kind(declared.name, Some(previous), declared.span);
709 return self.declare(declared);
710 }
711 if !self.check_linkage(&node, &declared, previous) {
712 return self.declare(declared);
713 }
714 if !compatible(&self.types, node.ty, declared.ty) {
715 self.conflicting_types(declared.name, declared.ty, Some(previous), declared.span);
716 return previous;
717 }
718 if node.state == Definition::Defined && declared.state == Definition::Defined {
719 let spelled = self.text(declared.name).to_owned();
720 let (note, at) = self.previous_note(previous);
721 self.report(
722 Diagnostic::error(format!("redefinition of '{spelled}'"), declared.span)
723 .with_code("E0588")
724 .note(note, at),
725 );
726 return previous;
727 }
728 let ty = composite(&mut self.types, node.ty, declared.ty).unwrap_or(declared.ty);
729 let merged = Decl {
730 ty,
731 linkage: if declared.is_extern { node.linkage } else { declared.linkage },
734 state: stronger(node.state, declared.state),
735 alignment: node.alignment.max(declared.alignment),
736 ..node
737 };
738 self.tast.set_decl(previous, merged);
739 self.scopes.declare(declared.name, Binding::Decl(previous));
740 previous
741 }
742
743 fn check_linkage(&mut self, node: &Decl, declared: &Declared, previous: DeclId) -> bool {
745 let spelled = self.text(declared.name).to_owned();
746 let message = match (node.linkage, declared.linkage) {
747 (Linkage::None, Linkage::None) => {
748 format!("redeclaration of '{spelled}' with no linkage")
749 }
750 (Linkage::None, _) => {
751 format!("extern declaration of '{spelled}' follows declaration with no linkage")
752 }
753 (_, Linkage::None) => {
754 format!("declaration of '{spelled}' with no linkage follows extern declaration")
755 }
756 (Linkage::External, Linkage::Internal) => {
757 format!("static declaration of '{spelled}' follows non-static declaration")
758 }
759 (Linkage::Internal, Linkage::External) if !declared.is_extern => {
762 format!("non-static declaration of '{spelled}' follows static declaration")
763 }
764 _ => return true,
765 };
766 let (note, at) = self.previous_note(previous);
767 self.report(Diagnostic::error(message, declared.span).with_code("E0592").note(note, at));
768 false
769 }
770
771 fn declare(&mut self, declared: Declared) -> DeclId {
773 let node = Decl {
774 name: Some(declared.name),
775 ty: declared.ty,
776 kind: declared.kind,
777 linkage: declared.linkage,
778 duration: declared.duration,
779 state: declared.state,
780 alignment: declared.alignment,
781 init: None,
782 params: DeclList::EMPTY,
783 body: None,
784 };
785 let id = self.tast.decl(node, declared.span);
786 self.scopes.declare(declared.name, Binding::Decl(id));
787 if self.scopes.at_file_scope() {
788 self.tast.add_top_level(id);
789 }
790 id
791 }
792
793 fn initializer(
799 &mut self,
800 decl: DeclId,
801 init: ast::InitId,
802 constant: bool,
803 deduce: Option<ast::Quals>,
804 span: Span,
805 ) -> Option<(InitList, TypeId)> {
806 let node = &self.tast[decl];
807 let (ty, kind, name, duration) = (node.ty, node.kind, node.name, node.duration);
808 if kind == DeclKind::Function {
809 let spelled = name.map_or_else(String::new, |name| self.text(name).to_owned());
810 self.report(
811 Diagnostic::error(
812 format!("function '{spelled}' is initialized like a variable"),
813 span,
814 )
815 .with_code("E0615"),
816 );
817 return None;
818 }
819 let is_static = duration != StorageDuration::Automatic;
820 match deduce {
821 Some(quals) => self.init_deduced(name, is_static, init, constant, quals, span),
822 None => self.init_object(ty, name, is_static, init, constant, span),
823 }
824 }
825
826 fn not_plain(&mut self, which: ast::Deduction, span: Span) {
831 let spelled = which.spelling();
832 let allowed = match which {
833 ast::Deduction::Auto => ", possibly with attributes,",
834 ast::Deduction::AutoType => "",
835 };
836 self.report(
837 Diagnostic::error(
838 format!("'{spelled}' requires a plain identifier{allowed} as declarator"),
839 span,
840 )
841 .with_code("E0651"),
842 );
843 }
844
845 fn deducible(&mut self, which: ast::Deduction, item: ast::InitDeclarator) -> bool {
852 let spelled = which.spelling();
853 let node = self.ast[item.declarator];
854 let span = if node.name.is_some() { node.name_span } else { node.span };
855 if !self.ast[node.derived].is_empty() {
856 self.not_plain(which, span);
857 return false;
858 }
859 if item.init.is_none() {
860 self.report(
861 Diagnostic::error(
862 format!("'{spelled}' requires an initialized data declaration"),
863 span,
864 )
865 .with_code("E0651"),
866 );
867 return false;
868 }
869 true
870 }
871
872 fn static_assert(&mut self, cond: ast::ExprId, message: Option<ast::StrId>, span: Span) {
874 let cond = self.expr(cond);
875 let cond = self.value(cond);
876 if self.is_poisoned(cond) {
877 return;
878 }
879 let value = match self.eval_integer(cond) {
880 Ok(value) => value,
881 Err(failed) => {
882 if !failed.poisoned {
883 self.report(
884 Diagnostic::error(
885 "expression in static assertion is not constant",
886 self.tast.expr_span(failed.at),
887 )
888 .with_code("E0614"),
889 );
890 }
891 return;
892 }
893 };
894 if value != 0 {
895 return;
896 }
897 let message = match message {
898 Some(id) => format!("static assertion failed: {}", self.quoted(id)),
899 None => "static assertion failed".to_owned(),
900 };
901 self.report(Diagnostic::error(message, span).with_code("E0613"));
902 }
903
904 fn conflicting_types(
906 &mut self,
907 name: Symbol,
908 ty: TypeId,
909 previous: Option<DeclId>,
910 span: Span,
911 ) {
912 let spelled = self.text(name).to_owned();
913 let written = self.spell(ty);
914 let mut diagnostic =
915 Diagnostic::error(format!("conflicting types for '{spelled}'; have '{written}'"), span)
916 .with_code("E0586");
917 if let Some(previous) = previous {
918 let (note, at) = self.previous_note(previous);
919 diagnostic = diagnostic.note(note, at);
920 }
921 self.report(diagnostic);
922 }
923
924 fn different_kind(&mut self, name: Symbol, previous: Option<DeclId>, span: Span) {
926 let spelled = self.text(name).to_owned();
927 let mut diagnostic =
928 Diagnostic::error(format!("'{spelled}' redeclared as different kind of symbol"), span)
929 .with_code("E0587");
930 if let Some(previous) = previous {
931 let (note, at) = self.previous_note(previous);
932 diagnostic = diagnostic.note(note, at);
933 }
934 self.report(diagnostic);
935 }
936
937 fn previous_note(&self, id: DeclId) -> (String, Span) {
943 let node = &self.tast[id];
944 let word = if node.state == Definition::Defined { "definition" } else { "declaration" };
945 let name = node.name.map_or("", |name| self.text(name));
946 let ty = self.spell(node.ty);
947 (format!("previous {word} of '{name}' with type '{ty}'"), self.tast.decl_span(id))
948 }
949
950 fn quoted(&self, id: ast::StrId) -> String {
952 let mut out = String::from("\"");
953 for &element in &self.ast[id].elements {
954 match char::from_u32(element) {
955 Some('"') => out.push_str("\\\""),
956 Some('\\') => out.push_str("\\\\"),
957 Some('\n') => out.push_str("\\n"),
958 Some(c) if !c.is_control() => out.push(c),
959 _ => out.push_str(&format!("\\x{element:x}")),
960 }
961 }
962 out.push('"');
963 out
964 }
965
966 pub(in crate::check) fn is_unsized_array(&self, ty: TypeId) -> bool {
968 matches!(
969 self.types.kind(self.types.canonical(ty)),
970 TypeKind::Array { len: ArrayLen::Unknown, .. }
971 )
972 }
973
974 fn declaration_unsupported(&mut self, what: &str, span: Span) {
976 self.report(
977 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
978 );
979 }
980}
981
982fn stronger(a: Definition, b: Definition) -> Definition {
984 let rank = |state| match state {
985 Definition::Declared => 0,
986 Definition::Tentative => 1,
987 Definition::Defined => 2,
988 };
989 if rank(a) >= rank(b) { a } else { b }
990}
991
992#[cfg(test)]
993mod tests {
994 use rucc_ast::{
995 ArraySize, AttrList, Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId,
996 Derived, ParamKind, ParamList, Quals, RecordKind, TypeSpec,
997 };
998 use rucc_base::Interner;
999 use rucc_diag::Span;
1000 use rucc_lex::{Encoding, IntConstant, IntConstantType, Remarks, StringLiteral};
1001 use rucc_session::Std;
1002 use rucc_target::{TargetInfo, Triple};
1003 use rucc_types::IntKind;
1004
1005 use super::*;
1006 use crate::check::Context;
1007 use crate::print::Printer;
1008
1009 struct Fixture {
1014 ast: rucc_ast::Ast,
1015 names: Interner,
1016 target: TargetInfo,
1017 }
1018
1019 impl Fixture {
1020 fn new() -> Fixture {
1021 let target =
1022 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
1023 Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1024 }
1025
1026 fn name(&mut self, text: &str) -> Symbol {
1027 self.names.intern(text)
1028 }
1029
1030 fn int_specs(&self) -> DeclSpecs {
1032 self.builtin(BuiltinSet::INT)
1033 }
1034
1035 fn deduced(&self, which: ast::Deduction) -> DeclSpecs {
1037 let mut specs = DeclSpecs::empty(Span::DUMMY);
1038 specs.ty = TypeSpec::Auto(which);
1039 specs
1040 }
1041
1042 fn builtin(&self, keyword: BuiltinSet) -> DeclSpecs {
1043 let mut specs = DeclSpecs::empty(Span::DUMMY);
1044 let builtin = Builtin::NONE.add(keyword).expect("a keyword written once");
1045 specs.ty = TypeSpec::Builtin(builtin);
1046 specs
1047 }
1048
1049 fn record(&mut self, tag: Option<&str>, fields: bool) -> DeclSpecs {
1051 let tag = tag.map(|tag| self.name(tag));
1052 let fields = fields.then(|| self.ast.add_member_list(&[]));
1053 let mut specs = DeclSpecs::empty(Span::DUMMY);
1054 specs.ty =
1055 TypeSpec::Record { kind: RecordKind::Struct, tag, fields, attrs: AttrList::EMPTY };
1056 specs
1057 }
1058
1059 fn declarator(&mut self, name: &str, derived: &[Derived]) -> DeclaratorId {
1060 let name = self.name(name);
1061 let derived = self.ast.add_derived_list(derived);
1062 self.ast.add_declarator(Declarator {
1063 name: Some(name),
1064 name_span: Span::DUMMY,
1065 derived,
1066 span: Span::DUMMY,
1067 })
1068 }
1069
1070 fn int(&mut self, value: u128) -> ast::ExprId {
1071 let ty = IntConstantType::Standard(IntKind::Int);
1072 let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1073 self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1074 }
1075
1076 fn use_name(&mut self, text: &str) -> ast::ExprId {
1077 let name = self.name(text);
1078 self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1079 }
1080
1081 fn string(&mut self, text: &str) -> ast::StrId {
1082 let elements = text.chars().map(|c| c as u32).collect();
1083 self.ast.add_string(StringLiteral {
1084 elements,
1085 encoding: Encoding::Plain,
1086 remarks: Remarks::default(),
1087 })
1088 }
1089
1090 fn var(
1092 &mut self,
1093 specs: DeclSpecs,
1094 name: &str,
1095 derived: &[Derived],
1096 init: Option<ast::ExprId>,
1097 ) -> ast::DeclId {
1098 let declarator = self.declarator(name, derived);
1099 let init = init.map(|expr| self.ast.add_init(ast::Init::Expr(expr)));
1100 let item = ast::InitDeclarator {
1101 declarator,
1102 init,
1103 asm_label: None,
1104 attrs: AttrList::EMPTY,
1105 span: Span::DUMMY,
1106 };
1107 let declarators = self.ast.add_init_declarator_list(&[item]);
1108 let specs = self.specs(specs);
1109 self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1110 }
1111
1112 fn object(&mut self, specs: DeclSpecs, name: &str) -> ast::DeclId {
1114 self.var(specs, name, &[], None)
1115 }
1116
1117 fn bare(&mut self, specs: DeclSpecs) -> ast::DeclId {
1119 let specs = self.specs(specs);
1120 let declarators = self.ast.add_init_declarator_list(&[]);
1121 self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1122 }
1123
1124 fn specs(&mut self, specs: DeclSpecs) -> DeclSpecsId {
1125 self.ast.add_specs(specs)
1126 }
1127
1128 fn param(
1130 &mut self,
1131 specs: DeclSpecs,
1132 name: Option<&str>,
1133 derived: &[Derived],
1134 ) -> ast::Param {
1135 let declarator = match name {
1136 Some(name) => self.declarator(name, derived),
1137 None => {
1138 let derived = self.ast.add_derived_list(derived);
1139 self.ast.add_declarator(Declarator {
1140 name: None,
1141 name_span: Span::DUMMY,
1142 derived,
1143 span: Span::DUMMY,
1144 })
1145 }
1146 };
1147 let specs = self.specs(specs);
1148 ast::Param { specs: Some(specs), declarator, attrs: AttrList::EMPTY, span: Span::DUMMY }
1149 }
1150
1151 fn takes(&mut self, params: &[ast::Param]) -> Derived {
1153 let params = self.ast.add_param_list(params);
1154 Derived::Function { params, variadic: false, kind: ParamKind::Prototype }
1155 }
1156
1157 fn stmt(&mut self, stmt: ast::Stmt) -> ast::StmtId {
1158 self.ast.stmt(stmt, Span::DUMMY)
1159 }
1160
1161 fn block(&mut self, body: &[ast::StmtId]) -> ast::StmtId {
1163 let body = self.ast.add_stmt_list(body);
1164 self.stmt(ast::Stmt::Compound(body))
1165 }
1166
1167 fn define(
1169 &mut self,
1170 specs: DeclSpecs,
1171 name: &str,
1172 derived: &[Derived],
1173 body: ast::StmtId,
1174 ) -> ast::DeclId {
1175 let declarator = self.declarator(name, derived);
1176 let specs = self.specs(specs);
1177 let params = self.ast.add_decl_list(&[]);
1178 self.ast.decl(ast::Decl::Function { specs, declarator, params, body }, Span::DUMMY)
1179 }
1180
1181 fn checker(&self) -> Checker<'_> {
1182 Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1183 }
1184 }
1185
1186 fn pointer() -> Derived {
1188 Derived::Pointer { quals: Quals::NONE, attrs: AttrList::EMPTY }
1189 }
1190
1191 fn function() -> Derived {
1193 Derived::Function { params: ParamList::EMPTY, variadic: false, kind: ParamKind::Void }
1194 }
1195
1196 fn array(size: ast::ExprId) -> Derived {
1198 Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1199 }
1200
1201 fn only(checker: &Checker<'_>, list: DeclList) -> DeclId {
1203 let declared = &checker.tast[list];
1204 assert_eq!(declared.len(), 1, "expected exactly one declaration, got {declared:?}");
1205 declared[0]
1206 }
1207
1208 fn dump(checker: &Checker<'_>, id: DeclId) -> String {
1210 let mut printer = Printer::new(&checker.tast, &checker.types, checker.cx.names);
1211 printer.decl(id);
1212 printer.finish()
1213 }
1214
1215 fn messages(checker: &Checker<'_>) -> Vec<String> {
1217 checker
1218 .errors
1219 .diagnostics()
1220 .iter()
1221 .flat_map(|d| {
1222 std::iter::once(d.message.clone())
1223 .chain(d.children.iter().map(|n| n.message.clone()))
1224 })
1225 .collect()
1226 }
1227
1228 fn message(checker: &Checker<'_>) -> String {
1230 let mut reported = messages(checker);
1231 assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1232 reported.pop().expect("one message")
1233 }
1234
1235 #[test]
1236 fn a_file_scope_object_is_external_and_static_and_defines_nothing_by_itself() {
1237 let mut f = Fixture::new();
1238 let specs = f.int_specs();
1239 let decl = f.object(specs, "x");
1240
1241 let mut c = f.checker();
1242 let list = c.check_decl(decl);
1243
1244 let id = only(&c, list);
1245 assert_eq!(dump(&c, id), "decl #0 x : int object external static tentative\n");
1246 assert_eq!(c.tast.top_level(), [id]);
1247 assert!(c.errors.is_empty());
1248 }
1249
1250 #[test]
1251 fn the_same_three_words_in_a_block_are_a_local_with_no_linkage() {
1252 let mut f = Fixture::new();
1253 let specs = f.int_specs();
1254 let decl = f.object(specs, "x");
1255
1256 let mut c = f.checker();
1257 c.scopes.push();
1258 let list = c.check_decl(decl);
1259
1260 let id = only(&c, list);
1261 assert_eq!(dump(&c, id), "decl #0 x : int object automatic defined\n");
1262 assert!(c.tast.top_level().is_empty());
1263 assert!(c.errors.is_empty());
1264 }
1265
1266 #[test]
1267 fn static_at_file_scope_hides_the_name_and_in_a_block_only_lengthens_the_lifetime() {
1268 let mut f = Fixture::new();
1269 let mut specs = f.int_specs();
1270 specs.storage = Some(StorageClass::Static);
1271 let outer = f.object(specs, "x");
1272 let inner = f.object(specs, "y");
1273
1274 let mut c = f.checker();
1275 let list = c.check_decl(outer);
1276 let outer = only(&c, list);
1277 c.scopes.push();
1278 let list = c.check_decl(inner);
1279 let inner = only(&c, list);
1280
1281 assert_eq!(dump(&c, outer), "decl #0 x : int object internal static tentative\n");
1282 assert_eq!(dump(&c, inner), "decl #1 y : int object static defined\n");
1283 assert!(c.errors.is_empty());
1284 }
1285
1286 #[test]
1287 fn extern_in_a_block_names_the_object_the_file_scope_declaration_named() {
1288 let mut f = Fixture::new();
1289 let specs = f.int_specs();
1290 let outer = f.object(specs, "x");
1291 let mut specs = f.int_specs();
1292 specs.storage = Some(StorageClass::Extern);
1293 let inner = f.object(specs, "x");
1294
1295 let mut c = f.checker();
1296 let list = c.check_decl(outer);
1297 let first = only(&c, list);
1298 c.scopes.push();
1299 let list = c.check_decl(inner);
1300
1301 assert_eq!(only(&c, list), first, "the block-scope declaration is the same object");
1302 assert_eq!(dump(&c, first), "decl #0 x : int object external static tentative\n");
1303 assert!(c.errors.is_empty());
1304 }
1305
1306 #[test]
1307 fn a_declaration_and_a_definition_of_one_name_are_one_declaration() {
1308 let mut f = Fixture::new();
1309 let mut specs = f.int_specs();
1310 specs.storage = Some(StorageClass::Extern);
1311 let declared = f.object(specs, "x");
1312 let specs = f.int_specs();
1313 let one = f.int(1);
1314 let defined = f.var(specs, "x", &[], Some(one));
1315
1316 let mut c = f.checker();
1317 let list = c.check_decl(declared);
1318 let first = only(&c, list);
1319 let list = c.check_decl(defined);
1320
1321 assert_eq!(only(&c, list), first);
1322 assert_eq!(
1323 dump(&c, first),
1324 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
1325 );
1326 assert!(c.errors.is_empty());
1327 }
1328
1329 #[test]
1330 fn two_definitions_of_one_name_are_refused_and_the_first_one_is_pointed_at() {
1331 let mut f = Fixture::new();
1332 let specs = f.int_specs();
1333 let one = f.int(1);
1334 let first = f.var(specs, "x", &[], Some(one));
1335 let two = f.int(2);
1336 let second = f.var(specs, "x", &[], Some(two));
1337
1338 let mut c = f.checker();
1339 c.check_decl(first);
1340 c.check_decl(second);
1341
1342 assert_eq!(
1343 messages(&c),
1344 ["redefinition of 'x'", "previous definition of 'x' with type 'int'"]
1345 );
1346 }
1347
1348 #[test]
1349 fn a_redeclaration_with_another_type_says_which_type_this_one_has() {
1350 let mut f = Fixture::new();
1351 let specs = f.int_specs();
1352 let first = f.object(specs, "x");
1353 let specs = f.builtin(BuiltinSet::CHAR);
1354 let second = f.object(specs, "x");
1355
1356 let mut c = f.checker();
1357 c.check_decl(first);
1358 c.check_decl(second);
1359
1360 assert_eq!(
1361 messages(&c),
1362 [
1363 "conflicting types for 'x'; have 'char'",
1364 "previous declaration of 'x' with type 'int'"
1365 ]
1366 );
1367 }
1368
1369 #[test]
1370 fn two_declarations_of_an_array_leave_the_one_that_gave_a_bound() {
1371 let mut f = Fixture::new();
1372 let specs = f.int_specs();
1373 let first = f.var(
1374 specs,
1375 "a",
1376 &[Derived::Array {
1377 size: ArraySize::Unspecified,
1378 quals: Quals::NONE,
1379 has_static: false,
1380 }],
1381 None,
1382 );
1383 let three = f.int(3);
1384 let second = f.var(specs, "a", &[array(three)], None);
1385
1386 let mut c = f.checker();
1387 let list = c.check_decl(first);
1388 let id = only(&c, list);
1389 c.check_decl(second);
1390
1391 assert_eq!(dump(&c, id), "decl #0 a : int [3] object external static tentative\n");
1392 assert!(c.errors.is_empty());
1393 }
1394
1395 #[test]
1396 fn static_and_non_static_declarations_of_one_name_contradict_each_other_both_ways() {
1397 let mut f = Fixture::new();
1398 let plain = f.int_specs();
1399 let mut hidden = f.int_specs();
1400 hidden.storage = Some(StorageClass::Static);
1401 let (a, b) = (f.object(plain, "x"), f.object(hidden, "x"));
1402 let (c1, d) = (f.object(hidden, "y"), f.object(plain, "y"));
1403
1404 let mut c = f.checker();
1405 c.check_decl(a);
1406 c.check_decl(b);
1407 c.check_decl(c1);
1408 c.check_decl(d);
1409
1410 assert_eq!(
1411 messages(&c),
1412 [
1413 "static declaration of 'x' follows non-static declaration",
1414 "previous declaration of 'x' with type 'int'",
1415 "non-static declaration of 'y' follows static declaration",
1416 "previous declaration of 'y' with type 'int'",
1417 ]
1418 );
1419 }
1420
1421 #[test]
1422 fn extern_after_static_keeps_the_linkage_the_first_declaration_gave_the_name() {
1423 let mut f = Fixture::new();
1424 let mut specs = f.int_specs();
1425 specs.storage = Some(StorageClass::Static);
1426 let first = f.object(specs, "x");
1427 let mut specs = f.int_specs();
1428 specs.storage = Some(StorageClass::Extern);
1429 let second = f.object(specs, "x");
1430
1431 let mut c = f.checker();
1432 let list = c.check_decl(first);
1433 let id = only(&c, list);
1434 c.check_decl(second);
1435
1436 assert_eq!(dump(&c, id), "decl #0 x : int object internal static tentative\n");
1437 assert!(c.errors.is_empty());
1438 }
1439
1440 #[test]
1441 fn two_locals_of_one_name_in_one_block_are_refused_as_having_no_linkage() {
1442 let mut f = Fixture::new();
1443 let specs = f.int_specs();
1444 let first = f.object(specs, "x");
1445 let second = f.object(specs, "x");
1446
1447 let mut c = f.checker();
1448 c.scopes.push();
1449 c.check_decl(first);
1450 c.check_decl(second);
1451
1452 assert_eq!(
1453 messages(&c),
1454 ["redeclaration of 'x' with no linkage", "previous definition of 'x' with type 'int'"]
1455 );
1456 }
1457
1458 #[test]
1459 fn a_name_that_already_means_a_type_is_redeclared_as_a_different_kind_of_symbol() {
1460 let mut f = Fixture::new();
1461 let mut specs = f.int_specs();
1462 specs.storage = Some(StorageClass::Typedef);
1463 let named = f.object(specs, "T");
1464 let specs = f.int_specs();
1465 let object = f.object(specs, "T");
1466
1467 let mut c = f.checker();
1468 c.check_decl(named);
1469 c.check_decl(object);
1470
1471 assert_eq!(message(&c), "'T' redeclared as different kind of symbol");
1472 }
1473
1474 #[test]
1475 fn a_typedef_may_be_written_twice_for_one_type_and_not_for_two() {
1476 let mut f = Fixture::new();
1477 let mut specs = f.int_specs();
1478 specs.storage = Some(StorageClass::Typedef);
1479 let first = f.object(specs, "T");
1480 let again = f.object(specs, "T");
1481 let mut specs = f.builtin(BuiltinSet::CHAR);
1482 specs.storage = Some(StorageClass::Typedef);
1483 let other = f.object(specs, "T");
1484
1485 let mut c = f.checker();
1486 let declared = c.check_decl(first);
1487 assert!(c.tast[declared].is_empty(), "a typedef declares nothing at run time");
1488 c.check_decl(again);
1489 assert!(c.errors.is_empty(), "the same type twice is what two headers do");
1490 c.check_decl(other);
1491
1492 assert_eq!(message(&c), "conflicting types for 'T'; have 'char'");
1493 }
1494
1495 #[test]
1496 fn a_typedef_with_an_initializer_names_the_operator_that_was_wanted_instead() {
1497 let mut f = Fixture::new();
1498 let mut specs = f.int_specs();
1499 specs.storage = Some(StorageClass::Typedef);
1500 let one = f.int(1);
1501 let decl = f.var(specs, "T", &[], Some(one));
1502
1503 let mut c = f.checker();
1504 c.check_decl(decl);
1505
1506 assert_eq!(message(&c), "typedef 'T' is initialized (use '__typeof__' instead)");
1507 }
1508
1509 #[test]
1510 fn an_object_of_a_type_with_no_size_is_refused_and_a_local_void_is_worded_apart() {
1511 let mut f = Fixture::new();
1512 let incomplete = f.record(Some("S"), false);
1513 let hidden = f.object(incomplete, "s");
1514 let void = f.builtin(BuiltinSet::VOID);
1515 let nothing = f.object(void, "x");
1516
1517 let mut c = f.checker();
1518 c.scopes.push();
1519 c.check_decl(hidden);
1520 c.check_decl(nothing);
1521
1522 assert_eq!(
1523 messages(&c),
1524 ["storage size of 's' isn't known", "variable or field 'x' declared void"]
1525 );
1526 }
1527
1528 #[test]
1529 fn an_array_with_no_bound_at_file_scope_waits_for_a_declaration_that_gives_one() {
1530 let mut f = Fixture::new();
1531 let specs = f.int_specs();
1532 let decl = f.var(
1533 specs,
1534 "a",
1535 &[Derived::Array {
1536 size: ArraySize::Unspecified,
1537 quals: Quals::NONE,
1538 has_static: false,
1539 }],
1540 None,
1541 );
1542
1543 let mut c = f.checker();
1544 let list = c.check_decl(decl);
1545
1546 assert_eq!(
1547 dump(&c, only(&c, list)),
1548 "decl #0 a : int [] object external static tentative\n"
1549 );
1550 assert!(c.errors.is_empty(), "the end of the translation unit is what decides this one");
1551 }
1552
1553 #[test]
1554 fn a_variable_length_array_may_be_automatic_and_may_not_outlive_the_block() {
1555 let mut f = Fixture::new();
1556 let specs = f.int_specs();
1557 let n = f.use_name("n");
1558 let automatic = f.var(specs, "a", &[array(n)], None);
1559 let mut specs = f.int_specs();
1560 specs.storage = Some(StorageClass::Static);
1561 let n = f.use_name("n");
1562 let stored = f.var(specs, "b", &[array(n)], None);
1563 let n = f.name("n");
1564
1565 let mut c = f.checker();
1566 c.scopes.push();
1567 let int = c.types.int(IntKind::Int);
1568 c.declare_object(n, int, Span::DUMMY);
1569 c.check_decl(automatic);
1570 assert!(c.errors.is_empty());
1571 c.check_decl(stored);
1572
1573 assert_eq!(message(&c), "storage size of 'b' isn't constant");
1574 }
1575
1576 #[test]
1577 fn auto_and_register_at_file_scope_are_each_refused_in_the_words_gcc_uses() {
1578 let mut f = Fixture::new();
1579 let mut specs = f.int_specs();
1580 specs.storage = Some(StorageClass::Auto);
1581 let automatic = f.object(specs, "x");
1582 let mut specs = f.int_specs();
1583 specs.storage = Some(StorageClass::Register);
1584 let in_a_register = f.object(specs, "y");
1585
1586 let mut c = f.checker();
1587 c.check_decl(automatic);
1588 c.check_decl(in_a_register);
1589
1590 assert_eq!(
1591 messages(&c),
1592 [
1593 "file-scope declaration of 'x' specifies 'auto'",
1594 "register name not specified for 'y'",
1595 ]
1596 );
1597 }
1598
1599 #[test]
1600 fn a_function_takes_static_at_file_scope_and_no_storage_class_anywhere_else() {
1601 let mut f = Fixture::new();
1602 let mut specs = f.int_specs();
1603 specs.storage = Some(StorageClass::Static);
1604 let hidden = f.var(specs, "f", &[function()], None);
1605 let inner = f.var(specs, "g", &[function()], None);
1606
1607 let mut c = f.checker();
1608 let list = c.check_decl(hidden);
1609 assert_eq!(dump(&c, only(&c, list)), "decl #0 f : int (void) function internal declared\n");
1610 assert!(c.errors.is_empty());
1611 c.scopes.push();
1612 c.check_decl(inner);
1613
1614 assert_eq!(message(&c), "invalid storage class for function 'g'");
1615 }
1616
1617 #[test]
1618 fn a_scalar_initializer_is_converted_to_the_type_of_the_object_it_initializes() {
1619 let mut f = Fixture::new();
1620 let specs = f.builtin(BuiltinSet::DOUBLE);
1621 let one = f.int(1);
1622 let decl = f.var(specs, "d", &[], Some(one));
1623
1624 let mut c = f.checker();
1625 c.scopes.push();
1626 let list = c.check_decl(decl);
1627
1628 assert_eq!(
1629 dump(&c, only(&c, list)),
1630 "decl #0 d : double object automatic defined\n init\n +0\n \
1631 convert arithmetic : double\n const 1 : int\n"
1632 );
1633 assert!(c.errors.is_empty());
1634 }
1635
1636 #[test]
1637 fn an_initializer_of_the_wrong_kind_names_the_conversion_it_would_have_taken() {
1638 let mut f = Fixture::new();
1639 let specs = f.int_specs();
1640 let one = f.int(1);
1641 let from_an_integer = f.var(specs, "p", &[pointer()], None.or(Some(one)));
1642 let specs = f.builtin(BuiltinSet::CHAR);
1643 let q = f.use_name("q");
1644 let from_a_pointer = f.var(specs, "r", &[pointer()], Some(q));
1645 let q = f.name("q");
1646
1647 let mut c = f.checker();
1648 c.scopes.push();
1649 let int = c.types.int(IntKind::Int);
1650 let to_int = c.types.pointer(int);
1651 c.declare_object(q, to_int, Span::DUMMY);
1652 c.check_decl(from_an_integer);
1653 c.check_decl(from_a_pointer);
1654
1655 assert_eq!(
1656 messages(&c),
1657 [
1658 "initialization of 'int *' from 'int' makes pointer from integer without a cast",
1659 "initialization of 'char *' from incompatible pointer type 'int *'",
1660 ]
1661 );
1662 }
1663
1664 #[test]
1665 fn an_array_and_a_structure_each_refuse_a_value_as_an_initializer() {
1666 let mut f = Fixture::new();
1667 let specs = f.int_specs();
1668 let two = f.int(2);
1669 let one = f.int(1);
1670 let an_array = f.var(specs, "a", &[array(two)], Some(one));
1671 let specs = f.record(Some("S"), true);
1672 let one = f.int(1);
1673 let a_record = f.var(specs, "s", &[], Some(one));
1674
1675 let mut c = f.checker();
1676 c.scopes.push();
1677 c.check_decl(an_array);
1678 c.check_decl(a_record);
1679
1680 assert_eq!(messages(&c), ["invalid initializer", "invalid initializer"]);
1681 }
1682
1683 #[test]
1684 fn extern_with_an_initializer_is_an_error_in_a_block_and_a_warning_at_file_scope() {
1685 let mut f = Fixture::new();
1686 let mut specs = f.int_specs();
1687 specs.storage = Some(StorageClass::Extern);
1688 let one = f.int(1);
1689 let outer = f.var(specs, "x", &[], Some(one));
1690 let one = f.int(1);
1691 let inner = f.var(specs, "y", &[], Some(one));
1692
1693 let mut c = f.checker();
1694 c.check_decl(outer);
1695 c.scopes.push();
1696 c.check_decl(inner);
1697
1698 assert_eq!(
1699 messages(&c),
1700 ["'x' initialized and declared 'extern'", "'y' has both 'extern' and initializer"]
1701 );
1702 }
1703
1704 #[test]
1705 fn alignas_raises_the_alignment_and_refuses_to_lower_it_or_to_take_a_number_that_is_not_one() {
1706 let mut f = Fixture::new();
1707 let sixteen = f.int(16);
1708 let mut specs = f.int_specs();
1709 specs.align = Some(AlignSpec::Expr(sixteen));
1710 let raised = f.object(specs, "x");
1711 let one = f.int(1);
1712 let mut specs = f.int_specs();
1713 specs.align = Some(AlignSpec::Expr(one));
1714 let lowered = f.object(specs, "y");
1715 let three = f.int(3);
1716 let mut specs = f.int_specs();
1717 specs.align = Some(AlignSpec::Expr(three));
1718 let odd = f.object(specs, "z");
1719
1720 let mut c = f.checker();
1721 let list = c.check_decl(raised);
1722 assert_eq!(
1723 dump(&c, only(&c, list)),
1724 "decl #0 x : int object external static tentative alignas 16\n"
1725 );
1726 c.check_decl(lowered);
1727 c.check_decl(odd);
1728
1729 assert_eq!(
1730 messages(&c),
1731 [
1732 "'_Alignas' specifiers cannot reduce alignment of 'y'",
1733 "requested alignment '3' is not a positive power of 2",
1734 ]
1735 );
1736 }
1737
1738 #[test]
1739 fn alignment_asked_for_on_a_typedef_and_on_a_function_is_refused_on_each() {
1740 let mut f = Fixture::new();
1741 let sixteen = f.int(16);
1742 let mut specs = f.int_specs();
1743 specs.align = Some(AlignSpec::Expr(sixteen));
1744 specs.storage = Some(StorageClass::Typedef);
1745 let named = f.object(specs, "T");
1746 let mut specs = f.int_specs();
1747 specs.align = Some(AlignSpec::Expr(sixteen));
1748 let called = f.var(specs, "g", &[function()], None);
1749
1750 let mut c = f.checker();
1751 c.check_decl(named);
1752 c.check_decl(called);
1753
1754 assert_eq!(
1755 messages(&c),
1756 ["alignment specified for typedef 'T'", "alignment specified for function 'g'"]
1757 );
1758 }
1759
1760 #[test]
1761 fn a_static_assertion_that_holds_says_nothing_and_one_that_fails_quotes_its_message() {
1762 let mut f = Fixture::new();
1763 let one = f.int(1);
1764 let holds = f.ast.decl(ast::Decl::StaticAssert { cond: one, message: None }, Span::DUMMY);
1765 let zero = f.int(0);
1766 let boom = f.string("boom");
1767 let fails =
1768 f.ast.decl(ast::Decl::StaticAssert { cond: zero, message: Some(boom) }, Span::DUMMY);
1769
1770 let mut c = f.checker();
1771 c.check_decl(holds);
1772 assert!(c.errors.is_empty());
1773 c.check_decl(fails);
1774
1775 assert_eq!(message(&c), "static assertion failed: \"boom\"");
1776 }
1777
1778 #[test]
1779 fn an_empty_declaration_says_what_about_it_was_useless() {
1780 let mut f = Fixture::new();
1781 let specs = f.int_specs();
1782 let a_type_name = f.bare(specs);
1783 let mut specs = f.record(Some("S"), false);
1784 specs.quals = Quals::CONST;
1785 let a_qualifier = f.bare(specs);
1786 let unnamed = f.record(None, true);
1787 let no_instances = f.bare(unnamed);
1788
1789 let mut c = f.checker();
1790 c.check_decl(a_type_name);
1791 c.check_decl(a_qualifier);
1792 c.check_decl(no_instances);
1793
1794 assert_eq!(
1795 messages(&c),
1796 [
1797 "useless type name in empty declaration",
1798 "useless type qualifier in empty declaration",
1799 "unnamed struct/union that defines no instances",
1800 ]
1801 );
1802 }
1803
1804 #[test]
1805 fn a_specifier_that_only_a_function_takes_is_warned_about_on_a_variable() {
1806 let mut f = Fixture::new();
1807 let mut specs = f.int_specs();
1808 specs.func = FuncSpecs::INLINE;
1809 let decl = f.object(specs, "x");
1810
1811 let mut c = f.checker();
1812 c.check_decl(decl);
1813
1814 assert_eq!(message(&c), "variable 'x' declared 'inline'");
1815 }
1816
1817 #[test]
1818 fn thread_local_in_a_block_needs_a_storage_class_that_gives_it_somewhere_to_live() {
1819 let mut f = Fixture::new();
1820 let mut specs = f.int_specs();
1821 specs.thread_local = true;
1822 let alone = f.object(specs, "x");
1823 let mut specs = f.int_specs();
1824 specs.thread_local = true;
1825 specs.storage = Some(StorageClass::Static);
1826 let stored = f.object(specs, "y");
1827
1828 let mut c = f.checker();
1829 c.scopes.push();
1830 c.check_decl(alone);
1831 assert_eq!(message(&c), "function-scope 'x' implicitly auto and declared '_Thread_local'");
1832 let list = c.check_decl(stored);
1833
1834 assert_eq!(dump(&c, only(&c, list)), "decl #1 y : int object thread defined\n");
1835 }
1836
1837 #[test]
1838 fn a_function_definition_is_a_declaration_with_its_body_under_it() {
1839 let mut f = Fixture::new();
1840 let specs = f.builtin(BuiltinSet::VOID);
1841 let body = f.block(&[]);
1842 let decl = f.define(specs, "f", &[function()], body);
1843
1844 let mut c = f.checker();
1845 let list = c.check_decl(decl);
1846
1847 let id = only(&c, list);
1848 assert_eq!(
1849 dump(&c, id),
1850 "decl #0 f : void (void) function external defined\n body\n block\n"
1851 );
1852 assert!(c.errors.is_empty());
1853 }
1854
1855 #[test]
1856 fn a_parameter_is_declared_once_and_the_body_names_that_declaration() {
1857 let mut f = Fixture::new();
1858 let int = f.int_specs();
1859 let n = f.param(int, Some("n"), &[]);
1860 let takes = f.takes(&[n]);
1861 let use_n = f.use_name("n");
1862 let ret = f.stmt(ast::Stmt::Return(Some(use_n)));
1863 let body = f.block(&[ret]);
1864 let specs = f.int_specs();
1865 let decl = f.define(specs, "f", &[takes], body);
1866
1867 let mut c = f.checker();
1868 let list = c.check_decl(decl);
1869
1870 let id = only(&c, list);
1871 assert_eq!(
1872 dump(&c, id),
1873 "decl #1 f : int (int) function external defined\n params\n decl #0 n : int \
1874 object automatic defined\n body\n block\n return\n convert lvalue \
1875 : int\n decl #0 n : int lvalue\n"
1876 );
1877 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1878 }
1879
1880 #[test]
1881 fn a_name_declared_in_the_body_meets_the_parameter_of_the_same_name() {
1882 let mut f = Fixture::new();
1883 let int = f.int_specs();
1884 let a = f.param(int, Some("a"), &[]);
1885 let takes = f.takes(&[a]);
1886 let specs = f.int_specs();
1887 let shadow = f.object(specs, "a");
1888 let shadow = f.stmt(ast::Stmt::Decl(shadow));
1889 let body = f.block(&[shadow]);
1890 let specs = f.builtin(BuiltinSet::VOID);
1891 let decl = f.define(specs, "f", &[takes], body);
1892
1893 let mut c = f.checker();
1894 c.check_decl(decl);
1895
1896 assert_eq!(
1897 messages(&c),
1898 ["redeclaration of 'a' with no linkage", "previous definition of 'a' with type 'int'"]
1899 );
1900 }
1901
1902 #[test]
1903 fn a_block_inside_the_body_may_shadow_a_parameter() {
1904 let mut f = Fixture::new();
1905 let int = f.int_specs();
1906 let a = f.param(int, Some("a"), &[]);
1907 let takes = f.takes(&[a]);
1908 let specs = f.int_specs();
1909 let shadow = f.object(specs, "a");
1910 let shadow = f.stmt(ast::Stmt::Decl(shadow));
1911 let inner = f.block(&[shadow]);
1912 let body = f.block(&[inner]);
1913 let specs = f.builtin(BuiltinSet::VOID);
1914 let decl = f.define(specs, "f", &[takes], body);
1915
1916 let mut c = f.checker();
1917 c.check_decl(decl);
1918
1919 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1920 }
1921
1922 #[test]
1923 fn an_array_parameter_is_a_pointer_in_the_body_as_well_as_in_the_type() {
1924 let mut f = Fixture::new();
1925 let int = f.int_specs();
1926 let three = f.int(3);
1927 let a = f.param(int, Some("a"), &[array(three)]);
1928 let takes = f.takes(&[a]);
1929 let use_a = f.use_name("a");
1930 let stmt = f.stmt(ast::Stmt::Expr(use_a));
1931 let body = f.block(&[stmt]);
1932 let specs = f.builtin(BuiltinSet::VOID);
1933 let decl = f.define(specs, "f", &[takes], body);
1934
1935 let mut c = f.checker();
1936 let list = c.check_decl(decl);
1937
1938 let id = only(&c, list);
1939 assert_eq!(
1940 dump(&c, id),
1941 "decl #1 f : void (int *) function external defined\n params\n decl #0 a : \
1942 int * object automatic defined\n body\n block\n expr\n convert \
1943 lvalue : int *\n decl #0 a : int * lvalue\n"
1944 );
1945 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1946 }
1947
1948 #[test]
1949 fn the_body_answers_to_the_return_type_the_definition_was_written_with() {
1950 let mut f = Fixture::new();
1951 let ret = f.stmt(ast::Stmt::Return(None));
1952 let body = f.block(&[ret]);
1953 let specs = f.int_specs();
1954 let decl = f.define(specs, "f", &[function()], body);
1955
1956 let mut c = f.checker();
1957 c.check_decl(decl);
1958
1959 assert_eq!(
1960 messages(&c),
1961 ["'return' with no value, in function returning non-void", "declared here"]
1962 );
1963 }
1964
1965 #[test]
1966 fn a_declaration_and_a_definition_of_one_function_are_one_declaration() {
1967 let mut f = Fixture::new();
1968 let specs = f.builtin(BuiltinSet::VOID);
1969 let declared = f.var(specs, "f", &[function()], None);
1970 let body = f.block(&[]);
1971 let specs = f.builtin(BuiltinSet::VOID);
1972 let defined = f.define(specs, "f", &[function()], body);
1973
1974 let mut c = f.checker();
1975 let list = c.check_decl(declared);
1976 let first = only(&c, list);
1977 let list = c.check_decl(defined);
1978
1979 assert_eq!(only(&c, list), first);
1980 assert_eq!(
1981 dump(&c, first),
1982 "decl #0 f : void (void) function external defined\n body\n block\n"
1983 );
1984 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1985 }
1986
1987 #[test]
1988 fn a_function_definition_declared_typedef_is_an_error() {
1989 let mut f = Fixture::new();
1990 let mut specs = f.builtin(BuiltinSet::VOID);
1991 specs.storage = Some(StorageClass::Typedef);
1992 let body = f.block(&[]);
1993 let decl = f.define(specs, "f", &[function()], body);
1994
1995 let mut c = f.checker();
1996 c.check_decl(decl);
1997
1998 assert_eq!(message(&c), "function definition declared 'typedef'");
1999 }
2000
2001 #[test]
2002 fn an_old_style_definition_is_recognised_and_not_checked_yet() {
2003 let mut f = Fixture::new();
2004 let int = f.int_specs();
2005 let a = f.param(int, Some("a"), &[]);
2006 let params = f.ast.add_param_list(&[a]);
2007 let old = Derived::Function { params, variadic: false, kind: ParamKind::Identifiers };
2008 let body = f.block(&[]);
2009 let specs = f.builtin(BuiltinSet::VOID);
2010 let decl = f.define(specs, "f", &[old], body);
2011
2012 let mut c = f.checker();
2013 c.check_decl(decl);
2014
2015 assert_eq!(message(&c), "an old-style function definition is not supported yet");
2016 }
2017
2018 #[test]
2019 fn a_deduced_type_is_the_type_the_initializer_would_have_where_it_is_used() {
2020 let mut f = Fixture::new();
2021 let one = f.int(1);
2022 let decl = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(one));
2023
2024 let mut c = f.checker();
2025 let list = c.check_decl(decl);
2026
2027 let id = only(&c, list);
2028 assert_eq!(
2029 dump(&c, id),
2030 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
2031 );
2032 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2033 }
2034
2035 #[test]
2036 fn a_deduced_type_is_the_one_a_use_has_so_an_array_deduces_a_pointer() {
2037 let mut f = Fixture::new();
2038 let three = f.int(3);
2039 let ints = f.int_specs();
2040 let array = f.var(ints, "a", &[array(three)], None);
2041 let a = f.use_name("a");
2042 let decl = f.var(f.deduced(ast::Deduction::AutoType), "p", &[], Some(a));
2043
2044 let mut c = f.checker();
2045 c.check_decl(array);
2046 c.scopes.push();
2047 let list = c.check_decl(decl);
2048
2049 let id = only(&c, list);
2050 assert!(dump(&c, id).starts_with("decl #1 p : int *"), "{}", dump(&c, id));
2051 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2052 }
2053
2054 #[test]
2055 fn a_deduced_type_drops_the_initializers_qualifiers_and_takes_the_declarations() {
2056 let mut f = Fixture::new();
2057 let mut ints = f.int_specs();
2058 ints.quals = Quals::CONST;
2059 let one = f.int(1);
2060 let source = f.var(ints, "c", &[], Some(one));
2061 let c1 = f.use_name("c");
2063 let plain = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(c1));
2064 let c2 = f.use_name("c");
2065 let mut qualified = f.deduced(ast::Deduction::Auto);
2066 qualified.quals = Quals::CONST;
2067 let kept = f.var(qualified, "y", &[], Some(c2));
2068
2069 let mut c = f.checker();
2070 c.check_decl(source);
2071 c.scopes.push();
2072 let list = c.check_decl(plain);
2073 let plain = only(&c, list);
2074 let list = c.check_decl(kept);
2075 let kept = only(&c, list);
2076
2077 assert!(dump(&c, plain).starts_with("decl #1 x : int "), "{}", dump(&c, plain));
2078 assert!(dump(&c, kept).starts_with("decl #2 y : const int "), "{}", dump(&c, kept));
2079 assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2080 }
2081
2082 #[test]
2083 fn a_deduced_type_needs_a_declarator_that_is_no_more_than_a_name() {
2084 let mut f = Fixture::new();
2085 let one = f.int(1);
2087 let c23 = f.var(f.deduced(ast::Deduction::Auto), "p", &[pointer()], Some(one));
2088 let two = f.int(2);
2089 let gnu = f.var(f.deduced(ast::Deduction::AutoType), "q", &[pointer()], Some(two));
2090
2091 let mut c = f.checker();
2092 c.check_decl(c23);
2093 c.check_decl(gnu);
2094
2095 assert_eq!(
2097 messages(&c),
2098 [
2099 "'auto' requires a plain identifier, possibly with attributes, as declarator",
2100 "'__auto_type' requires a plain identifier as declarator",
2101 ]
2102 );
2103 }
2104
2105 #[test]
2106 fn a_deduced_type_needs_something_to_deduce_from() {
2107 let mut f = Fixture::new();
2108 let decl = f.var(f.deduced(ast::Deduction::AutoType), "x", &[], None);
2109
2110 let mut c = f.checker();
2111 c.check_decl(decl);
2112
2113 assert_eq!(message(&c), "'__auto_type' requires an initialized data declaration");
2114 }
2115
2116 #[test]
2117 fn one_initializer_deduces_one_type_so_a_second_declarator_is_refused() {
2118 let mut f = Fixture::new();
2119 let one = f.int(1);
2122 let two = f.int(2);
2123 let x = f.declarator("x", &[]);
2124 let y = f.declarator("y", &[]);
2125 let items: Vec<ast::InitDeclarator> = [(x, one), (y, two)]
2126 .into_iter()
2127 .map(|(declarator, value)| ast::InitDeclarator {
2128 declarator,
2129 init: Some(f.ast.add_init(ast::Init::Expr(value))),
2130 asm_label: None,
2131 attrs: AttrList::EMPTY,
2132 span: Span::DUMMY,
2133 })
2134 .collect();
2135 let declarators = f.ast.add_init_declarator_list(&items);
2136 let specs = f.specs(f.deduced(ast::Deduction::Auto));
2137 let decl = f.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY);
2138
2139 let mut c = f.checker();
2140 let list = c.check_decl(decl);
2141
2142 let id = only(&c, list);
2143 assert_eq!(
2144 dump(&c, id),
2145 "decl #0 x : int object external static defined\n init\n +0\n const 1 : int\n"
2146 );
2147 assert_eq!(message(&c), "'auto' may only be used with a single declarator");
2148 }
2149
2150 #[test]
2151 fn a_function_definition_deduces_nothing_because_it_has_no_initializer() {
2152 let mut f = Fixture::new();
2153 let body = f.block(&[]);
2154 let decl = f.define(f.deduced(ast::Deduction::Auto), "f", &[function()], body);
2155
2156 let mut c = f.checker();
2157 let list = c.check_decl(decl);
2158
2159 assert!(c.tast[list].is_empty());
2160 assert_eq!(
2161 message(&c),
2162 "'auto' requires a plain identifier, possibly with attributes, as declarator"
2163 );
2164 }
2165
2166 #[test]
2167 fn a_name_with_no_type_until_its_initializer_is_checked_may_not_be_used_in_it() {
2168 let mut f = Fixture::new();
2169 let x = f.use_name("x");
2172 let deduced = f.var(f.deduced(ast::Deduction::Auto), "x", &[], Some(x));
2173 let y = f.use_name("y");
2174 let mut ints = f.int_specs();
2175 ints.storage = Some(StorageClass::Constexpr);
2176 let constant = f.var(ints, "y", &[], Some(y));
2177
2178 let mut c = f.checker();
2179 c.scopes.push();
2180 c.check_decl(deduced);
2181 c.check_decl(constant);
2182
2183 assert_eq!(
2186 messages(&c),
2187 [
2188 "underspecified 'x' referenced in its initializer",
2189 "underspecified 'y' referenced in its initializer",
2190 ]
2191 );
2192 }
2193}