diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index edab6b5ebde..da08027d66b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -554,53 +554,43 @@ impl<'hir> Map<'hir> { /// } /// ``` pub fn get_fn_id_for_return_block(self, id: HirId) -> Option { - let mut iter = self.parent_iter(id).peekable(); - let mut ignore_tail = false; - if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) { - // When dealing with `return` statements, we don't care about climbing only tail - // expressions. - ignore_tail = true; - } + let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id)); - let mut prev_hir_id = None; - while let Some((hir_id, node)) = iter.next() { - if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) { - match next_node { - Node::Block(Block { expr: None, .. }) => return None, - // The current node is not the tail expression of its parent. - Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None, + // Return `None` if the `id` expression is not the returned value of the enclosing body + let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable(); + while let Some(cur_id) = iter.next() { + if enclosing_body_owner == cur_id { + break; + } + + // A return statement is always the value returned from the enclosing body regardless of + // what the parent expressions are. + if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) { + break; + } + + // If the current expression's value doesnt get used as the parent expressions value then return `None` + if let Some(&parent_id) = iter.peek() { + match self.tcx.hir_node(parent_id) { + // The current node is not the tail expression of the block expression parent expr. + Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None, Node::Block(Block { expr: Some(e), .. }) if matches!(e.kind, ExprKind::If(_, _, None)) => { return None; } + + // The current expression's value does not pass up through these parent expressions + Node::Block(Block { expr: None, .. }) + | Node::Expr(Expr { kind: ExprKind::Loop(..), .. }) + | Node::LetStmt(..) => return None, + _ => {} } } - match node { - Node::Item(_) - | Node::ForeignItem(_) - | Node::TraitItem(_) - | Node::Expr(Expr { kind: ExprKind::Closure(_), .. }) - | Node::ImplItem(_) - // The input node `id` must be enclosed in the method's body as opposed - // to some other place such as its return type (fixes #114918). - // We verify that indirectly by checking that the previous node is the - // current node's body - if node.body_id().map(|b| b.hir_id) == prev_hir_id => { - return Some(hir_id) - } - // Ignore `return`s on the first iteration - Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. }) - | Node::LetStmt(_) => { - return None; - } - _ => {} - } - - prev_hir_id = Some(hir_id); } - None + + Some(enclosing_body_owner) } /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f2d87814130..5dd0e69cf1f 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1418,21 +1418,19 @@ pub fn write_allocations<'tcx>( alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id()) } - fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator + '_ { + fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option { match val { - ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => { - Either::Left(std::iter::once(ptr.provenance.alloc_id())) - } - ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()), - ConstValue::ZeroSized => Either::Right(std::iter::empty()), + ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()), + ConstValue::Scalar(interpret::Scalar::Int { .. }) => None, + ConstValue::ZeroSized => None, ConstValue::Slice { .. } => { // `u8`/`str` slices, shouldn't contain pointers that we want to print. - Either::Right(std::iter::empty()) + None } ConstValue::Indirect { alloc_id, .. } => { // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR. // Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor. - Either::Left(std::iter::once(alloc_id)) + Some(alloc_id) } } } @@ -1443,7 +1441,9 @@ pub fn write_allocations<'tcx>( match c.const_ { Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { - self.0.extend(alloc_ids_from_const_val(val)); + if let Some(id) = alloc_id_from_const_val(val) { + self.0.insert(id); + } } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 6120b1453cf..5b5f97cb514 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{HirId, Node}; +use rustc_hir::HirId; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; @@ -110,11 +110,7 @@ impl<'tcx> Cx<'tcx> { } #[instrument(level = "debug", skip(self))] - fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box> { - let p = match self.tcx.hir_node(p.hir_id) { - Node::Pat(p) => p, - node => bug!("pattern became {:?}", node), - }; + fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box> { pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 0318d34fb73..1ea4ca375f1 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -430,6 +430,10 @@ passes_link_section = .warn = {-passes_previously_accepted} .label = not a function or static +passes_linkage = + attribute should be applied to a function or static + .label = not a function definition or static + passes_macro_export = `#[macro_export]` only has an effect on macro definitions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bd157d1d619..a47add929eb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -243,6 +243,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::coroutine, ..] => { self.check_coroutine(attr, target); } + [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok sym::allow @@ -256,7 +257,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfi_encoding // FIXME(cfi_encoding) | sym::may_dangle // FIXME(dropck_eyepatch) | sym::pointee // FIXME(derive_smart_pointer) - | sym::linkage // FIXME(linkage) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items | sym::repr // handled elsewhere to restrict to type decls items @@ -2347,6 +2347,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } + + fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) { + match target { + Target::Fn + | Target::Method(..) + | Target::Static + | Target::ForeignStatic + | Target::ForeignFn => {} + _ => { + self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span }); + } + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 36dfc40e762..3a043e0e3c1 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -643,6 +643,15 @@ pub struct CoroutineOnNonClosure { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_linkage)] +pub struct Linkage { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_empty_confusables)] pub(crate) struct EmptyConfusables { diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index b91333e5f81..d49fa3ac5ac 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -75,7 +75,6 @@ impl DocTestRunner { #![allow(internal_features)] #![feature(test)] #![feature(rustc_attrs)] -#![feature(coverage_attribute)] " .to_string(); @@ -135,7 +134,6 @@ mod __doctest_mod {{ }} #[rustc_main] -#[coverage(off)] fn main() -> std::process::ExitCode {{ const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}]; let bin_marker = std::ffi::OsStr::new(__doctest_mod::BIN_OPTION); @@ -235,11 +233,9 @@ fn main() {returns_result} {{ writeln!( output, " -#[rustc_test_marker = {test_name:?}] pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic}, test::StaticTestFn( - #[coverage(off)] || {{{runner}}}, )); }}", diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index a424faaf999..e2860292aa3 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -39,8 +39,10 @@ pub(crate) struct JsonRenderer<'tcx> { /// A mapping of IDs that contains all local items for this crate which gets output as a top /// level field of the JSON blob. index: Rc>>, - /// The directory where the blob will be written to. - out_path: Option, + /// The directory where the JSON blob should be written to. + /// + /// If this is `None`, the blob will be printed to `stdout` instead. + out_dir: Option, cache: Rc, imported_items: DefIdSet, } @@ -101,18 +103,20 @@ impl<'tcx> JsonRenderer<'tcx> { .unwrap_or_default() } - fn write( + fn serialize_and_write( &self, - output: types::Crate, + output_crate: types::Crate, mut writer: BufWriter, path: &str, ) -> Result<(), Error> { - self.tcx - .sess - .time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut writer, &output)) - .unwrap(); - try_err!(writer.flush(), path); - Ok(()) + self.sess().time("rustdoc_json_serialize_and_write", || { + try_err!( + serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()), + path + ); + try_err!(writer.flush(), path); + Ok(()) + }) } } @@ -137,7 +141,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { JsonRenderer { tcx, index: Rc::new(RefCell::new(FxHashMap::default())), - out_path: if options.output_to_stdout { None } else { Some(options.output) }, + out_dir: if options.output_to_stdout { None } else { Some(options.output) }, cache: Rc::new(cache), imported_items, }, @@ -237,7 +241,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let index = (*self.index).clone().into_inner(); debug!("Constructing Output"); - let output = types::Crate { + let output_crate = types::Crate { root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())), crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, @@ -278,20 +282,20 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { .collect(), format_version: types::FORMAT_VERSION, }; - if let Some(ref out_path) = self.out_path { - let out_dir = out_path.clone(); + if let Some(ref out_dir) = self.out_dir { try_err!(create_dir_all(&out_dir), out_dir); - let mut p = out_dir; - p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); + let mut p = out_dir.clone(); + p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap()); p.set_extension("json"); - self.write( - output, + + self.serialize_and_write( + output_crate, BufWriter::new(try_err!(File::create(&p), p)), &p.display().to_string(), ) } else { - self.write(output, BufWriter::new(stdout()), "") + self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "") } } diff --git a/tests/crashes/128810.rs b/tests/crashes/128810.rs deleted file mode 100644 index 68214ff010c..00000000000 --- a/tests/crashes/128810.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ known-bug: rust-lang/rust#128810 - -#![feature(fn_delegation)] - -use std::marker::PhantomData; - -pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); - -impl<'a> InvariantRef<'a, ()> { - pub const NEW: Self = InvariantRef::new(&()); -} - -trait Trait { - fn foo(&self) -> u8 { 0 } - fn bar(&self) -> u8 { 1 } - fn meh(&self) -> u8 { 2 } -} - -struct Z(u8); - -impl Trait for Z { - reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } -} - -fn main() { } diff --git a/tests/ui/attributes/linkage.rs b/tests/ui/attributes/linkage.rs new file mode 100644 index 00000000000..0d5ce699fa8 --- /dev/null +++ b/tests/ui/attributes/linkage.rs @@ -0,0 +1,42 @@ +#![feature(linkage)] +#![feature(stmt_expr_attributes)] +#![deny(unused_attributes)] +#![allow(dead_code)] + +#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +type InvalidTy = (); + +#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +mod invalid_module {} + +#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +struct F; + +#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +impl F { + #[linkage = "weak"] + fn valid(&self) {} +} + +#[linkage = "weak"] +fn f() { + #[linkage = "weak"] + { + 1 + }; + //~^^^^ ERROR attribute should be applied to a function or static +} + +extern "C" { + #[linkage = "weak"] + static A: *const (); + + #[linkage = "weak"] + fn bar(); +} + +fn main() { + let _ = #[linkage = "weak"] + (|| 1); + //~^^ ERROR attribute should be applied to a function or static +} diff --git a/tests/ui/attributes/linkage.stderr b/tests/ui/attributes/linkage.stderr new file mode 100644 index 00000000000..d5595529f40 --- /dev/null +++ b/tests/ui/attributes/linkage.stderr @@ -0,0 +1,55 @@ +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:6:1 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | type InvalidTy = (); + | -------------------- not a function definition or static + +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:9:1 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | mod invalid_module {} + | --------------------- not a function definition or static + +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:12:1 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | struct F; + | --------- not a function definition or static + +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:15:1 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | / impl F { +LL | | #[linkage = "weak"] +LL | | fn valid(&self) {} +LL | | } + | |_- not a function definition or static + +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:23:5 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | / { +LL | | 1 +LL | | }; + | |_____- not a function definition or static + +error: attribute should be applied to a function or static + --> $DIR/linkage.rs:39:13 + | +LL | let _ = #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ +LL | (|| 1); + | ------ not a function definition or static + +error: aborting due to 6 previous errors + diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs new file mode 100644 index 00000000000..0a7ec5ab5c1 --- /dev/null +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs @@ -0,0 +1,34 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +use std::marker::PhantomData; + +pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + +impl<'a> InvariantRef<'a, ()> { + pub const NEW: Self = InvariantRef::new(&()); + //~^ ERROR: no function or associated item named `new` found +} + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } + fn meh(&self) -> u8 { 2 } +} + +struct Z(u8); + +impl Trait for Z { + reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + //~^ ERROR: use of undeclared lifetime name `'a` + //~| ERROR: use of undeclared lifetime name `'a` + //~| ERROR: use of undeclared lifetime name `'a` + //~| ERROR: the trait bound `u8: Trait` is not satisfied + //~| ERROR: the trait bound `u8: Trait` is not satisfied + //~| ERROR: the trait bound `u8: Trait` is not satisfied + //~| ERROR: mismatched types + //~| ERROR: mismatched types + //~| ERROR: mismatched types +} + +fn main() { } diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr new file mode 100644 index 00000000000..2ce3b388073 --- /dev/null +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr @@ -0,0 +1,113 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | reuse ::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } } + | +++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> Trait for Z { + | ++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | reuse ::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } } + | +++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> Trait for Z { + | ++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | reuse ::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } } + | +++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> Trait for Z { + | ++++ + +error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41 + | +LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + | -------------------------------------- function or associated item `new` not found for this struct +... +LL | pub const NEW: Self = InvariantRef::new(&()); + | ^^^ function or associated item not found in `InvariantRef<'_, _>` + +error[E0308]: mismatched types + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>` + | + = note: expected type `u8` + found struct `InvariantRef<'_, ()>` + +error[E0277]: the trait bound `u8: Trait` is not satisfied + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ the trait `Trait` is not implemented for `u8` + | + = help: the trait `Trait` is implemented for `Z` + +error[E0308]: mismatched types + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>` + | + = note: expected type `u8` + found struct `InvariantRef<'_, ()>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `u8: Trait` is not satisfied + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ the trait `Trait` is not implemented for `u8` + | + = help: the trait `Trait` is implemented for `Z` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0308]: mismatched types + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>` + | + = note: expected type `u8` + found struct `InvariantRef<'_, ()>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `u8: Trait` is not satisfied + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12 + | +LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } } + | ^^ the trait `Trait` is not implemented for `u8` + | + = help: the trait `Trait` is implemented for `Z` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0261, E0277, E0308, E0599. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/typeck/const-in-fn-call-generics.rs b/tests/ui/typeck/const-in-fn-call-generics.rs new file mode 100644 index 00000000000..675dbcc3054 --- /dev/null +++ b/tests/ui/typeck/const-in-fn-call-generics.rs @@ -0,0 +1,16 @@ +fn generic() {} + +trait Collate { + type Pass; + fn collate(self) -> Self::Pass; +} + +impl Collate for i32 { + type Pass = (); + fn collate(self) -> Self::Pass { + generic::<{ true }>() + //~^ ERROR: mismatched types + } +} + +fn main() {} diff --git a/tests/ui/typeck/const-in-fn-call-generics.stderr b/tests/ui/typeck/const-in-fn-call-generics.stderr new file mode 100644 index 00000000000..12dd454188c --- /dev/null +++ b/tests/ui/typeck/const-in-fn-call-generics.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/const-in-fn-call-generics.rs:11:21 + | +LL | generic::<{ true }>() + | ^^^^ expected `u32`, found `bool` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.