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