From a052f2cce1df8ac5ac9fcd104c948545f8b5f2f4 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 20 Sep 2022 11:55:07 +0000 Subject: [PATCH 01/20] Add the `#[derive_const]` attribute --- .../src/cfg_accessible.rs | 1 + compiler/rustc_builtin_macros/src/derive.rs | 9 ++--- .../src/deriving/bounds.rs | 2 ++ .../src/deriving/clone.rs | 2 ++ .../src/deriving/cmp/eq.rs | 2 ++ .../src/deriving/cmp/ord.rs | 2 ++ .../src/deriving/cmp/partial_eq.rs | 2 ++ .../src/deriving/cmp/partial_ord.rs | 2 ++ .../src/deriving/debug.rs | 2 ++ .../src/deriving/decodable.rs | 2 ++ .../src/deriving/default.rs | 2 ++ .../src/deriving/encodable.rs | 2 ++ .../src/deriving/generic/mod.rs | 6 ++-- .../rustc_builtin_macros/src/deriving/hash.rs | 2 ++ .../rustc_builtin_macros/src/deriving/mod.rs | 35 ++++++++++++------- compiler/rustc_builtin_macros/src/lib.rs | 3 +- compiler/rustc_expand/src/base.rs | 4 ++- compiler/rustc_expand/src/expand.rs | 13 +++---- compiler/rustc_expand/src/proc_macro.rs | 1 + compiler/rustc_resolve/src/macros.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 13 +++++++ library/core/src/prelude/v1.rs | 4 +++ library/std/src/prelude/v1.rs | 4 +++ src/test/ui/issues/issue-32655.stderr | 14 ++++++-- .../const_derives/derive-const-gate.rs | 4 +++ .../const_derives/derive-const-gate.stderr | 11 ++++++ .../derive-const-non-const-type.rs | 13 +++++++ .../derive-const-non-const-type.stderr | 14 ++++++++ .../const_derives/derive-const-use.rs | 19 ++++++++++ 30 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index cb5359dd1e27e..86df3c44eb334 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -34,6 +34,7 @@ impl MultiItemModifier for Expander { span: Span, meta_item: &ast::MetaItem, item: Annotatable, + _is_derive_const: bool, ) -> ExpandResult, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; let attr = &ecx.attribute(meta_item.clone()); diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index e0fb7affb3498..01f237e6ab5fa 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -10,7 +10,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -pub(crate) struct Expander; +pub(crate) struct Expander(pub bool); impl MultiItemModifier for Expander { fn expand( @@ -19,6 +19,7 @@ impl MultiItemModifier for Expander { span: Span, meta_item: &ast::MetaItem, item: Annotatable, + _: bool, ) -> ExpandResult, Annotatable> { let sess = ecx.sess; if report_bad_target(sess, &item, span) { @@ -58,20 +59,20 @@ impl MultiItemModifier for Expander { report_path_args(sess, &meta); meta.path }) - .map(|path| (path, dummy_annotatable(), None)) + .map(|path| (path, dummy_annotatable(), None, self.0)) .collect(); // Do not configure or clone items unless necessary. match &mut resolutions[..] { [] => {} - [(_, first_item, _), others @ ..] => { + [(_, first_item, ..), others @ ..] => { *first_item = cfg_eval( sess, features, item.clone(), ecx.current_expansion.lint_node_id, ); - for (_, item, _) in others { + for (_, item, _, _) in others { *item = first_item.clone(); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 77e0b6c55a80e..3a5b7ecde8a9e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -12,6 +12,7 @@ pub fn expand_deriving_copy( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let trait_def = TraitDef { span, @@ -21,6 +22,7 @@ pub fn expand_deriving_copy( supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index c7f2d95e72f0c..6d9be879cd19f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -14,6 +14,7 @@ pub fn expand_deriving_clone( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { // The simple form is `fn clone(&self) -> Self { *self }`, possibly with // some additional `AssertParamIsClone` assertions. @@ -86,6 +87,7 @@ pub fn expand_deriving_clone( combine_substructure: substructure, }], associated_types: Vec::new(), + is_const, }; trait_def.expand_ext(cx, mitem, item, push, is_simple) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 5b556c5c9b9d1..9c01314112a59 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -15,6 +15,7 @@ pub fn expand_deriving_eq( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let span = cx.with_def_site_ctxt(span); let inline = cx.meta_word(span, sym::inline); @@ -41,6 +42,7 @@ pub fn expand_deriving_eq( })), }], associated_types: Vec::new(), + is_const, }; super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 7262586955811..d5c81c387834e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_ord( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let inline = cx.meta_word(span, sym::inline); let attrs = thin_vec![cx.attribute(inline)]; @@ -33,6 +34,7 @@ pub fn expand_deriving_ord( combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 42ee65b570a2a..11b838a076c6d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -14,6 +14,7 @@ pub fn expand_deriving_partial_eq( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let base = true; @@ -88,6 +89,7 @@ pub fn expand_deriving_partial_eq( supports_unions: false, methods, associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 516892aeda96f..107a01190bb40 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_partial_ord( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let ordering_ty = Path(path_std!(cmp::Ordering)); let ret_ty = @@ -42,6 +43,7 @@ pub fn expand_deriving_partial_ord( supports_unions: false, methods: vec![partial_cmp_def], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 4af7fd8165388..cf977c0824d8d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_debug( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { // &mut ::std::fmt::Formatter let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut); @@ -36,6 +37,7 @@ pub fn expand_deriving_debug( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 7174dbbe7ea8b..a27a068f31a27 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -16,6 +16,7 @@ pub fn expand_deriving_rustc_decodable( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let krate = sym::rustc_serialize; let typaram = sym::__D; @@ -54,6 +55,7 @@ pub fn expand_deriving_rustc_decodable( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index a94c8a996e642..35b23f2f8f31a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -16,6 +16,7 @@ pub fn expand_deriving_default( mitem: &ast::MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); @@ -46,6 +47,7 @@ pub fn expand_deriving_default( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index b220e54238f46..f06cf0c56bc70 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -100,6 +100,7 @@ pub fn expand_deriving_rustc_encodable( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let krate = sym::rustc_serialize; let typaram = sym::__S; @@ -138,6 +139,7 @@ pub fn expand_deriving_rustc_encodable( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3cc160adb5397..78dbe8e5979e2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -171,7 +171,7 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; use std::iter; use std::vec; @@ -200,6 +200,8 @@ pub struct TraitDef<'a> { pub methods: Vec>, pub associated_types: Vec<(Ident, Ty)>, + + pub is_const: bool, } pub struct MethodDef<'a> { @@ -726,7 +728,7 @@ impl<'a> TraitDef<'a> { unsafety: ast::Unsafe::No, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, - constness: ast::Const::No, + constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f1f02e7ce7787..ef3da94f9e3f5 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_hash( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std); @@ -38,6 +39,7 @@ pub fn expand_deriving_hash( })), }], associated_types: Vec::new(), + is_const, }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index a65d0bad6de80..5b89da91d4278 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -38,9 +38,10 @@ pub mod partial_ord; pub mod generic; -pub(crate) struct BuiltinDerive( - pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), -); +pub(crate) type BuiltinDeriveFn = + fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); + +pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); impl MultiItemModifier for BuiltinDerive { fn expand( @@ -49,6 +50,7 @@ impl MultiItemModifier for BuiltinDerive { span: Span, meta_item: &MetaItem, item: Annotatable, + is_derive_const: bool, ) -> ExpandResult, Annotatable> { // FIXME: Built-in derives often forget to give spans contexts, // so we are doing it here in a centralized way. @@ -57,21 +59,28 @@ impl MultiItemModifier for BuiltinDerive { match item { Annotatable::Stmt(stmt) => { if let ast::StmtKind::Item(item) = stmt.into_inner().kind { - (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| { - // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' - // to the function - items.push(Annotatable::Stmt(P(ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(a.expect_item()), - span, - }))); - }); + (self.0)( + ecx, + span, + meta_item, + &Annotatable::Item(item), + &mut |a| { + // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' + // to the function + items.push(Annotatable::Stmt(P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(a.expect_item()), + span, + }))); + }, + is_derive_const, + ); } else { unreachable!("should have already errored on non-item statement") } } _ => { - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); + (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const); } } ExpandResult::Ready(items) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 8aeb3b82a9cd0..ab1fcde16865f 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -97,7 +97,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, - derive: derive::Expander, + derive: derive::Expander(false), + derive_const: derive::Expander(true), global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e1da3ecdec7f4..b3d187848be9c 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -248,6 +248,7 @@ pub trait MultiItemModifier { span: Span, meta_item: &ast::MetaItem, item: Annotatable, + is_derive_const: bool, ) -> ExpandResult, Annotatable>; } @@ -261,6 +262,7 @@ where span: Span, meta_item: &ast::MetaItem, item: Annotatable, + _is_derive_const: bool, ) -> ExpandResult, Annotatable> { ExpandResult::Ready(self(ecx, span, meta_item, item)) } @@ -871,7 +873,7 @@ impl SyntaxExtension { /// Error type that denotes indeterminacy. pub struct Indeterminate; -pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option>)>; +pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option>, bool)>; pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c2add852a0679..a63b59d31cfd9 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -319,6 +319,7 @@ pub enum InvocationKind { }, Derive { path: ast::Path, + is_const: bool, item: Annotatable, }, } @@ -460,13 +461,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derive_invocations.reserve(derives.len()); derives .into_iter() - .map(|(path, item, _exts)| { + .map(|(path, item, _exts, is_const)| { // FIXME: Consider using the derive resolutions (`_exts`) // instead of enqueuing the derives to be resolved again later. let expn_id = LocalExpnId::fresh_empty(); derive_invocations.push(( Invocation { - kind: InvocationKind::Derive { path, item }, + kind: InvocationKind::Derive { path, item, is_const }, fragment_kind, expansion_data: ExpansionData { id: expn_id, @@ -699,7 +700,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) { Ok(meta) => { - let items = match expander.expand(self.cx, span, &meta, item) { + let items = match expander.expand(self.cx, span, &meta, item, false) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { // Reassemble the original invocation for retrying. @@ -731,19 +732,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!(), }, - InvocationKind::Derive { path, item } => match ext { + InvocationKind::Derive { path, item, is_const } => match ext { SyntaxExtensionKind::Derive(expander) | SyntaxExtensionKind::LegacyDerive(expander) => { if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path }; - let items = match expander.expand(self.cx, span, &meta, item) { + let items = match expander.expand(self.cx, span, &meta, item, is_const) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { // Reassemble the original invocation for retrying. return ExpandResult::Retry(Invocation { - kind: InvocationKind::Derive { path: meta.path, item }, + kind: InvocationKind::Derive { path: meta.path, item, is_const }, ..invoc }); } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 1a2ab9d190ebd..e9a6919206894 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -112,6 +112,7 @@ impl MultiItemModifier for DeriveProcMacro { span: Span, _meta_item: &ast::MetaItem, item: Annotatable, + _is_derive_const: bool, ) -> ExpandResult, Annotatable> { // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dafa10e9e0026..8ef99e5ef968a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -356,7 +356,7 @@ impl<'a> ResolverExpand for Resolver<'a> { has_derive_copy: false, }); let parent_scope = self.invocation_parent_scopes[&expn_id]; - for (i, (path, _, opt_ext)) in entry.resolutions.iter_mut().enumerate() { + for (i, (path, _, opt_ext, _)) in entry.resolutions.iter_mut().enumerate() { if opt_ext.is_none() { *opt_ext = Some( match self.resolve_macro_path( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 562360130e92f..0a9570979d5af 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -614,6 +614,7 @@ symbols! { deref_mut, deref_target, derive, + derive_const, derive_default_enum, destruct, destructuring_assignment, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index fd96e1ff77d53..e504db8143447 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1464,6 +1464,19 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// Attribute macro used to apply derive macros for implementing traits + /// in a const context. + /// + /// See [the reference] for more info. + /// + /// [the reference]: ../../../reference/attributes/derive.html + #[unstable(feature = "derive_const", issue = "none")] + #[rustc_builtin_macro] + #[cfg(not(bootstrap))] + pub macro derive_const($item:item) { + /* compiler built-in */ + } + /// Attribute macro applied to a function to turn it into a unit test. /// /// See [the reference] for more info. diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index b566e211cd89d..f52c06d7eadc2 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -78,6 +78,10 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case}; +#[unstable(feature = "derive_const", issue = "none")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::derive_const; + #[unstable( feature = "cfg_accessible", issue = "64797", diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 0226c4d7a2581..93f4a17bbfca3 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -62,6 +62,10 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case}; +#[unstable(feature = "derive_const", issue = "none")] +#[cfg(not(bootstrap))] +pub use core::prelude::v1::derive_const; + // Do not `doc(no_inline)` either. #[unstable( feature = "cfg_accessible", diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr index 2d9ce430a462d..5a758c7002b92 100644 --- a/src/test/ui/issues/issue-32655.stderr +++ b/src/test/ui/issues/issue-32655.stderr @@ -2,18 +2,28 @@ error: cannot find attribute `derive_Clone` in this scope --> $DIR/issue-32655.rs:3:11 | LL | #[derive_Clone] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const` ... LL | foo!(); | ------ in this macro invocation | + ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | pub macro derive_const($item:item) { + | ---------------------- similarly named attribute macro `derive_const` defined here + | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find attribute `derive_Clone` in this scope --> $DIR/issue-32655.rs:15:7 | LL | #[derive_Clone] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const` + | + ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | pub macro derive_const($item:item) { + | ---------------------- similarly named attribute macro `derive_const` defined here error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs new file mode 100644 index 0000000000000..348ca0ab1906b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs @@ -0,0 +1,4 @@ +#[derive_const(Default)] //~ ERROR use of unstable library feature +pub struct S; + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr new file mode 100644 index 0000000000000..cc9bdd2715f70 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'derive_const' + --> $DIR/derive-const-gate.rs:1:3 + | +LL | #[derive_const(Default)] + | ^^^^^^^^^^^^ + | + = help: add `#![feature(derive_const)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs new file mode 100644 index 0000000000000..92843a8a2da48 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs @@ -0,0 +1,13 @@ +#![feature(derive_const)] + +pub struct A; + +impl Default for A { + fn default() -> A { A } +} + +#[derive_const(Default)] +pub struct S(A); +//~^ cannot call non-const fn + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr new file mode 100644 index 0000000000000..d463c774e289e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -0,0 +1,14 @@ +error[E0015]: cannot call non-const fn `::default` in constant functions + --> $DIR/derive-const-non-const-type.rs:10:14 + | +LL | #[derive_const(Default)] + | ------- in this derive macro expansion +LL | pub struct S(A); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs new file mode 100644 index 0000000000000..d1fbeac8598e4 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs @@ -0,0 +1,19 @@ +// check-pass +#![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)] + +pub struct A; + +impl const Default for A { + fn default() -> A { A } +} + +impl const PartialEq for A { + fn eq(&self, _: &A) -> bool { true } +} + +#[derive_const(Default, PartialEq)] +pub struct S((), A); + +const _: () = assert!(S((), A) == S::default()); + +fn main() {} From 2f7b4d91e21863cd7e9ffc24d18299db432639c5 Mon Sep 17 00:00:00 2001 From: Alex Brachet Date: Mon, 10 Oct 2022 20:13:10 +0000 Subject: [PATCH 02/20] Don't internalize __llvm_profile_counter_bias Currently, LLVM profiling runtime counter relocation cannot be used by rust during LTO because symbols are being internalized before all symbol information is known. This mode makes LLVM emit a __llvm_profile_counter_bias symbol which is referenced by the profiling initialization, which itself is pulled in by the rust driver here [1]. It is enabled with -Cllvm-args=-runtime-counter-relocation for platforms which are opt-in to this mode like Linux. On these platforms there will be no link error, rather just surprising behavior for a user which request runtime counter relocation. The profiling runtime will not see that symbol go on as if it were never there. On Fuchsia, the profiling runtime must have this symbol which will cause a hard link error. As an aside, I don't have enough context as to why rust's LTO model is how it is. AFAICT, the internalize pass is only safe to run at link time when all symbol information is actually known, this being an example as to why. I think special casing this symbol as a known one that LLVM can emit which should not have it's visbility de-escalated should be fine given how seldom this pattern of defining an undefined symbol to get initilization code pulled in is. From a quick grep, __llvm_profile_runtime is the only symbol that rustc does this for. [1] https://github.com/rust-lang/rust/blob/0265a3e93bf1b89d97cae113ed214954d5c35e22/compiler/rustc_codegen_ssa/src/back/linker.rs#L598 --- .../rustc_codegen_ssa/src/back/symbol_export.rs | 15 +++++++++++---- src/test/codegen/pgo-counter-bias.rs | 9 +++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/test/codegen/pgo-counter-bias.rs diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8d7e2c5cf3939..341b28424e40b 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -212,10 +212,17 @@ fn exported_symbols_provider_local<'tcx>( // These are weak symbols that point to the profile version and the // profile name, which need to be treated as exported so LTO doesn't nix // them. - const PROFILER_WEAK_SYMBOLS: [&str; 2] = - ["__llvm_profile_raw_version", "__llvm_profile_filename"]; - - symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { + // __llvm_profile_counter_bias is not weak, but is only referenced by the + // profiling initialization runtime, which is itself pulled in by an + // undefined reference to __llvm_profile_runtime. This happens at link time + // and thus this symbol cannot be internalized until then. + const PROFILER_DEFAULT_VIS_SYMBOLS: [&str; 3] = [ + "__llvm_profile_raw_version", + "__llvm_profile_filename", + "__llvm_profile_counter_bias", + ]; + + symbols.extend(PROFILER_DEFAULT_VIS_SYMBOLS.iter().map(|sym| { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); ( exported_symbol, diff --git a/src/test/codegen/pgo-counter-bias.rs b/src/test/codegen/pgo-counter-bias.rs new file mode 100644 index 0000000000000..b9019e9de7b22 --- /dev/null +++ b/src/test/codegen/pgo-counter-bias.rs @@ -0,0 +1,9 @@ +// Test that __llvm_profile_counter_bias does not get internalized by lto. + +// compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat +// needs-profiler-support +// no-prefer-dynamic + +// CHECK: @__llvm_profile_counter_bias = {{.*}}global + +pub fn main() {} From 9bcc083c873be61e62446d0240a72f99d71350e0 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 7 Nov 2022 14:43:28 +0000 Subject: [PATCH 03/20] run-make-fulldeps: fix split debuginfo test Add lots of comments to this test and enable parts of the test that were added but never ran. Signed-off-by: David Wood --- .../split-debuginfo/Makefile | 160 ++++++++++++++++-- 1 file changed, 145 insertions(+), 15 deletions(-) diff --git a/src/test/run-make-fulldeps/split-debuginfo/Makefile b/src/test/run-make-fulldeps/split-debuginfo/Makefile index 1032f3408f062..a511aff4f3af2 100644 --- a/src/test/run-make-fulldeps/split-debuginfo/Makefile +++ b/src/test/run-make-fulldeps/split-debuginfo/Makefile @@ -3,7 +3,7 @@ include ../tools.mk all: off packed unpacked ifeq ($(UNAME),Darwin) -# If disabled, don't run dsymutil +# If disabled, don't run `dsymutil`. off: rm -rf $(TMPDIR)/*.dSYM $(RUSTC) foo.rs -g -C split-debuginfo=off @@ -29,98 +29,228 @@ unpacked: [ ! -d $(TMPDIR)/foo.dSYM ] else ifdef IS_WINDOWS -# Windows only supports =packed +# Windows only supports packed debuginfo - nothing to test. off: packed: unpacked: else +# Some non-Windows, non-Darwin platforms are not stable, and some are. ifeq ($(UNAME),Linux) UNSTABLEOPTS := else UNSTABLEOPTS := -Zunstable-options endif +# - Debuginfo in `.o` files +# - `.o` deleted +# - `.dwo` never created +# - `.dwp` never created off: $(RUSTC) foo.rs -g -C $(UNSTABLEOPTS) split-debuginfo=off [ ! -f $(TMPDIR)/*.dwp ] [ ! -f $(TMPDIR)/*.dwo ] - $(RUSTC) foo.rs -g [ ! -f $(TMPDIR)/*.dwp ] [ ! -f $(TMPDIR)/*.dwo ] -packed: packed-split packed-single +packed: packed-split packed-single packed-remapped packed-crosscrate +# - Debuginfo in `.dwo` files +# - `.o` deleted +# - `.dwo` deleted +# - `.dwp` present packed-split: $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=split - ls $(TMPDIR)/*.dwp - rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + rm $(TMPDIR)/foo.dwp + rm $(TMPDIR)/$(call BIN,foo) +# - Debuginfo in `.o` files +# - `.o` deleted +# - `.dwo` never created +# - `.dwp` present packed-single: $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=single - ls $(TMPDIR)/*.dwp + ls $(TMPDIR)/*.o && exit 1 || exit 0 ls $(TMPDIR)/*.dwo && exit 1 || exit 0 - rm -rf $(TMPDIR)/*.dwp + rm $(TMPDIR)/foo.dwp + rm $(TMPDIR)/$(call BIN,foo) packed-remapped: packed-remapped-split packed-remapped-single +# - Debuginfo in `.dwo` files +# - `.o` and binary refer to remapped `.dwo` paths which do not exist +# - `.o` deleted +# - `.dwo` deleted +# - `.dwp` present packed-remapped-split: $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \ -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1 + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + rm $(TMPDIR)/foo.dwp + rm $(TMPDIR)/$(call BIN,foo) +# - Debuginfo in `.o` files +# - `.o` and binary refer to remapped `.o` paths which do not exist +# - `.o` deleted +# - `.dwo` never created +# - `.dwp` present packed-remapped-single: $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \ -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1 + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + rm $(TMPDIR)/foo.dwp + rm $(TMPDIR)/$(call BIN,foo) packed-crosscrate: packed-crosscrate-split packed-crosscrate-single +# - Debuginfo in `.dwo` files +# - (bar) `.rlib` file created, contains `.dwo` +# - (bar) `.o` deleted +# - (bar) `.dwo` deleted +# - (bar) `.dwp` never created +# - (main) `.o` deleted +# - (main) `.dwo` deleted +# - (main) `.dwp` present packed-crosscrate-split: $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \ -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs ls $(TMPDIR)/*.rlib + ls $(TMPDIR)/*.o && exit 1 || exit 0 ls $(TMPDIR)/*.dwo && exit 1 || exit 0 ls $(TMPDIR)/*.dwp && exit 1 || exit 0 - $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \ + $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \ -C split-debuginfo=packed -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs - rm $(TMPDIR)/*.dwo + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 rm $(TMPDIR)/main.dwp rm $(TMPDIR)/$(call BIN,main) +# - Debuginfo in `.o` files +# - (bar) `.rlib` file created, contains `.o` +# - (bar) `.o` deleted +# - (bar) `.dwo` never created +# - (bar) `.dwp` never created +# - (main) `.o` deleted +# - (main) `.dwo` never created +# - (main) `.dwp` present packed-crosscrate-single: $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \ -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs ls $(TMPDIR)/*.rlib + ls $(TMPDIR)/*.o && exit 1 || exit 0 ls $(TMPDIR)/*.dwo && exit 1 || exit 0 ls $(TMPDIR)/*.dwp && exit 1 || exit 0 - $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \ + $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \ -C split-debuginfo=packed -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs + ls $(TMPDIR)/*.o && exit 1 || exit 0 ls $(TMPDIR)/*.dwo && exit 1 || exit 0 rm $(TMPDIR)/main.dwp rm $(TMPDIR)/$(call BIN,main) -unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single +unpacked: unpacked-split unpacked-single unpacked-remapped unpacked-crosscrate +# - Debuginfo in `.dwo` files +# - `.o` deleted +# - `.dwo` present +# - `.dwp` never created unpacked-split: $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=split + ls $(TMPDIR)/*.o && exit 1 || exit 0 + rm $(TMPDIR)/*.dwo ls $(TMPDIR)/*.dwp && exit 1 || exit 0 - ls $(TMPDIR)/*.dwo - rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo + rm $(TMPDIR)/$(call BIN,foo) +# - Debuginfo in `.o` files +# - `.o` present +# - `.dwo` never created +# - `.dwp` never created unpacked-single: $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=single - ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + ls $(TMPDIR)/*.o ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/$(call BIN,foo) + +unpacked-remapped: unpacked-remapped-split unpacked-remapped-single +# - Debuginfo in `.dwo` files +# - `.o` and binary refer to remapped `.dwo` paths which do not exist +# - `.o` deleted +# - `.dwo` present +# - `.dwp` never created unpacked-remapped-split: $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \ -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1 + ls $(TMPDIR)/*.o && exit 1 || exit 0 + rm $(TMPDIR)/*.dwo + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/$(call BIN,foo) +# - Debuginfo in `.o` files +# - `.o` and binary refer to remapped `.o` paths which do not exist +# - `.o` present +# - `.dwo` never created +# - `.dwp` never created unpacked-remapped-single: $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \ -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1 + ls $(TMPDIR)/*.o + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/$(call BIN,foo) + +unpacked-crosscrate: packed-crosscrate-split packed-crosscrate-single + +# - Debuginfo in `.dwo` files +# - (bar) `.rlib` file created, contains `.dwo` +# - (bar) `.o` deleted +# - (bar) `.dwo` present +# - (bar) `.dwp` never created +# - (main) `.o` deleted +# - (main) `.dwo` present +# - (main) `.dwp` never created +unpacked-crosscrate-split: + $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=unpacked \ + -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs + ls $(TMPDIR)/*.rlib + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \ + -C split-debuginfo=unpacked -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs + ls $(TMPDIR)/*.o && exit 1 || exit 0 + rm $(TMPDIR)/*.dwo + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/$(call BIN,main) + +# - Debuginfo in `.o` files +# - (bar) `.rlib` file created, contains `.o` +# - (bar) `.o` present +# - (bar) `.dwo` never created +# - (bar) `.dwp` never created +# - (main) `.o` present +# - (main) `.dwo` never created +# - (main) `.dwp` never created +unpacked-crosscrate-single: + $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=unpacked \ + -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs + ls $(TMPDIR)/*.rlib + ls $(TMPDIR)/*.o + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \ + -C split-debuginfo=unpacked -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs + ls $(TMPDIR)/*.o + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/$(call BIN,main) endif endif From 29dc08307dde3051ab6bf17c53f2db99e32681ee Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 7 Nov 2022 15:15:24 +0000 Subject: [PATCH 04/20] llvm: dwo only emitted when object code emitted `CompiledModule` should not think a DWARF object was emitted when a bitcode-only compilation has happened, this can confuse archive file creation (which expects to create an archive containing non-existent dwo files). Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/src/back/write.rs | 16 +++++- .../split-debuginfo/Makefile | 56 ++++++++++++++++++- .../run-make-fulldeps/split-debuginfo/baz.rs | 1 + 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/test/run-make-fulldeps/split-debuginfo/baz.rs diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 11053a8f6c452..97d0de47b3a6e 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -765,11 +765,21 @@ pub(crate) unsafe fn codegen( drop(handlers); } + // `.dwo` files are only emitted if: + // + // - Object files are being emitted (i.e. bitcode only or metadata only compilations will not + // produce dwarf objects, even if otherwise enabled) + // - Target supports Split DWARF + // - Split debuginfo is enabled + // - Split DWARF kind is `split` (i.e. debuginfo is split into `.dwo` files, not different + // sections in the `.o` files). + let dwarf_object_emitted = matches!(config.emit_obj, EmitObj::ObjectCode(_)) + && cgcx.target_can_use_split_dwarf + && cgcx.split_debuginfo != SplitDebuginfo::Off + && cgcx.split_dwarf_kind == SplitDwarfKind::Split; Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, - cgcx.target_can_use_split_dwarf - && cgcx.split_debuginfo != SplitDebuginfo::Off - && cgcx.split_dwarf_kind == SplitDwarfKind::Split, + dwarf_object_emitted, config.emit_bc, &cgcx.output_filenames, )) diff --git a/src/test/run-make-fulldeps/split-debuginfo/Makefile b/src/test/run-make-fulldeps/split-debuginfo/Makefile index a511aff4f3af2..1831ab38fab49 100644 --- a/src/test/run-make-fulldeps/split-debuginfo/Makefile +++ b/src/test/run-make-fulldeps/split-debuginfo/Makefile @@ -53,7 +53,7 @@ off: [ ! -f $(TMPDIR)/*.dwp ] [ ! -f $(TMPDIR)/*.dwo ] -packed: packed-split packed-single packed-remapped packed-crosscrate +packed: packed-split packed-single packed-lto packed-remapped packed-crosscrate # - Debuginfo in `.dwo` files # - `.o` deleted @@ -77,6 +77,32 @@ packed-single: rm $(TMPDIR)/foo.dwp rm $(TMPDIR)/$(call BIN,foo) +packed-lto: packed-lto-split packed-lto-single + +# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated +# - `.o` never created +# - `.dwo` never created +# - `.dwp` never created +packed-lto-split: + $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split \ + --crate-type=rlib -Clinker-plugin-lto + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/libbaz.rlib + +# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated +# - `.o` never created +# - `.dwo` never created +# - `.dwp` never created +packed-lto-single: + $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single \ + --crate-type=rlib -Clinker-plugin-lto + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/libbaz.rlib + packed-remapped: packed-remapped-split packed-remapped-single # - Debuginfo in `.dwo` files @@ -153,7 +179,7 @@ packed-crosscrate-single: rm $(TMPDIR)/main.dwp rm $(TMPDIR)/$(call BIN,main) -unpacked: unpacked-split unpacked-single unpacked-remapped unpacked-crosscrate +unpacked: unpacked-split unpacked-single unpacked-lto unpacked-remapped unpacked-crosscrate # - Debuginfo in `.dwo` files # - `.o` deleted @@ -177,6 +203,32 @@ unpacked-single: ls $(TMPDIR)/*.dwp && exit 1 || exit 0 rm $(TMPDIR)/$(call BIN,foo) +unpacked-lto: packed-lto-split packed-lto-single + +# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated +# - `.o` never created +# - `.dwo` never created +# - `.dwp` never created +unpacked-lto-split: + $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=split \ + --crate-type=rlib -Clinker-plugin-lto + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/libbaz.rlib + +# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated +# - `.o` never created +# - `.dwo` never created +# - `.dwp` never created +unpacked-lto-single: + $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single \ + --crate-type=rlib -Clinker-plugin-lto + ls $(TMPDIR)/*.o && exit 1 || exit 0 + ls $(TMPDIR)/*.dwo && exit 1 || exit 0 + ls $(TMPDIR)/*.dwp && exit 1 || exit 0 + rm $(TMPDIR)/libbaz.rlib + unpacked-remapped: unpacked-remapped-split unpacked-remapped-single # - Debuginfo in `.dwo` files diff --git a/src/test/run-make-fulldeps/split-debuginfo/baz.rs b/src/test/run-make-fulldeps/split-debuginfo/baz.rs new file mode 100644 index 0000000000000..8b1a393741c96 --- /dev/null +++ b/src/test/run-make-fulldeps/split-debuginfo/baz.rs @@ -0,0 +1 @@ +// empty From 0e0bcd95cda4293915ecd68921320a0928cdd0bb Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Fri, 4 Nov 2022 16:27:28 +0000 Subject: [PATCH 05/20] prevent uninitialized access in black_box for zero-sized-types --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 15 +++++++-- src/test/ui/sanitize/memory-passing.rs | 32 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/sanitize/memory-passing.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 825011941a241..cf590a43826e5 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -340,17 +340,26 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::black_box => { args[0].val.store(self, result); - + let result_val_span = [result.llval]; // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black // box. This isn't the greatest implementation since it probably deoptimizes // more than we want, but it's so far good enough. + // + // For zero-sized types, the location pointed to by the result may be + // uninitialized. Do not "use" the result in this case; instead just clobber + // the memory. + let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() { + ("~{memory}", &[]) + } else { + ("r,~{memory}", &result_val_span) + }; crate::asm::inline_asm_call( self, "", - "r,~{memory}", - &[result.llval], + constraint, + inputs, self.type_void(), true, false, diff --git a/src/test/ui/sanitize/memory-passing.rs b/src/test/ui/sanitize/memory-passing.rs new file mode 100644 index 0000000000000..6d9b70ad6b1c2 --- /dev/null +++ b/src/test/ui/sanitize/memory-passing.rs @@ -0,0 +1,32 @@ +// needs-sanitizer-support +// needs-sanitizer-memory +// +// revisions: unoptimized optimized +// +// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins +// +// run-pass +// +// This test case intentionally limits the usage of the std, +// since it will be linked with an uninstrumented version of it. + +#![feature(core_intrinsics)] +#![feature(start)] +#![allow(invalid_value)] + +use std::hint::black_box; + +fn calling_black_box_on_zst_ok() { + // It's OK to call black_box on a value of a zero-sized type, even if its + // underlying the memory location is uninitialized. For non-zero-sized types, + // this would be an MSAN error. + let zst = (); + black_box(zst); +} + +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + calling_black_box_on_zst_ok(); + 0 +} From 3074678cd1c9a2934ef11122b3744523083f1736 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Tue, 8 Nov 2022 02:14:02 +0800 Subject: [PATCH 06/20] Mark `trait_upcasting` feature no longer incomplete. --- compiler/rustc_feature/src/active.rs | 6 +-- src/test/ui/codegen/issue-99551.rs | 1 - src/test/ui/traits/trait-upcasting/basic.rs | 1 - .../correct-supertrait-substitution.rs | 1 - src/test/ui/traits/trait-upcasting/diamond.rs | 1 - .../traits/trait-upcasting/invalid-upcast.rs | 1 - .../trait-upcasting/invalid-upcast.stderr | 30 +++++++------- .../issue-11515-upcast-fn_mut-fn.rs | 1 - .../ui/traits/trait-upcasting/lifetime.rs | 1 - .../multiple-occurrence-ambiguousity.rs | 3 +- .../multiple-occurrence-ambiguousity.stderr | 2 +- .../ui/traits/trait-upcasting/replace-vptr.rs | 1 - src/test/ui/traits/trait-upcasting/struct.rs | 1 - .../traits/trait-upcasting/subtrait-method.rs | 1 - .../trait-upcasting/subtrait-method.stderr | 20 +++++----- .../trait-upcasting/type-checking-test-1.rs | 1 - .../type-checking-test-1.stderr | 4 +- .../trait-upcasting/type-checking-test-2.rs | 1 - .../type-checking-test-2.stderr | 8 ++-- .../type-checking-test-3.polonius.stderr | 8 +--- .../trait-upcasting/type-checking-test-3.rs | 5 +-- .../type-checking-test-3.stderr | 4 +- .../type-checking-test-4.polonius.stderr | 39 ++++++++++++++----- .../trait-upcasting/type-checking-test-4.rs | 13 +++---- .../type-checking-test-4.stderr | 12 +++--- 25 files changed, 83 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 09a747662e266..b6fe48f1bb8a1 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -510,9 +510,9 @@ declare_features! ( (active, thread_local, "1.0.0", Some(29594), None), /// Allows defining `trait X = A + B;` alias items. (active, trait_alias, "1.24.0", Some(41517), None), - /// Allows upcasting trait objects via supertraits. - /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. - (incomplete, trait_upcasting, "1.56.0", Some(65991), None), + /// Allows dyn upcasting trait objects via supertraits. + /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. + (active, trait_upcasting, "1.56.0", Some(65991), None), /// Allows #[repr(transparent)] on unions (RFC 2645). (active, transparent_unions, "1.37.0", Some(60405), None), /// Allows inconsistent bounds in where clauses. diff --git a/src/test/ui/codegen/issue-99551.rs b/src/test/ui/codegen/issue-99551.rs index f24874c992eaf..b223aff4e9492 100644 --- a/src/test/ui/codegen/issue-99551.rs +++ b/src/test/ui/codegen/issue-99551.rs @@ -1,6 +1,5 @@ // build-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] pub trait A {} pub trait B {} diff --git a/src/test/ui/traits/trait-upcasting/basic.rs b/src/test/ui/traits/trait-upcasting/basic.rs index 484a222bc012d..570ec5160bfe9 100644 --- a/src/test/ui/traits/trait-upcasting/basic.rs +++ b/src/test/ui/traits/trait-upcasting/basic.rs @@ -1,7 +1,6 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { diff --git a/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs index 8d0a9ef0ace69..eae5cf8d58d01 100644 --- a/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs +++ b/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs @@ -1,6 +1,5 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: Bar + Bar {} trait Bar { diff --git a/src/test/ui/traits/trait-upcasting/diamond.rs b/src/test/ui/traits/trait-upcasting/diamond.rs index e4e23c1a26e78..a4f81c464b402 100644 --- a/src/test/ui/traits/trait-upcasting/diamond.rs +++ b/src/test/ui/traits/trait-upcasting/diamond.rs @@ -1,7 +1,6 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { diff --git a/src/test/ui/traits/trait-upcasting/invalid-upcast.rs b/src/test/ui/traits/trait-upcasting/invalid-upcast.rs index 24022450406a7..e634bbd5ac6f5 100644 --- a/src/test/ui/traits/trait-upcasting/invalid-upcast.rs +++ b/src/test/ui/traits/trait-upcasting/invalid-upcast.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo { fn a(&self) -> i32 { diff --git a/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr b/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr index b4530ed0c3a94..3aa21ee3dddfb 100644 --- a/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr +++ b/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:54:35 + --> $DIR/invalid-upcast.rs:53:35 | LL | let _: &dyn std::fmt::Debug = baz; | -------------------- ^^^ expected trait `Debug`, found trait `Baz` @@ -10,7 +10,7 @@ LL | let _: &dyn std::fmt::Debug = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:56:24 + --> $DIR/invalid-upcast.rs:55:24 | LL | let _: &dyn Send = baz; | --------- ^^^ expected trait `Send`, found trait `Baz` @@ -21,7 +21,7 @@ LL | let _: &dyn Send = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:58:24 + --> $DIR/invalid-upcast.rs:57:24 | LL | let _: &dyn Sync = baz; | --------- ^^^ expected trait `Sync`, found trait `Baz` @@ -32,7 +32,7 @@ LL | let _: &dyn Sync = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:61:25 + --> $DIR/invalid-upcast.rs:60:25 | LL | let bar: &dyn Bar = baz; | -------- ^^^ expected trait `Bar`, found trait `Baz` @@ -43,7 +43,7 @@ LL | let bar: &dyn Bar = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:63:35 + --> $DIR/invalid-upcast.rs:62:35 | LL | let _: &dyn std::fmt::Debug = bar; | -------------------- ^^^ expected trait `Debug`, found trait `Bar` @@ -54,7 +54,7 @@ LL | let _: &dyn std::fmt::Debug = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:65:24 + --> $DIR/invalid-upcast.rs:64:24 | LL | let _: &dyn Send = bar; | --------- ^^^ expected trait `Send`, found trait `Bar` @@ -65,7 +65,7 @@ LL | let _: &dyn Send = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:67:24 + --> $DIR/invalid-upcast.rs:66:24 | LL | let _: &dyn Sync = bar; | --------- ^^^ expected trait `Sync`, found trait `Bar` @@ -76,7 +76,7 @@ LL | let _: &dyn Sync = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:70:25 + --> $DIR/invalid-upcast.rs:69:25 | LL | let foo: &dyn Foo = baz; | -------- ^^^ expected trait `Foo`, found trait `Baz` @@ -87,7 +87,7 @@ LL | let foo: &dyn Foo = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:72:35 + --> $DIR/invalid-upcast.rs:71:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -98,7 +98,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:74:24 + --> $DIR/invalid-upcast.rs:73:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -109,7 +109,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:76:24 + --> $DIR/invalid-upcast.rs:75:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` @@ -120,7 +120,7 @@ LL | let _: &dyn Sync = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:79:25 + --> $DIR/invalid-upcast.rs:78:25 | LL | let foo: &dyn Foo = bar; | -------- ^^^ expected trait `Foo`, found trait `Bar` @@ -131,7 +131,7 @@ LL | let foo: &dyn Foo = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:81:35 + --> $DIR/invalid-upcast.rs:80:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -142,7 +142,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:83:24 + --> $DIR/invalid-upcast.rs:82:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -153,7 +153,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:85:24 + --> $DIR/invalid-upcast.rs:84:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` diff --git a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs index 6d88002540c1a..b672963ae9887 100644 --- a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +++ b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs @@ -1,6 +1,5 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] struct Test { func: Box, diff --git a/src/test/ui/traits/trait-upcasting/lifetime.rs b/src/test/ui/traits/trait-upcasting/lifetime.rs index f029a6f081f58..9825158c2dd38 100644 --- a/src/test/ui/traits/trait-upcasting/lifetime.rs +++ b/src/test/ui/traits/trait-upcasting/lifetime.rs @@ -1,7 +1,6 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs index 6986ad6217240..2e53a00a90e9c 100644 --- a/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs +++ b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs @@ -1,12 +1,11 @@ // check-fail #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Bar { fn bar(&self, _: T) {} } -trait Foo : Bar + Bar { +trait Foo: Bar + Bar { fn foo(&self, _: ()) {} } diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr index 9564813512c4a..0ad18be03cdf9 100644 --- a/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr +++ b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/multiple-occurrence-ambiguousity.rs:21:26 + --> $DIR/multiple-occurrence-ambiguousity.rs:20:26 | LL | let t: &dyn Bar<_> = s; | ----------- ^ expected trait `Bar`, found trait `Foo` diff --git a/src/test/ui/traits/trait-upcasting/replace-vptr.rs b/src/test/ui/traits/trait-upcasting/replace-vptr.rs index 1164e43611a1d..9ccfc9306ac0c 100644 --- a/src/test/ui/traits/trait-upcasting/replace-vptr.rs +++ b/src/test/ui/traits/trait-upcasting/replace-vptr.rs @@ -1,7 +1,6 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait A { fn foo_a(&self); diff --git a/src/test/ui/traits/trait-upcasting/struct.rs b/src/test/ui/traits/trait-upcasting/struct.rs index 0f3cb285bf4c3..a3e41696956cb 100644 --- a/src/test/ui/traits/trait-upcasting/struct.rs +++ b/src/test/ui/traits/trait-upcasting/struct.rs @@ -1,7 +1,6 @@ // run-pass #![feature(trait_upcasting)] -#![allow(incomplete_features)] use std::rc::Rc; use std::sync::Arc; diff --git a/src/test/ui/traits/trait-upcasting/subtrait-method.rs b/src/test/ui/traits/trait-upcasting/subtrait-method.rs index 3508e15284bf2..136d15af0e8b2 100644 --- a/src/test/ui/traits/trait-upcasting/subtrait-method.rs +++ b/src/test/ui/traits/trait-upcasting/subtrait-method.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { diff --git a/src/test/ui/traits/trait-upcasting/subtrait-method.stderr b/src/test/ui/traits/trait-upcasting/subtrait-method.stderr index af7a410f6d92c..918159e845b9e 100644 --- a/src/test/ui/traits/trait-upcasting/subtrait-method.stderr +++ b/src/test/ui/traits/trait-upcasting/subtrait-method.stderr @@ -1,64 +1,64 @@ error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope - --> $DIR/subtrait-method.rs:56:9 + --> $DIR/subtrait-method.rs:55:9 | LL | bar.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:28:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:60:9 + --> $DIR/subtrait-method.rs:59:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:18:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:62:9 + --> $DIR/subtrait-method.rs:61:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:28:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:66:9 + --> $DIR/subtrait-method.rs:65:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:18:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:68:9 + --> $DIR/subtrait-method.rs:67:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:28:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs index 79ddedd418756..6bc9f4a75d333 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: Bar + Bar {} trait Bar { diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr index 3985372119e88..fe269d8e99bf5 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:16:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ invalid cast @@ -10,7 +10,7 @@ LL | let _ = &x as &dyn Bar<_>; // Ambiguous | + error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:16:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs index 32754c5380378..36b11dffdb158 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo: Bar + Bar {} trait Bar { diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr index 93c71f54eb53a..ef007d5cb909f 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` - --> $DIR/type-checking-test-2.rs:20:13 + --> $DIR/type-checking-test-2.rs:19:13 | LL | let _ = x as &dyn Bar; // Error | ^^^^^^^^^^^^^^^^^^ invalid cast @@ -10,7 +10,7 @@ LL | let _ = &x as &dyn Bar; // Error | + error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied - --> $DIR/type-checking-test-2.rs:20:13 + --> $DIR/type-checking-test-2.rs:19:13 | LL | let _ = x as &dyn Bar; // Error | ^ the trait `Bar` is not implemented for `&dyn Foo` @@ -18,7 +18,7 @@ LL | let _ = x as &dyn Bar; // Error = note: required for the cast from `&dyn Foo` to the object type `dyn Bar` error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-2.rs:26:13 + --> $DIR/type-checking-test-2.rs:25:13 | LL | let a = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ invalid cast @@ -29,7 +29,7 @@ LL | let a = &x as &dyn Bar<_>; // Ambiguous | + error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied - --> $DIR/type-checking-test-2.rs:26:13 + --> $DIR/type-checking-test-2.rs:25:13 | LL | let a = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.polonius.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-3.polonius.stderr index e48ba709af1fd..e6cb6a753998f 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-3.polonius.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.polonius.stderr @@ -1,22 +1,18 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:13:13 + --> $DIR/type-checking-test-3.rs:11:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'a>; // Error | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:18:13 + --> $DIR/type-checking-test-3.rs:16:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'static>; // Error | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs index b3aa2279a30a0..b2db3a127974c 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo<'a>: Bar<'a> {} trait Bar<'a> {} @@ -10,12 +9,12 @@ fn test_correct(x: &dyn Foo<'static>) { fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { let _ = x as &dyn Bar<'a>; // Error - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong2<'a>(x: &dyn Foo<'a>) { let _ = x as &dyn Bar<'static>; // Error - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr index 5ad151b50924d..e6cb6a753998f 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:12:13 + --> $DIR/type-checking-test-3.rs:11:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'a>; // Error | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:17:13 + --> $DIR/type-checking-test-3.rs:16:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { | -- lifetime `'a` defined here diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.polonius.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.polonius.stderr index a3411f40ad0fb..8d506e5807ece 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.polonius.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.polonius.stderr @@ -1,33 +1,52 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:17:13 + --> $DIR/type-checking-test-4.rs:15:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'static, 'a>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:22:13 + --> $DIR/type-checking-test-4.rs:20:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'a, 'static>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:29:5 + --> $DIR/type-checking-test-4.rs:26:5 | LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here -... +LL | let y = x as &dyn Bar<'_, '_>; LL | y.get_b() // ERROR | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/type-checking-test-4.rs:31:5 + | +LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | -- lifetime `'a` defined here +LL | <_ as Bar>::get_b(x) // ERROR + | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/type-checking-test-4.rs:36:5 + | +LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | -- lifetime `'a` defined here +LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/type-checking-test-4.rs:44:5 | - = help: consider replacing `'a` with `'static` +LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | -- lifetime `'a` defined here +... +LL | z.get_b() // ERROR + | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs index 70ccc87fc3e14..f40c48f0d125f 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -1,5 +1,4 @@ #![feature(trait_upcasting)] -#![allow(incomplete_features)] trait Foo<'a>: Bar<'a, 'a> {} trait Bar<'a, 'b> { @@ -14,28 +13,28 @@ fn test_correct(x: &dyn Foo<'static>) { fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { let _ = x as &dyn Bar<'static, 'a>; // Error - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { let _ = x as &dyn Bar<'a, 'static>; // Error - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { let y = x as &dyn Bar<'_, '_>; y.get_b() // ERROR - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { <_ as Bar>::get_b(x) // ERROR - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { <_ as Bar<'_, '_>>::get_b(x) // ERROR - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { @@ -43,7 +42,7 @@ fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { y.get_b(); // ERROR let z = y; z.get_b() // ERROR - //~^ ERROR lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 436129d0bee52..8d506e5807ece 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:16:13 + --> $DIR/type-checking-test-4.rs:15:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'static, 'a>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:21:13 + --> $DIR/type-checking-test-4.rs:20:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -15,7 +15,7 @@ LL | let _ = x as &dyn Bar<'a, 'static>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:27:5 + --> $DIR/type-checking-test-4.rs:26:5 | LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -24,7 +24,7 @@ LL | y.get_b() // ERROR | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:32:5 + --> $DIR/type-checking-test-4.rs:31:5 | LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -32,7 +32,7 @@ LL | <_ as Bar>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:37:5 + --> $DIR/type-checking-test-4.rs:36:5 | LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -40,7 +40,7 @@ LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:45:5 + --> $DIR/type-checking-test-4.rs:44:5 | LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here From 5c25d30f6fe9996f815a96f4b328e62c452cc3e3 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Thu, 24 Mar 2022 19:24:40 -0500 Subject: [PATCH 07/20] Allow specialized const trait impls. Fixes #95186. Fixes #95187. --- .../src/impl_wf_check/min_specialization.rs | 65 +++++++++++++------ .../const-default-const-specialized.rs | 38 +++++++++++ .../const-default-non-const-specialized.rs | 37 +++++++++++ ...const-default-non-const-specialized.stderr | 37 +++++++++++ .../specialization/default-keyword.rs | 14 ++++ .../issue-95186-specialize-on-tilde-const.rs | 34 ++++++++++ ...87-same-trait-bound-different-constness.rs | 28 ++++++++ .../non-const-default-const-specialized.rs | 34 ++++++++++ ...non-const-default-const-specialized.stderr | 20 ++++++ 9 files changed, 286 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 267077cdab4e6..f65760b9c98ca 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -80,6 +80,7 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; +use tracing::instrument; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { @@ -103,13 +104,11 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti } /// Check that `impl1` is a sound specialization +#[instrument(level = "debug", skip(tcx))] fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); - debug!( - "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)", - impl1_def_id, impl2_def_id, impl2_substs - ); + debug!(?impl2_def_id, ?impl2_substs); let parent_substs = if impl2_node.is_from_trait() { impl2_substs.to_vec() @@ -280,13 +279,13 @@ fn check_static_lifetimes<'tcx>( /// /// Each predicate `P` must be: /// -/// * global (not reference any parameters) -/// * `T: Tr` predicate where `Tr` is an always-applicable trait -/// * on the base `impl impl2` -/// * Currently this check is done using syntactic equality, which is -/// conservative but generally sufficient. -/// * a well-formed predicate of a type argument of the trait being implemented, +/// * Global (not reference any parameters). +/// * A `T: Tr` predicate where `Tr` is an always-applicable trait. +/// * Present on the base impl `impl2`. +/// * This check is done using the `trait_predicates_eq` function below. +/// * A well-formed predicate of a type argument of the trait being implemented, /// including the `Self`-type. +#[instrument(level = "debug", skip(tcx))] fn check_predicates<'tcx>( tcx: TyCtxt<'tcx>, impl1_def_id: LocalDefId, @@ -322,10 +321,7 @@ fn check_predicates<'tcx>( .map(|obligation| obligation.predicate) .collect() }; - debug!( - "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)", - impl1_predicates, impl2_predicates, - ); + debug!(?impl1_predicates, ?impl2_predicates); // Since impls of always applicable traits don't get to assume anything, we // can also assume their supertraits apply. @@ -373,25 +369,52 @@ fn check_predicates<'tcx>( ); for (predicate, span) in impl1_predicates { - if !impl2_predicates.contains(&predicate) { + if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(predicate, *pred2)) { check_specialization_on(tcx, predicate, span) } } } +/// Checks whether two predicates are the same for the purposes of specialization. +/// +/// This is slightly more complicated than simple syntactic equivalence, since +/// we want to equate `T: Tr` with `T: ~const Tr` so this can work: +/// +/// #[rustc_specialization_trait] +/// trait Specialize { } +/// +/// impl const Tr for T { } +/// impl Tr for T { } +fn trait_predicates_eq<'tcx>( + predicate1: ty::Predicate<'tcx>, + predicate2: ty::Predicate<'tcx>, +) -> bool { + let predicate_kind_without_constness = |kind: ty::PredicateKind<'tcx>| match kind { + ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity }) => { + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity, + }) + } + _ => kind, + }; + + let pred1_kind_not_const = predicate1.kind().map_bound(predicate_kind_without_constness); + let pred2_kind_not_const = predicate2.kind().map_bound(predicate_kind_without_constness); + + pred1_kind_not_const == pred2_kind_not_const +} + +#[instrument(level = "debug", skip(tcx))] fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) { - debug!("can_specialize_on(predicate = {:?})", predicate); match predicate.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. _ if predicate.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: _, - }) => { + ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => { if !matches!( trait_predicate_kind(tcx, predicate), Some(TraitSpecializationKind::Marker) diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs new file mode 100644 index 0000000000000..1eddfbf50f386 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -0,0 +1,38 @@ +// Tests that a const default trait impl can be specialized by another const +// trait impl and that the specializing impl will be used during const-eval. + +// run-pass + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +trait Value { + fn value() -> u32; +} + +const fn get_value() -> u32 { + T::value() +} + +impl const Value for T { + default fn value() -> u32 { + 0 + } +} + +struct FortyTwo; + +impl const Value for FortyTwo { + fn value() -> u32 { + 42 + } +} + +const ZERO: u32 = get_value::<()>(); + +const FORTY_TWO: u32 = get_value::(); + +fn main() { + assert_eq!(ZERO, 0); + assert_eq!(FORTY_TWO, 42); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs new file mode 100644 index 0000000000000..31de6fadeb7a2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs @@ -0,0 +1,37 @@ +// Tests that a const default trait impl can be specialized by a non-const trait +// impl, but that the specializing impl cannot be used in a const context. + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +trait Value { + fn value() -> u32; +} + +const fn get_value() -> u32 { + T::value() + //~^ ERROR any use of this value will cause an error [const_err] + //~| WARNING this was previously accepted +} + +impl const Value for T { + default fn value() -> u32 { + 0 + } +} + +struct FortyTwo; + +impl Value for FortyTwo { + fn value() -> u32 { + println!("You can't do that (constly)"); + 42 + } +} + +const ZERO: u32 = get_value::<()>(); + +const FORTY_TWO: u32 = + get_value::(); // This is the line that causes the error, but it gets reported above + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr new file mode 100644 index 0000000000000..7dfd489ea65c6 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr @@ -0,0 +1,37 @@ +error: any use of this value will cause an error + --> $DIR/const-default-non-const-specialized.rs:12:5 + | +LL | T::value() + | ^^^^^^^^^^ + | | + | calling non-const function `::value` + | inside `get_value::` at $DIR/const-default-non-const-specialized.rs:12:5 + | inside `FORTY_TWO` at $DIR/const-default-non-const-specialized.rs:35:5 +... +LL | const FORTY_TWO: u32 = + | -------------------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: aborting due to previous error + +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-default-non-const-specialized.rs:12:5 + | +LL | T::value() + | ^^^^^^^^^^ + | | + | calling non-const function `::value` + | inside `get_value::` at $DIR/const-default-non-const-specialized.rs:12:5 + | inside `FORTY_TWO` at $DIR/const-default-non-const-specialized.rs:35:5 +... +LL | const FORTY_TWO: u32 = + | -------------------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs new file mode 100644 index 0000000000000..c03b0a0d19ca5 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +trait Foo { + fn foo(); +} + +impl const Foo for u32 { + default fn foo() {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs new file mode 100644 index 0000000000000..1f7f47879d78b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -0,0 +1,34 @@ +// Tests that `~const` trait bounds can be used to specialize const trait impls. + +// check-pass + +#![feature(const_trait_impl)] +#![feature(rustc_attrs)] +#![feature(min_specialization)] + +#[rustc_specialization_trait] +trait Specialize {} + +trait Foo {} + +impl const Foo for T {} + +impl const Foo for T +where + T: ~const Specialize, +{} + +trait Bar {} + +impl const Bar for T +where + T: ~const Foo, +{} + +impl const Bar for T +where + T: ~const Foo, + T: ~const Specialize, +{} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs new file mode 100644 index 0000000000000..f6daba5595a8d --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -0,0 +1,28 @@ +// Tests that `T: ~const Foo` and `T: Foo` are treated as equivalent for the +// purposes of min_specialization. + +// check-pass + +#![feature(rustc_attrs)] +#![feature(min_specialization)] +#![feature(const_trait_impl)] + +#[rustc_specialization_trait] +trait Specialize {} + +trait Foo {} + +trait Bar {} + +impl const Bar for T +where + T: ~const Foo, +{} + +impl Bar for T +where + T: Foo, + T: Specialize, +{} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs new file mode 100644 index 0000000000000..cf6c292e8a465 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -0,0 +1,34 @@ +// Tests that a non-const default impl can be specialized by a const trait impl, +// but that the default impl cannot be used in a const context. + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +trait Value { + fn value() -> u32; +} + +const fn get_value() -> u32 { + T::value() +} + +impl Value for T { + default fn value() -> u32 { + println!("You can't do that (constly)"); + 0 + } +} + +struct FortyTwo; + +impl const Value for FortyTwo { + fn value() -> u32 { + 42 + } +} + +const ZERO: u32 = get_value::<()>(); //~ ERROR the trait bound `(): ~const Value` is not satisfied + +const FORTY_TWO: u32 = get_value::(); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr new file mode 100644 index 0000000000000..1065009c8910e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): ~const Value` is not satisfied + --> $DIR/non-const-default-const-specialized.rs:30:31 + | +LL | const ZERO: u32 = get_value::<()>(); + | ^^ the trait `~const Value` is not implemented for `()` + | +note: the trait `Value` is implemented for `()`, but that implementation is not `const` + --> $DIR/non-const-default-const-specialized.rs:30:31 + | +LL | const ZERO: u32 = get_value::<()>(); + | ^^ +note: required by a bound in `get_value` + --> $DIR/non-const-default-const-specialized.rs:11:23 + | +LL | const fn get_value() -> u32 { + | ^^^^^^^^^^^^ required by this bound in `get_value` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From ce03d259da4a9e47111465353363597868aa2266 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Tue, 13 Sep 2022 22:18:14 -0500 Subject: [PATCH 08/20] Disallow specializing on const impls with non-const impls. --- .../src/impl_wf_check/min_specialization.rs | 35 ++++++++++++++++-- .../const-default-non-const-specialized.rs | 17 ++------- ...const-default-non-const-specialized.stderr | 37 ++----------------- ...87-same-trait-bound-different-constness.rs | 10 ++--- .../non-const-default-const-specialized.rs | 12 ++++-- ...non-const-default-const-specialized.stderr | 20 ---------- 6 files changed, 51 insertions(+), 80 deletions(-) delete mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index f65760b9c98ca..9c7150b79240a 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -69,6 +69,7 @@ use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; @@ -117,12 +118,33 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node }; let span = tcx.def_span(impl1_def_id); + check_constness(tcx, impl1_def_id, impl2_node, span); check_static_lifetimes(tcx, &parent_substs, span); check_duplicate_params(tcx, impl1_substs, &parent_substs, span); check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span); } } +/// Check that the specializing impl `impl1` is at least as const as the base +/// impl `impl2` +fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { + if impl2_node.is_from_trait() { + // This isn't a specialization + return; + } + + let impl1_constness = tcx.constness(impl1_def_id.to_def_id()); + let impl2_constness = tcx.constness(impl2_node.def_id()); + + if let hir::Constness::Const = impl2_constness { + if let hir::Constness::NotConst = impl1_constness { + tcx.sess + .struct_span_err(span, "cannot specialize on const impl with non-const impl") + .emit(); + } + } +} + /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two /// substitutions `(S1, S2)` that equate their trait references. The returned /// types are expressed in terms of the generics of `impl1`. @@ -277,7 +299,7 @@ fn check_static_lifetimes<'tcx>( /// Check whether predicates on the specializing impl (`impl1`) are allowed. /// -/// Each predicate `P` must be: +/// Each predicate `P` must be one of: /// /// * Global (not reference any parameters). /// * A `T: Tr` predicate where `Tr` is an always-applicable trait. @@ -375,16 +397,19 @@ fn check_predicates<'tcx>( } } -/// Checks whether two predicates are the same for the purposes of specialization. +/// Checks if some predicate on the specializing impl (`predicate1`) is the same +/// as some predicate on the base impl (`predicate2`). /// /// This is slightly more complicated than simple syntactic equivalence, since /// we want to equate `T: Tr` with `T: ~const Tr` so this can work: /// +/// ```ignore (illustrative) /// #[rustc_specialization_trait] /// trait Specialize { } /// -/// impl const Tr for T { } -/// impl Tr for T { } +/// impl Tr for T { } +/// impl const Tr for T { } +/// ``` fn trait_predicates_eq<'tcx>( predicate1: ty::Predicate<'tcx>, predicate2: ty::Predicate<'tcx>, @@ -400,6 +425,8 @@ fn trait_predicates_eq<'tcx>( _ => kind, }; + // We rely on `check_constness` above to ensure that pred1 is const if pred2 + // is const. let pred1_kind_not_const = predicate1.kind().map_bound(predicate_kind_without_constness); let pred2_kind_not_const = predicate2.kind().map_bound(predicate_kind_without_constness); diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs index 31de6fadeb7a2..a25329ba388d2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs @@ -1,5 +1,5 @@ -// Tests that a const default trait impl can be specialized by a non-const trait -// impl, but that the specializing impl cannot be used in a const context. +// Tests that a const default trait impl cannot be specialized by a non-const +// trait impl. #![feature(const_trait_impl)] #![feature(min_specialization)] @@ -8,12 +8,6 @@ trait Value { fn value() -> u32; } -const fn get_value() -> u32 { - T::value() - //~^ ERROR any use of this value will cause an error [const_err] - //~| WARNING this was previously accepted -} - impl const Value for T { default fn value() -> u32 { 0 @@ -22,16 +16,11 @@ impl const Value for T { struct FortyTwo; -impl Value for FortyTwo { +impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl fn value() -> u32 { println!("You can't do that (constly)"); 42 } } -const ZERO: u32 = get_value::<()>(); - -const FORTY_TWO: u32 = - get_value::(); // This is the line that causes the error, but it gets reported above - fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr index 7dfd489ea65c6..b0b76e7eca8ac 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr @@ -1,37 +1,8 @@ -error: any use of this value will cause an error - --> $DIR/const-default-non-const-specialized.rs:12:5 +error: cannot specialize on const impl with non-const impl + --> $DIR/const-default-non-const-specialized.rs:19:1 | -LL | T::value() - | ^^^^^^^^^^ - | | - | calling non-const function `::value` - | inside `get_value::` at $DIR/const-default-non-const-specialized.rs:12:5 - | inside `FORTY_TWO` at $DIR/const-default-non-const-specialized.rs:35:5 -... -LL | const FORTY_TWO: u32 = - | -------------------- - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 +LL | impl Value for FortyTwo { + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -Future incompatibility report: Future breakage diagnostic: -error: any use of this value will cause an error - --> $DIR/const-default-non-const-specialized.rs:12:5 - | -LL | T::value() - | ^^^^^^^^^^ - | | - | calling non-const function `::value` - | inside `get_value::` at $DIR/const-default-non-const-specialized.rs:12:5 - | inside `FORTY_TWO` at $DIR/const-default-non-const-specialized.rs:35:5 -... -LL | const FORTY_TWO: u32 = - | -------------------- - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index f6daba5595a8d..da6df064d4fd1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -1,4 +1,4 @@ -// Tests that `T: ~const Foo` and `T: Foo` are treated as equivalent for the +// Tests that `T: Foo` and `T: ~const Foo` are treated as equivalent for the // purposes of min_specialization. // check-pass @@ -14,14 +14,14 @@ trait Foo {} trait Bar {} -impl const Bar for T +impl Bar for T where - T: ~const Foo, + T: Foo, {} -impl Bar for T +impl const Bar for T where - T: Foo, + T: ~const Foo, T: Specialize, {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs index cf6c292e8a465..84614f5459d63 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -1,6 +1,8 @@ // Tests that a non-const default impl can be specialized by a const trait impl, // but that the default impl cannot be used in a const context. +// run-pass + #![feature(const_trait_impl)] #![feature(min_specialization)] @@ -27,8 +29,10 @@ impl const Value for FortyTwo { } } -const ZERO: u32 = get_value::<()>(); //~ ERROR the trait bound `(): ~const Value` is not satisfied - -const FORTY_TWO: u32 = get_value::(); +fn main() { + let zero = get_value::<()>(); + assert_eq!(zero, 0); -fn main() {} + const FORTY_TWO: u32 = get_value::(); + assert_eq!(FORTY_TWO, 42); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr deleted file mode 100644 index 1065009c8910e..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `(): ~const Value` is not satisfied - --> $DIR/non-const-default-const-specialized.rs:30:31 - | -LL | const ZERO: u32 = get_value::<()>(); - | ^^ the trait `~const Value` is not implemented for `()` - | -note: the trait `Value` is implemented for `()`, but that implementation is not `const` - --> $DIR/non-const-default-const-specialized.rs:30:31 - | -LL | const ZERO: u32 = get_value::<()>(); - | ^^ -note: required by a bound in `get_value` - --> $DIR/non-const-default-const-specialized.rs:11:23 - | -LL | const fn get_value() -> u32 { - | ^^^^^^^^^^^^ required by this bound in `get_value` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. From d492b9b000553f1407d9b75e15412d9df50314b2 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Sat, 5 Nov 2022 23:12:57 -0500 Subject: [PATCH 09/20] Add #[const_trait] where needed in tests. --- .../specialization/const-default-const-specialized.rs | 1 + .../specialization/const-default-non-const-specialized.rs | 1 + .../specialization/const-default-non-const-specialized.stderr | 2 +- .../specialization/default-keyword.rs | 1 + .../specialization/issue-95186-specialize-on-tilde-const.rs | 3 +++ .../issue-95187-same-trait-bound-different-constness.rs | 2 ++ .../specialization/non-const-default-const-specialized.rs | 1 + 7 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs index 1eddfbf50f386..9ddea427cfd80 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -6,6 +6,7 @@ #![feature(const_trait_impl)] #![feature(min_specialization)] +#[const_trait] trait Value { fn value() -> u32; } diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs index a25329ba388d2..79dd4950af32a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs @@ -4,6 +4,7 @@ #![feature(const_trait_impl)] #![feature(min_specialization)] +#[const_trait] trait Value { fn value() -> u32; } diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr index b0b76e7eca8ac..5232a8609cd80 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr @@ -1,5 +1,5 @@ error: cannot specialize on const impl with non-const impl - --> $DIR/const-default-non-const-specialized.rs:19:1 + --> $DIR/const-default-non-const-specialized.rs:20:1 | LL | impl Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs index c03b0a0d19ca5..2aac0a2b4d111 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs @@ -3,6 +3,7 @@ #![feature(const_trait_impl)] #![feature(min_specialization)] +#[const_trait] trait Foo { fn foo(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs index 1f7f47879d78b..9c2c2cf1610a2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -6,9 +6,11 @@ #![feature(rustc_attrs)] #![feature(min_specialization)] +#[const_trait] #[rustc_specialization_trait] trait Specialize {} +#[const_trait] trait Foo {} impl const Foo for T {} @@ -18,6 +20,7 @@ where T: ~const Specialize, {} +#[const_trait] trait Bar {} impl const Bar for T diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index da6df064d4fd1..3370aebf0634a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -10,8 +10,10 @@ #[rustc_specialization_trait] trait Specialize {} +#[const_trait] trait Foo {} +#[const_trait] trait Bar {} impl Bar for T diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs index 84614f5459d63..35aa52fbd4ed2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -6,6 +6,7 @@ #![feature(const_trait_impl)] #![feature(min_specialization)] +#[const_trait] trait Value { fn value() -> u32; } From c0ae62ee955712c96dec17170d4d63fd2b34f504 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Sun, 6 Nov 2022 01:07:06 -0500 Subject: [PATCH 10/20] Require `~const` qualifier on trait bounds in specializing impls if present in base impl. --- .../src/impl_wf_check/min_specialization.rs | 59 ++++++++++++++----- ...fault-bound-non-const-specialized-bound.rs | 46 +++++++++++++++ ...t-bound-non-const-specialized-bound.stderr | 18 ++++++ ...efault-impl-non-const-specialized-impl.rs} | 3 +- ...lt-impl-non-const-specialized-impl.stderr} | 2 +- ...87-same-trait-bound-different-constness.rs | 19 +++++- .../specializing-constness.rs | 4 +- .../specializing-constness.stderr | 10 +++- 8 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr rename src/test/ui/rfc-2632-const-trait-impl/specialization/{const-default-non-const-specialized.rs => const-default-impl-non-const-specialized-impl.rs} (81%) rename src/test/ui/rfc-2632-const-trait-impl/specialization/{const-default-non-const-specialized.stderr => const-default-impl-non-const-specialized-impl.stderr} (71%) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 9c7150b79240a..f3cb558ef7093 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -391,7 +391,7 @@ fn check_predicates<'tcx>( ); for (predicate, span) in impl1_predicates { - if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(predicate, *pred2)) { + if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) { check_specialization_on(tcx, predicate, span) } } @@ -400,8 +400,8 @@ fn check_predicates<'tcx>( /// Checks if some predicate on the specializing impl (`predicate1`) is the same /// as some predicate on the base impl (`predicate2`). /// -/// This is slightly more complicated than simple syntactic equivalence, since -/// we want to equate `T: Tr` with `T: ~const Tr` so this can work: +/// This basically just checks syntactic equivalence, but is a little more +/// forgiving since we want to equate `T: Tr` with `T: ~const Tr` so this can work: /// /// ```ignore (illustrative) /// #[rustc_specialization_trait] @@ -410,27 +410,54 @@ fn check_predicates<'tcx>( /// impl Tr for T { } /// impl const Tr for T { } /// ``` +/// +/// However, we *don't* want to allow the reverse, i.e., when the bound on the +/// specializing impl is not as const as the bound on the base impl: +/// +/// ```ignore (illustrative) +/// impl const Tr for T { } +/// impl const Tr for T { } // should be T: ~const Bound +/// ``` +/// +/// So we make that check in this function and try to raise a helpful error message. fn trait_predicates_eq<'tcx>( + tcx: TyCtxt<'tcx>, predicate1: ty::Predicate<'tcx>, predicate2: ty::Predicate<'tcx>, + span: Span, ) -> bool { - let predicate_kind_without_constness = |kind: ty::PredicateKind<'tcx>| match kind { - ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity }) => { - ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity, - }) + let pred1_kind = predicate1.kind().no_bound_vars(); + let pred2_kind = predicate2.kind().no_bound_vars(); + let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) { + (Some(ty::PredicateKind::Trait(pred1)), Some(ty::PredicateKind::Trait(pred2))) => { + (pred1, pred2) } - _ => kind, + // Just use plain syntactic equivalence if either of the predicates aren't + // trait predicates or have bound vars. + _ => return pred1_kind == pred2_kind, + }; + + let predicates_equal_modulo_constness = { + let pred1_unconsted = + ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred1 }; + let pred2_unconsted = + ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred2 }; + pred1_unconsted == pred2_unconsted }; - // We rely on `check_constness` above to ensure that pred1 is const if pred2 - // is const. - let pred1_kind_not_const = predicate1.kind().map_bound(predicate_kind_without_constness); - let pred2_kind_not_const = predicate2.kind().map_bound(predicate_kind_without_constness); + if !predicates_equal_modulo_constness { + return false; + } + + // Check that the predicate on the specializing impl is at least as const as + // the one on the base. + if trait_pred2.constness == ty::BoundConstness::ConstIfConst + && trait_pred1.constness == ty::BoundConstness::NotConst + { + tcx.sess.struct_span_err(span, "missing `~const` qualifier").emit(); + } - pred1_kind_not_const == pred2_kind_not_const + true } #[instrument(level = "debug", skip(tcx))] diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs new file mode 100644 index 0000000000000..3ac909924864d --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -0,0 +1,46 @@ +// Tests that trait bounds on specializing trait impls must be `~const` if the +// same bound is present on the default impl and is `~const` there. + +#![feature(const_trait_impl)] +#![feature(rustc_attrs)] +#![feature(min_specialization)] + +#[rustc_specialization_trait] +trait Specialize {} + +#[const_trait] +trait Foo {} + +#[const_trait] +trait Bar {} + +// bgr360: I was only able to exercise the code path that raises the +// "missing ~const qualifier" error by making this base impl non-const, even +// though that doesn't really make sense to do. As seen below, if the base impl +// is made const, rustc fails earlier with an overlapping impl failure. +impl Bar for T +where + T: ~const Foo, +{} + +impl Bar for T +where + T: Foo, //~ ERROR missing `~const` qualifier + T: Specialize, +{} + +#[const_trait] +trait Baz {} + +impl const Baz for T +where + T: ~const Foo, +{} + +impl const Baz for T //~ ERROR conflicting implementations of trait `Baz` +where + T: Foo, + T: Specialize, +{} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr new file mode 100644 index 0000000000000..583c4cec77fb6 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -0,0 +1,18 @@ +error: missing `~const` qualifier + --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8 + | +LL | T: Foo, + | ^^^ + +error[E0119]: conflicting implementations of trait `Baz` + --> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1 + | +LL | impl const Baz for T + | ----------------------- first implementation here +... +LL | impl const Baz for T + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs similarity index 81% rename from src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs rename to src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs index 79dd4950af32a..a3bb9b3f93eda 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs @@ -1,5 +1,4 @@ -// Tests that a const default trait impl cannot be specialized by a non-const -// trait impl. +// Tests that specializing trait impls must be at least as const as the default impl. #![feature(const_trait_impl)] #![feature(min_specialization)] diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr similarity index 71% rename from src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr rename to src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr index 5232a8609cd80..24766804708a3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-non-const-specialized.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr @@ -1,5 +1,5 @@ error: cannot specialize on const impl with non-const impl - --> $DIR/const-default-non-const-specialized.rs:20:1 + --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1 | LL | impl Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index 3370aebf0634a..1e6b1c6513b39 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -1,5 +1,6 @@ -// Tests that `T: Foo` and `T: ~const Foo` are treated as equivalent for the -// purposes of min_specialization. +// Tests that `T: ~const Foo` in a specializing impl is treated as equivalent to +// `T: Foo` in the default impl for the purposes of specialization (i.e., it +// does not think that the user is attempting to specialize on trait `Foo`). // check-pass @@ -27,4 +28,18 @@ where T: Specialize, {} +#[const_trait] +trait Baz {} + +impl const Baz for T +where + T: Foo, +{} + +impl const Baz for T +where + T: ~const Foo, + T: Specialize, +{} + fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs index ff0cd489d4744..9ab170f092006 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs @@ -17,7 +17,9 @@ impl const A for T { } } -impl A for T { //~ ERROR: cannot specialize +impl A for T { +//~^ ERROR: cannot specialize +//~| ERROR: missing `~const` qualifier fn a() -> u32 { 3 } diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr index 3296c109c4e73..281ba82d64429 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -1,8 +1,14 @@ -error: cannot specialize on trait `Default` +error: cannot specialize on const impl with non-const impl + --> $DIR/specializing-constness.rs:20:1 + | +LL | impl A for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing `~const` qualifier --> $DIR/specializing-constness.rs:20:9 | LL | impl A for T { | ^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors From fe53cacff9f1e2aaeaeea4116d99cfa24d1f460f Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Thu, 10 Nov 2022 12:56:09 -0600 Subject: [PATCH 11/20] Apply PR feedback. --- .../src/impl_wf_check/min_specialization.rs | 19 +++++++++---------- ...t-bound-non-const-specialized-bound.stderr | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index f3cb558ef7093..55cca0cd2d7b5 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -426,15 +426,13 @@ fn trait_predicates_eq<'tcx>( predicate2: ty::Predicate<'tcx>, span: Span, ) -> bool { - let pred1_kind = predicate1.kind().no_bound_vars(); - let pred2_kind = predicate2.kind().no_bound_vars(); + let pred1_kind = predicate1.kind().skip_binder(); + let pred2_kind = predicate2.kind().skip_binder(); let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) { - (Some(ty::PredicateKind::Trait(pred1)), Some(ty::PredicateKind::Trait(pred2))) => { - (pred1, pred2) - } + (ty::PredicateKind::Trait(pred1), ty::PredicateKind::Trait(pred2)) => (pred1, pred2), // Just use plain syntactic equivalence if either of the predicates aren't // trait predicates or have bound vars. - _ => return pred1_kind == pred2_kind, + _ => return predicate1 == predicate2, }; let predicates_equal_modulo_constness = { @@ -451,10 +449,11 @@ fn trait_predicates_eq<'tcx>( // Check that the predicate on the specializing impl is at least as const as // the one on the base. - if trait_pred2.constness == ty::BoundConstness::ConstIfConst - && trait_pred1.constness == ty::BoundConstness::NotConst - { - tcx.sess.struct_span_err(span, "missing `~const` qualifier").emit(); + match (trait_pred2.constness, trait_pred1.constness) { + (ty::BoundConstness::ConstIfConst, ty::BoundConstness::NotConst) => { + tcx.sess.struct_span_err(span, "missing `~const` qualifier for specialization").emit(); + } + _ => {} } true diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr index 583c4cec77fb6..4aea1979421c3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,4 +1,4 @@ -error: missing `~const` qualifier +error: missing `~const` qualifier for specialization --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8 | LL | T: Foo, From c467006fd0d0fd046590c7867fcfef2062d144a3 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 8 Nov 2022 19:45:41 +0900 Subject: [PATCH 12/20] suggest removing unnecessary . to use a floating point literal --- compiler/rustc_hir_typeck/src/demand.rs | 3 +- .../src/fn_ctxt/suggestions.rs | 21 ++++++++ ...ecessary_dot_for_floating_point_literal.rs | 6 +++ ...sary_dot_for_floating_point_literal.stderr | 52 +++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs create mode 100644 src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 7f78f5fb8a7b2..be618eb664c3f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -43,7 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) - || self.suggest_option_to_bool(err, expr, expr_ty, expected); + || self.suggest_option_to_bool(err, expr, expr_ty, expected) + || self.suggest_floating_point_literal(err, expr, expected); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index a14759e254c49..fb8669e949cdf 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1204,6 +1204,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(skip(self, err))] + pub(crate) fn suggest_floating_point_literal( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected_ty: Ty<'tcx>, + ) -> bool { + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, _], _) = expr.kind + && expected_ty.is_floating_point() + { + err.span_suggestion_verbose( + self.tcx.sess.source_map().next_point(start.span), + "remove the unnecessary `.` operator to to use a floating point literal", + "", + Applicability::MachineApplicable, + ); + return true; + } + false + } + fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs new file mode 100644 index 0000000000000..b1eda63d56e27 --- /dev/null +++ b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs @@ -0,0 +1,6 @@ +fn main() { + let _: f64 = 0..10; //~ ERROR mismatched types + let _: f64 = 0..; //~ ERROR mismatched types + let _: f64 = ..10; //~ ERROR mismatched types + let _: f64 = std::ops::Range { start: 0, end: 1 }; //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr new file mode 100644 index 0000000000000..2f1d7dc230f4d --- /dev/null +++ b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/unnecessary_dot_for_floating_point_literal.rs:2:18 + | +LL | let _: f64 = 0..10; + | --- ^^^^^ expected `f64`, found struct `std::ops::Range` + | | + | expected due to this + | + = note: expected type `f64` + found struct `std::ops::Range<{integer}>` +help: remove the unnecessary `.` operator to to use a floating point literal + | +LL - let _: f64 = 0..10; +LL + let _: f64 = 0.10; + | + +error[E0308]: mismatched types + --> $DIR/unnecessary_dot_for_floating_point_literal.rs:3:18 + | +LL | let _: f64 = 0..; + | --- ^^^ expected `f64`, found struct `RangeFrom` + | | + | expected due to this + | + = note: expected type `f64` + found struct `RangeFrom<{integer}>` + +error[E0308]: mismatched types + --> $DIR/unnecessary_dot_for_floating_point_literal.rs:4:18 + | +LL | let _: f64 = ..10; + | --- ^^^^ expected `f64`, found struct `RangeTo` + | | + | expected due to this + | + = note: expected type `f64` + found struct `RangeTo<{integer}>` + +error[E0308]: mismatched types + --> $DIR/unnecessary_dot_for_floating_point_literal.rs:5:18 + | +LL | let _: f64 = std::ops::Range { start: 0, end: 1 }; + | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found struct `std::ops::Range` + | | + | expected due to this + | + = note: expected type `f64` + found struct `std::ops::Range<{integer}>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 004986b79b933a5c9ec160b977f791b154c8d275 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 8 Nov 2022 19:45:48 +0900 Subject: [PATCH 13/20] avoid unnecessary `format!` --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index fb8669e949cdf..5a0af00b6e1fc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -374,7 +374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let annotation_span = ty.span; err.span_suggestion( annotation_span.with_hi(annotation_span.lo()), - format!("alternatively, consider changing the type annotation"), + "alternatively, consider changing the type annotation", suggest_annotation, Applicability::MaybeIncorrect, ); From 6018f115aa7365db39a9df1f883123076403a97b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 10 Nov 2022 07:24:22 +0900 Subject: [PATCH 14/20] emit errors when using `RangeFrom` and `RangeTo` --- .../src/fn_ctxt/suggestions.rs | 43 ++++++++++++++----- ...ecessary_dot_for_floating_point_literal.rs | 2 +- ...sary_dot_for_floating_point_literal.stderr | 17 +++++--- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5a0af00b6e1fc..06e6e4350fcbc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1211,18 +1211,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, expected_ty: Ty<'tcx>, ) -> bool { - if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, _], _) = expr.kind - && expected_ty.is_floating_point() - { - err.span_suggestion_verbose( - self.tcx.sess.source_map().next_point(start.span), - "remove the unnecessary `.` operator to to use a floating point literal", - "", - Applicability::MachineApplicable, - ); - return true; + if !expected_ty.is_floating_point() { + return false; + } + match expr.kind { + ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => { + err.span_suggestion_verbose( + start.span.shrink_to_hi().with_hi(end.span.lo()), + "remove the unnecessary `.` operator for a floating point literal", + '.', + Applicability::MaybeIncorrect, + ); + true + } + ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => { + err.span_suggestion_verbose( + expr.span.with_lo(start.span.hi()), + "remove the unnecessary `.` operator for a floating point literal", + '.', + Applicability::MaybeIncorrect, + ); + true + } + ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => { + err.span_suggestion_verbose( + expr.span.until(end.span), + "remove the unnecessary `.` operator and add an integer part for a floating point literal", + "0.", + Applicability::MaybeIncorrect, + ); + true + } + _ => false, } - false } fn is_loop(&self, id: hir::HirId) -> bool { diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs index b1eda63d56e27..c1a944562683a 100644 --- a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs +++ b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs @@ -1,6 +1,6 @@ fn main() { let _: f64 = 0..10; //~ ERROR mismatched types - let _: f64 = 0..; //~ ERROR mismatched types + let _: f64 = 1..; //~ ERROR mismatched types let _: f64 = ..10; //~ ERROR mismatched types let _: f64 = std::ops::Range { start: 0, end: 1 }; //~ ERROR mismatched types } diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr index 2f1d7dc230f4d..773f1392ae765 100644 --- a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr +++ b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr @@ -8,22 +8,25 @@ LL | let _: f64 = 0..10; | = note: expected type `f64` found struct `std::ops::Range<{integer}>` -help: remove the unnecessary `.` operator to to use a floating point literal - | -LL - let _: f64 = 0..10; -LL + let _: f64 = 0.10; +help: remove the unnecessary `.` operator for a floating point literal | +LL | let _: f64 = 0.10; + | ~ error[E0308]: mismatched types --> $DIR/unnecessary_dot_for_floating_point_literal.rs:3:18 | -LL | let _: f64 = 0..; +LL | let _: f64 = 1..; | --- ^^^ expected `f64`, found struct `RangeFrom` | | | expected due to this | = note: expected type `f64` found struct `RangeFrom<{integer}>` +help: remove the unnecessary `.` operator for a floating point literal + | +LL | let _: f64 = 1.; + | ~ error[E0308]: mismatched types --> $DIR/unnecessary_dot_for_floating_point_literal.rs:4:18 @@ -35,6 +38,10 @@ LL | let _: f64 = ..10; | = note: expected type `f64` found struct `RangeTo<{integer}>` +help: remove the unnecessary `.` operator and add an integer part for a floating point literal + | +LL | let _: f64 = 0.10; + | ~~ error[E0308]: mismatched types --> $DIR/unnecessary_dot_for_floating_point_literal.rs:5:18 From 94f67e667be3efd1845bb95fcd25fcce11cf983c Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Thu, 10 Nov 2022 22:14:08 -0600 Subject: [PATCH 15/20] Oops, bless this test. --- .../ui/rfc-2632-const-trait-impl/specializing-constness.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr index 281ba82d64429..843fc6ce84d45 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -4,7 +4,7 @@ error: cannot specialize on const impl with non-const impl LL | impl A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: missing `~const` qualifier +error: missing `~const` qualifier for specialization --> $DIR/specializing-constness.rs:20:9 | LL | impl A for T { From 84e1fbcadfa6299e63e517e722485b47fc99daad Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Mon, 5 Sep 2022 10:56:06 +0200 Subject: [PATCH 16/20] Add no_std AArch64 support for the QNX Neutrino (nto) 7.1 RTOS This change allows to compile no_std applications for the QNX Neutrino realtime operating system for ARM 64 bit CPUs. Tested with QNX Neutrino 7.1. --- .../src/spec/aarch64_unknown_nto_qnx_710.rs | 28 +++++ compiler/rustc_target/src/spec/mod.rs | 4 + .../rustc_target/src/spec/nto_qnx_base.rs | 19 +++ .../src/spec/x86_64_pc_nto_qnx710.rs | 21 ++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + src/doc/rustc/src/platform-support/nto-qnx.md | 117 ++++++++++++++++++ 7 files changed, 192 insertions(+) create mode 100644 compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs create mode 100644 compiler/rustc_target/src/spec/nto_qnx_base.rs create mode 100644 compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs create mode 100644 src/doc/rustc/src/platform-support/nto-qnx.md diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs b/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs new file mode 100644 index 0000000000000..916b6137b650a --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs @@ -0,0 +1,28 @@ +use super::nto_qnx_base; +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "aarch64-unknown-unknown".into(), + pointer_width: 64, + // from: https://llvm.org/docs/LangRef.html#data-layout + // e = little endian + // m:e = ELF mangling: Private symbols get a .L prefix + // i8:8:32 = 8-bit-integer, minimum_alignment=8, preferred_alignment=32 + // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32 + // i64:64 = 64-bit-integer, minimum_alignment=64, preferred_alignment=64 + // i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128 + // n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently. + // S128 = 128 bits are the natural alignment of the stack in bits. + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + arch: "aarch64".into(), + options: TargetOptions { + max_atomic_width: Some(128), + pre_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::Yes, Lld::No), + &["-Vgcc_ntoaarch64le_cxx"], + ), + ..nto_qnx_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 77d9a0920036a..e809f646860b0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -74,6 +74,7 @@ mod linux_musl_base; mod linux_uclibc_base; mod msvc_base; mod netbsd_base; +mod nto_qnx_base; mod openbsd_base; mod redox_base; mod solaris_base; @@ -1242,6 +1243,9 @@ supported_targets! { ("x86_64-unknown-none", x86_64_unknown_none), ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl), + + ("aarch64-unknown-nto-qnx7.1.0", aarch64_unknown_nto_qnx_710), + ("x86_64-pc-nto-qnx7.1.0", x86_64_pc_nto_qnx710), } /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]> diff --git a/compiler/rustc_target/src/spec/nto_qnx_base.rs b/compiler/rustc_target/src/spec/nto_qnx_base.rs new file mode 100644 index 0000000000000..6fb581ef5ce34 --- /dev/null +++ b/compiler/rustc_target/src/spec/nto_qnx_base.rs @@ -0,0 +1,19 @@ +use crate::spec::{cvs, RelroLevel, TargetOptions}; + +pub fn opts() -> TargetOptions { + TargetOptions { + crt_static_respected: true, + dynamic_linking: true, + env: "nto71".into(), + executables: true, + families: cvs!["unix"], + has_rpath: true, + has_thread_local: false, + linker: Some("qcc".into()), + os: "nto".into(), + position_independent_executables: true, + static_position_independent_executables: true, + relro_level: RelroLevel::Full, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs new file mode 100644 index 0000000000000..e9b3acee2e7f1 --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs @@ -0,0 +1,21 @@ +use super::nto_qnx_base; +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "x86_64-pc-unknown".into(), + pointer_width: 64, + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), + arch: "x86_64".into(), + options: TargetOptions { + cpu: "x86-64".into(), + max_atomic_width: Some(64), + pre_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::Yes, Lld::No), + &["-Vgcc_ntox86_64_cxx"], + ), + ..nto_qnx_base::opts() + }, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 86bb2c0d3816a..2d3b830946145 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -33,6 +33,7 @@ - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) + - [\*-nto-qnx-\*](platform-support/nto-qnx.md) - [*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0315f1e3725ff..28929acb9b48d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -214,6 +214,7 @@ target | std | host | notes [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | +[`aarch64-unknown-nto-qnx7.1.0`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.1 RTOS | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -303,6 +304,7 @@ target | std | host | notes `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator +[`x86_64-pc-nto-qnx7.1.0`](platform-support/nto-qnx.md) | ? | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support `x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md new file mode 100644 index 0000000000000..2d4265334eaca --- /dev/null +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -0,0 +1,117 @@ +# nto-qnx + +**Tier: 3** + +[BlackBerry® QNX®][BlackBerry] Neutrino (nto) Real-time operating system. +The support has been implemented jointly by [Elektrobit Automotive GmbH][Elektrobit] +and [BlackBerry][BlackBerry]. + +[BlackBerry]: https://blackberry.qnx.com +[Elektrobit]: https://www.elektrobit.com + +## Target maintainers + +- Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb + +## Requirements + +Currently, only cross-compilation for QNX Neutrino on AArch64 and x86_64 are supported (little endian). +Adding other architectures that are supported by QNX Neutrino is possible. + +The standard library does not yet support QNX Neutrino. Therefore, only `no_std` code can +be compiled. + +`core` and `alloc` (with default allocator) are supported. + +Applications must link against `libc.so` (see example). This is required because applications +always link against the `crt` library and `crt` depends on `libc.so`. + +The correct version of `qcc` must be available by setting the `$PATH` variable (e.g. by sourcing `qnxsdp-env.sh` of the +QNX Neutrino toolchain). + +### Small example application + +```rust +#![no_std] +#![no_main] +#![feature(lang_items)] + +// We must always link against libc, even if no external functions are used +// "extern C" - Block can be empty but must be present +#[link(name = "c")] +extern "C" { + pub fn printf(format: *const core::ffi::c_char, ...) -> core::ffi::c_int; +} + +#[no_mangle] +pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { + const HELLO: &'static str = "Hello World, the answer is %d\n\0"; + unsafe { + printf(HELLO.as_ptr() as *const _, 42); + } + 0 +} + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(_panic: &PanicInfo<'_>) -> ! { + loop {} +} + +#[lang = "eh_personality"] +#[no_mangle] +pub extern "C" fn rust_eh_personality() {} +``` + +The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.1. + +There are no further known requirements. + +## Conditional compilation + +For conditional compilation, following QNX Neutrino specific attributes are defined: + +- `target_os` = `"nto"` +- `target_env` = `"nto71"` (for QNX Neutrino 7.1) + +## Building the target + +1. Create a `config.toml` + +Example content: + +```toml +profile = "compiler" +changelog-seen = 2 +``` + +2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host (for both `aarch64` and `x86_64` targets) + +Run the following: + +```bash +env \ + CC_aarch64-unknown-nto-qnx7.1.0="qcc" \ + CFLAGS_aarch64-unknown-nto-qnx7.1.0="-Vgcc_ntoaarch64le_cxx" \ + CXX_aarch64-unknown-nto-qnx7.1.0="qcc" \ + AR_aarch64_unknown_nto_qnx7.1.0="ntoaarch64-ar" \ + CC_x86_64-pc-nto-qnx7.1.0="qcc" \ + CFLAGS_x86_64-pc-nto-qnx7.1.0="-Vgcc_ntox86_64_cxx" \ + CXX_x86_64-pc-nto-qnx7.1.0="qcc" \ + AR_x86_64_pc_nto_qnx7.1.0="ntox86_64-ar" \ + ./x.py build --target aarch64-unknown-nto-qnx7.1.0 --target x86_64-pc-nto-qnx7.1.0 --target x86_64-unknown-linux-gnu rustc library/core library/alloc/ +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you must either build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Compiled executables can directly be run on QNX Neutrino. + +## Cross-compilation toolchains and C code + +Compiling C code requires the same environment variables to be set as compiling the Rust toolchain (see above), to ensure `qcc` is used with proper arguments. To ensure compatibility, do not specify any further arguments that for example change calling conventions or memory layout. From ae71df987baba72251db819f32e77308e88e9c13 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Wed, 5 Oct 2022 12:32:22 +0200 Subject: [PATCH 17/20] Add `nto` as known `target_os` --- src/test/ui/check-cfg/well-known-values.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/check-cfg/well-known-values.stderr b/src/test/ui/check-cfg/well-known-values.stderr index 4ec74494fe09b..6c0dc05ba2330 100644 --- a/src/test/ui/check-cfg/well-known-values.stderr +++ b/src/test/ui/check-cfg/well-known-values.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: did you mean: `"linux"` | - = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous + = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value From f149837f0db964ffc3b67bfa003da621113ef522 Mon Sep 17 00:00:00 2001 From: Florian Bartels <108917393+flba-eb@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:29:33 +0100 Subject: [PATCH 18/20] Add Tristan as maintainer --- src/doc/rustc/src/platform-support/nto-qnx.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 2d4265334eaca..62d426bf3161b 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -12,6 +12,7 @@ and [BlackBerry][BlackBerry]. ## Target maintainers - Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb +- Tristan Roach, `TRoach@blackberry.com`, https://github.com/gh-tr ## Requirements From f6d7f0807275f709adab2a3ead9c51d0f2291e9d Mon Sep 17 00:00:00 2001 From: StackDoubleFlow Date: Mon, 7 Nov 2022 22:42:07 -0600 Subject: [PATCH 19/20] Issue error when `-C link-self-contained` option is used on unsupported platforms Document supported targets for `-C link-self-contained` Move `LinkSelfContainedDefault::True` from wasm_base to wasm32_wasi --- compiler/rustc_codegen_ssa/src/back/link.rs | 3 +++ compiler/rustc_codegen_ssa/src/errors.rs | 4 ++++ compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl | 2 ++ compiler/rustc_target/src/spec/wasm32_wasi.rs | 6 +++++- compiler/rustc_target/src/spec/wasm_base.rs | 4 ---- src/doc/rustc/src/codegen-options/index.md | 4 ++-- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5a1ad792924fc..cc9367f53265a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1582,6 +1582,9 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { /// We only provide such support for a very limited number of targets. fn self_contained(sess: &Session, crate_type: CrateType) -> bool { if let Some(self_contained) = sess.opts.cg.link_self_contained { + if sess.target.link_self_contained == LinkSelfContainedDefault::False { + sess.emit_err(errors::UnsupportedLinkSelfContained); + } return self_contained; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 36c94462b0b3e..d24579364c476 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -521,3 +521,7 @@ pub enum AppleSdkRootError<'a> { #[diag(codegen_ssa_apple_sdk_error_sdk_path)] SdkPath { sdk_name: &'a str, error: Error }, } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unsupported_link_self_contained)] +pub struct UnsupportedLinkSelfContained; diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index ad0d758210175..717c7816fabc2 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -182,3 +182,5 @@ codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$ codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error} + +codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 93a956403e50f..6f0bbf0672d44 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -72,7 +72,8 @@ //! best we can with this target. Don't start relying on too much here unless //! you know what you're getting in to! -use super::{crt_objects, wasm_base, Cc, LinkerFlavor, Target}; +use super::crt_objects::{self, LinkSelfContainedDefault}; +use super::{wasm_base, Cc, LinkerFlavor, Target}; pub fn target() -> Target { let mut options = wasm_base::options(); @@ -83,6 +84,9 @@ pub fn target() -> Target { options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained(); options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained(); + // FIXME: Figure out cases in which WASM needs to link with a native toolchain. + options.link_self_contained = LinkSelfContainedDefault::True; + // Right now this is a bit of a workaround but we're currently saying that // the target by default has a static crt which we're taking as a signal // for "use the bundled crt". If that's turned off then the system's crt diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index 528a84a8b37cb..625d3b37c4f26 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -1,4 +1,3 @@ -use super::crt_objects::LinkSelfContainedDefault; use super::{cvs, Cc, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; pub fn options() -> TargetOptions { @@ -95,9 +94,6 @@ pub fn options() -> TargetOptions { pre_link_args, - // FIXME: Figure out cases in which WASM needs to link with a native toolchain. - link_self_contained: LinkSelfContainedDefault::True, - // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when // PIC code is implemented this has quite a drastic effect if it stays // at the default, `pic`. In an effort to keep wasm binaries as minimal diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index f5a49410ea555..7e355b7fccfc4 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -210,8 +210,8 @@ metrics. ## link-self-contained -On targets that support it this flag controls whether the linker will use libraries and objects -shipped with Rust instead or those in the system. +On `windows-gnu`, `linux-musl`, and `wasi` targets, this flag controls whether the +linker will use libraries and objects shipped with Rust instead or those in the system. It takes one of the following values: * no value: rustc will use heuristic to disable self-contained mode if system has necessary tools. From 934c4141cc56bda1f46d508df71d1ed8524fb915 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 11 Nov 2022 22:07:29 +0000 Subject: [PATCH 20/20] Update cargo 9 commits in 9286a1beba5b28b115bad67de2ae91fb1c61eb0b..a3dfea71ca0c888a88111086898aa833c291d497 2022-11-04 06:41:49 +0000 to 2022-11-11 03:50:47 +0000 - fix: return non UTF-8 error message (rust-lang/cargo#11321) - Extract `two_kinds_of_msg_format_err` message to de-duplicate it (rust-lang/cargo#11358) - Propagate change of artifact bin dep to its parent fingerprint (rust-lang/cargo#11353) - Fix not a hyperlink warnings (rust-lang/cargo#11357) - Fix wait-for-publish with sparse registry (rust-lang/cargo#11356) - Add `rm` alias to configuration docs (rust-lang/cargo#11351) - Add `registries.crates-io.protocol` docs (rust-lang/cargo#11350) - test(features2): test to prevent regressing of optional host deps of dep (rust-lang/cargo#11342) - Bump to 0.68.0, update changelog (rust-lang/cargo#11340) --- Cargo.lock | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddacf9cf02463..c105d04c1f440 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,7 +273,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.67.0" +version = "0.68.0" dependencies = [ "anyhow", "atty", diff --git a/src/tools/cargo b/src/tools/cargo index 9286a1beba5b2..a3dfea71ca0c8 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 9286a1beba5b28b115bad67de2ae91fb1c61eb0b +Subproject commit a3dfea71ca0c888a88111086898aa833c291d497