From a8ff1aead87a702d78609dd873579106f6bc00c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Fri, 1 Apr 2022 18:32:02 +0200 Subject: [PATCH 01/11] Avoid duplication of doc comments in `std::char` constants and functions. For those consts and functions, only the summary is kept and a reference to the `char` associated const/method is included. Additionaly, re-exported functions have been converted to function definitions that call the previously re-exported function. This makes it easier to add a deprecated attribute to these functions in the future. --- library/core/src/char/convert.rs | 139 ++----------------------------- library/core/src/char/decode.rs | 49 +---------- library/core/src/char/mod.rs | 69 +++++++++------ 3 files changed, 54 insertions(+), 203 deletions(-) diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 4ee0310b361fb..778f06aeb63e6 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -6,52 +6,10 @@ use crate::fmt; use crate::mem::transmute; use crate::str::FromStr; -/// Converts a `u32` to a `char`. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// `as`: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value -/// for a [`char`]. -/// -/// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked`]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x2764); -/// -/// assert_eq!(Some('❤'), c); -/// ``` -/// -/// Returning `None` when the input is not a valid [`char`]: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x110000); -/// -/// assert_eq!(None, c); -/// ``` -#[doc(alias = "chr")] +/// Converts a `u32` to a `char`. See [`char::from_u32`]. #[must_use] #[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const fn from_u32(i: u32) -> Option { +pub(super) const fn from_u32(i: u32) -> Option { // FIXME: once Result::ok is const fn, use it here match char_try_from_u32(i) { Ok(c) => Some(c), @@ -59,44 +17,11 @@ pub const fn from_u32(i: u32) -> Option { } } -/// Converts a `u32` to a `char`, ignoring validity. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// `as`: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to -/// [`char`], possibly creating an invalid one. -/// -/// # Safety -/// -/// This function is unsafe, as it may construct invalid `char` values. -/// -/// For a safe version of this function, see the [`from_u32`] function. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = unsafe { char::from_u32_unchecked(0x2764) }; -/// -/// assert_eq!('❤', c); -/// ``` +/// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`]. +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] #[inline] #[must_use] -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const unsafe fn from_u32_unchecked(i: u32) -> char { +pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } } } @@ -317,60 +242,10 @@ impl fmt::Display for CharTryFromError { } } -/// Converts a digit in the given radix to a `char`. -/// -/// A 'radix' here is sometimes also called a 'base'. A radix of two -/// indicates a binary number, a radix of ten, decimal, and a radix of -/// sixteen, hexadecimal, to give some common values. Arbitrary -/// radices are supported. -/// -/// `from_digit()` will return `None` if the input is not a digit in -/// the given radix. -/// -/// # Panics -/// -/// Panics if given a radix larger than 36. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(4, 10); -/// -/// assert_eq!(Some('4'), c); -/// -/// // Decimal 11 is a single digit in base 16 -/// let c = char::from_digit(11, 16); -/// -/// assert_eq!(Some('b'), c); -/// ``` -/// -/// Returning `None` when the input is not a digit: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(20, 10); -/// -/// assert_eq!(None, c); -/// ``` -/// -/// Passing a large radix, causing a panic: -/// -/// ```should_panic -/// use std::char; -/// -/// // this panics -/// let c = char::from_digit(1, 37); -/// ``` +/// Converts a digit in the given radix to a `char`. See [`char::from_digit`]. #[inline] #[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const fn from_digit(num: u32, radix: u32) -> Option { +pub(super) const fn from_digit(num: u32, radix: u32) -> Option { if radix > 36 { panic!("from_digit: radix is too high (maximum 36)"); } diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 794c9c13cc3b8..71297acd17145 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -30,54 +30,9 @@ pub struct DecodeUtf16Error { } /// Creates an iterator over the UTF-16 encoded code points in `iter`, -/// returning unpaired surrogates as `Err`s. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char::decode_utf16; -/// -/// // 𝄞music -/// let v = [ -/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, -/// ]; -/// -/// assert_eq!( -/// decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::>(), -/// vec![ -/// Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834) -/// ] -/// ); -/// ``` -/// -/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: -/// -/// ``` -/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; -/// -/// // 𝄞music -/// let v = [ -/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, -/// ]; -/// -/// assert_eq!( -/// decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::(), -/// "𝄞mus�ic�" -/// ); -/// ``` -#[stable(feature = "decode_utf16", since = "1.9.0")] +/// returning unpaired surrogates as `Err`s. See [`char::decode_utf16`]. #[inline] -pub fn decode_utf16>(iter: I) -> DecodeUtf16 { +pub(super) fn decode_utf16>(iter: I) -> DecodeUtf16 { DecodeUtf16 { iter: iter.into_iter(), buf: None } } diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 9364ac4f3ec1f..0df23e7bbe695 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -23,18 +23,12 @@ mod decode; mod methods; // stable re-exports -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -pub use self::convert::from_u32_unchecked; #[stable(feature = "try_from", since = "1.34.0")] pub use self::convert::CharTryFromError; #[stable(feature = "char_from_str", since = "1.20.0")] pub use self::convert::ParseCharError; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::convert::{from_digit, from_u32}; #[stable(feature = "decode_utf16", since = "1.9.0")] -pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; -#[stable(feature = "unicode_version", since = "1.45.0")] -pub use crate::unicode::UNICODE_VERSION; +pub use self::decode::{DecodeUtf16, DecodeUtf16Error}; // perma-unstable re-exports #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] @@ -89,30 +83,57 @@ const MAX_THREE_B: u32 = 0x10000; Cn Unassigned a reserved unassigned code point or a noncharacter */ -/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. -/// -/// # Examples -/// -/// ``` -/// # fn something_which_returns_char() -> char { 'a' } -/// let c: char = something_which_returns_char(); -/// assert!(c <= char::MAX); -/// -/// let value_at_max = char::MAX as u32; -/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); -/// assert_eq!(char::from_u32(value_at_max + 1), None); -/// ``` +/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead. #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = char::MAX; /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a -/// decoding error. -/// -/// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). +/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead. #[stable(feature = "decode_utf16", since = "1.9.0")] pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER; +/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of +/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead. +#[stable(feature = "unicode_version", since = "1.45.0")] +pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION; + +/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning +/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[inline] +pub fn decode_utf16>(iter: I) -> DecodeUtf16 { + self::decode::decode_utf16(iter) +} + +/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const fn from_u32(i: u32) -> Option { + self::convert::from_u32(i) +} + +/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]. +/// instead. +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const unsafe fn from_u32_unchecked(i: u32) -> char { + // SAFETY: the safety contract must be upheld by the caller. + unsafe { self::convert::from_u32_unchecked(i) } +} + +/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const fn from_digit(num: u32, radix: u32) -> Option { + self::convert::from_digit(num, radix) +} + /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. /// From c34473bceaa7cb6a87c20e47f76ff4f282258840 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:50:56 +0000 Subject: [PATCH 02/11] Reimplement lowering of sym operands for asm! so that it also works with global_asm! --- compiler/rustc_ast/src/ast.rs | 16 ++- compiler/rustc_ast/src/mut_visit.rs | 29 ++++- compiler/rustc_ast/src/visit.rs | 19 ++- compiler/rustc_ast_lowering/src/asm.rs | 65 +++++++++- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 +- compiler/rustc_builtin_macros/src/asm.rs | 22 ++-- compiler/rustc_hir/src/hir.rs | 10 +- compiler/rustc_hir/src/intravisit.rs | 21 ++-- compiler/rustc_hir_pretty/src/lib.rs | 11 +- compiler/rustc_middle/src/thir.rs | 3 +- compiler/rustc_middle/src/thir/visit.rs | 4 +- .../rustc_mir_build/src/build/expr/into.rs | 12 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 119 ++++++------------ compiler/rustc_passes/src/dead.rs | 4 + compiler/rustc_passes/src/intrinsicck.rs | 42 ++++++- compiler/rustc_passes/src/liveness.rs | 10 +- compiler/rustc_passes/src/naked_functions.rs | 4 +- compiler/rustc_resolve/src/diagnostics.rs | 6 + compiler/rustc_resolve/src/late.rs | 27 +++- compiler/rustc_resolve/src/lib.rs | 40 ++++++ compiler/rustc_typeck/src/check/expr.rs | 7 +- compiler/rustc_typeck/src/check/mod.rs | 33 +++-- compiler/rustc_typeck/src/collect/type_of.rs | 3 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 7 +- .../clippy_lints/src/loops/never_loop.rs | 7 +- .../clippy_lints/src/utils/inspector.rs | 23 +++- .../clippy/clippy_utils/src/hir_utils.rs | 3 +- 27 files changed, 394 insertions(+), 161 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 75ccbc92be1f6..136bc199ba378 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2061,6 +2061,20 @@ impl InlineAsmTemplatePiece { } } +/// Inline assembly symbol operands get their own AST node that is somewhat +/// similar to `AnonConst`. +/// +/// The main difference is that we specifically don't assign it `DefId` in +/// `DefCollector`. Instead this is deferred until AST lowering where we +/// lower it to an `AnonConst` (for functions) or a `Path` (for statics) +/// depending on what the path resolves to. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct InlineAsmSym { + pub id: NodeId, + pub qself: Option, + pub path: Path, +} + /// Inline assembly operand. /// /// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`. @@ -2090,7 +2104,7 @@ pub enum InlineAsmOperand { anon_const: AnonConst, }, Sym { - expr: P, + sym: InlineAsmSym, }, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 32621eb5f2f66..a65f860d24084 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -280,6 +280,14 @@ pub trait MutVisitor: Sized { fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { noop_flat_map_pat_field(fp, self) } + + fn visit_inline_asm(&mut self, asm: &mut InlineAsm) { + noop_visit_inline_asm(asm, self) + } + + fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { + noop_visit_inline_asm_sym(sym, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -1017,7 +1025,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { } } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), - ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis), + ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty, .. }) => { @@ -1235,13 +1243,12 @@ pub fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonCo vis.visit_expr(value); } -fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { +pub fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { for (op, _) in &mut asm.operands { match op { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } - | InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr), + | InlineAsmOperand::InOut { expr, .. } => vis.visit_expr(expr), InlineAsmOperand::Out { expr: None, .. } => {} InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { vis.visit_expr(in_expr); @@ -1249,11 +1256,21 @@ fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { vis.visit_expr(out_expr); } } - InlineAsmOperand::Const { anon_const, .. } => vis.visit_anon_const(anon_const), + InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const), + InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym), } } } +pub fn noop_visit_inline_asm_sym( + InlineAsmSym { id, qself, path }: &mut InlineAsmSym, + vis: &mut T, +) { + vis.visit_id(id); + vis.visit_qself(qself); + vis.visit_path(path); +} + pub fn noop_visit_expr( Expr { kind, id, span, attrs, tokens }: &mut Expr, vis: &mut T, @@ -1372,7 +1389,7 @@ pub fn noop_visit_expr( ExprKind::Ret(expr) => { visit_opt(expr, |expr| vis.visit_expr(expr)); } - ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis), + ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = se.deref_mut(); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ed16c25d921e4..3183612597d13 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -214,6 +214,12 @@ pub trait Visitor<'ast>: Sized { fn visit_crate(&mut self, krate: &'ast Crate) { walk_crate(self, krate) } + fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) { + walk_inline_asm(self, asm) + } + fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) { + walk_inline_asm_sym(self, sym) + } } #[macro_export] @@ -717,13 +723,12 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo visitor.visit_expr(&constant.value); } -fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) { +pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) { for (op, _) in &asm.operands { match op { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } - | InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr), + | InlineAsmOperand::InOut { expr, .. } => visitor.visit_expr(expr), InlineAsmOperand::Out { expr: None, .. } => {} InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { visitor.visit_expr(in_expr); @@ -732,10 +737,18 @@ fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) { } } InlineAsmOperand::Const { anon_const, .. } => visitor.visit_anon_const(anon_const), + InlineAsmOperand::Sym { sym } => visitor.visit_inline_asm_sym(sym), } } } +pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineAsmSym) { + if let Some(ref qself) = sym.qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(&sym.path, sym.id); +} + pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_attribute, expression.attrs.iter()); diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 171cc60dfd77c..ae3e367596258 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,12 +1,17 @@ +use crate::{ImplTraitContext, ImplTraitPosition, ParamMode}; + use super::LoweringContext; +use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::definitions::DefPathData; use rustc_session::parse::feature_err; -use rustc_span::{sym, Span}; +use rustc_span::{sym, ExpnId, Span}; use rustc_target::asm; use std::collections::hash_map::Entry; use std::fmt::Write; @@ -188,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { anon_const: self.lower_anon_const(anon_const), } } - InlineAsmOperand::Sym { ref expr } => { + InlineAsmOperand::Sym { ref sym } => { if !self.sess.features_untracked().asm_sym { feature_err( &self.sess.parse_sess, @@ -198,7 +203,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) .emit(); } - hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) } + + let static_def_id = self + .resolver + .get_partial_res(sym.id) + .filter(|res| res.unresolved_segments() == 0) + .and_then(|res| { + if let Res::Def(DefKind::Static(_), def_id) = res.base_res() { + Some(def_id) + } else { + None + } + }); + + if let Some(def_id) = static_def_id { + let path = self.lower_qpath( + sym.id, + &sym.qself, + &sym.path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ); + hir::InlineAsmOperand::SymStatic { path, def_id } + } else { + // Replace the InlineAsmSym AST node with an + // Expr using the name node id. + let expr = Expr { + id: sym.id, + kind: ExprKind::Path(sym.qself.clone(), sym.path.clone()), + span: *op_sp, + attrs: AttrVec::new(), + tokens: None, + }; + + // Wrap the expression in an AnonConst. + let parent_def_id = self.current_hir_id_owner; + let node_id = self.resolver.next_node_id(); + self.resolver.create_def( + parent_def_id, + node_id, + DefPathData::AnonConst, + ExpnId::root(), + *op_sp, + ); + let anon_const = AnonConst { id: node_id, value: P(expr) }; + hir::InlineAsmOperand::SymFn { + anon_const: self.lower_anon_const(&anon_const), + } + } } }; (op, self.lower_span(*op_sp)) @@ -260,7 +312,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { err.span_label(op_sp, "argument"); err.emit(); } - hir::InlineAsmOperand::Sym { .. } => { + hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => { let mut err = sess.struct_span_err( placeholder_span, "asm template modifiers are not allowed for `sym` arguments", @@ -308,7 +361,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::InlineAsmOperand::InOut { .. } | hir::InlineAsmOperand::SplitInOut { .. } => (true, true), - hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => { + hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => { unreachable!() } }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 719fd27109321..c2247150d09c2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1266,10 +1266,14 @@ impl<'a> State<'a> { s.space(); s.print_expr(&anon_const.value); } - InlineAsmOperand::Sym { expr } => { + InlineAsmOperand::Sym { sym } => { s.word("sym"); s.space(); - s.print_expr(expr); + if let Some(qself) = &sym.qself { + s.print_qpath(&sym.path, qself, true); + } else { + s.print_path(&sym.path, true, 0); + } } } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 57ef46475ddd8..030295d3d8dc3 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -154,17 +154,19 @@ pub fn parse_asm_args<'a>( } else if p.eat_keyword(kw::Const) { let anon_const = p.parse_anon_const_expr()?; ast::InlineAsmOperand::Const { anon_const } - } else if !is_global_asm && p.eat_keyword(sym::sym) { + } else if p.eat_keyword(sym::sym) { let expr = p.parse_expr()?; - match expr.kind { - ast::ExprKind::Path(..) => {} - _ => { - let err = diag - .struct_span_err(expr.span, "argument to `sym` must be a path expression"); - return Err(err); - } - } - ast::InlineAsmOperand::Sym { expr } + let ast::ExprKind::Path(qself, path) = &expr.kind else { + let err = diag + .struct_span_err(expr.span, "expected a path for argument to `sym`"); + return Err(err); + }; + let sym = ast::InlineAsmSym { + id: ast::DUMMY_NODE_ID, + qself: qself.clone(), + path: path.clone(), + }; + ast::InlineAsmOperand::Sym { sym } } else if allow_templates { let template = p.parse_expr()?; // If it can't possibly expand to a string, provide diagnostics here to include other diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 10871df3ab9d0..cab1d2f096523 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2390,8 +2390,12 @@ pub enum InlineAsmOperand<'hir> { Const { anon_const: AnonConst, }, - Sym { - expr: Expr<'hir>, + SymFn { + anon_const: AnonConst, + }, + SymStatic { + path: QPath<'hir>, + def_id: DefId, }, } @@ -2402,7 +2406,7 @@ impl<'hir> InlineAsmOperand<'hir> { | Self::Out { reg, .. } | Self::InOut { reg, .. } | Self::SplitInOut { reg, .. } => Some(reg), - Self::Const { .. } | Self::Sym { .. } => None, + Self::Const { .. } | Self::SymFn { .. } | Self::SymStatic { .. } => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1b40f3d390ee5..445b856e513dc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -484,6 +484,9 @@ pub trait Visitor<'v>: Sized { fn visit_defaultness(&mut self, defaultness: &'v Defaultness) { walk_defaultness(self, defaultness); } + fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) { + walk_inline_asm(self, asm, id); + } } pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) { @@ -588,7 +591,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { } ItemKind::GlobalAsm(asm) => { visitor.visit_id(item.hir_id()); - walk_inline_asm(visitor, asm); + visitor.visit_inline_asm(asm, item.hir_id()); } ItemKind::TyAlias(ref ty, ref generics) => { visitor.visit_id(item.hir_id()); @@ -648,12 +651,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { } } -fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>) { - for (op, _op_sp) in asm.operands { +pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) { + for (op, op_sp) in asm.operands { match op { - InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::InOut { expr, .. } - | InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr), + InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => { + visitor.visit_expr(expr) + } InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { visitor.visit_expr(expr); @@ -665,7 +668,9 @@ fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>) visitor.visit_expr(out_expr); } } - InlineAsmOperand::Const { anon_const } => visitor.visit_anon_const(anon_const), + InlineAsmOperand::Const { anon_const, .. } + | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const), + InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp), } } } @@ -1221,7 +1226,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, optional_expression); } ExprKind::InlineAsm(ref asm) => { - walk_inline_asm(visitor, asm); + visitor.visit_inline_asm(asm, expression.hir_id); } ExprKind::Yield(ref subexpression, _) => { visitor.visit_expr(subexpression); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3042c61002c4..27f07a479b1b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1352,10 +1352,15 @@ impl<'a> State<'a> { s.space(); s.print_anon_const(anon_const); } - hir::InlineAsmOperand::Sym { expr } => { - s.word("sym"); + hir::InlineAsmOperand::SymFn { anon_const } => { + s.word("sym_fn"); s.space(); - s.print_expr(expr); + s.print_anon_const(anon_const); + } + hir::InlineAsmOperand::SymStatic { path, def_id: _ } => { + s.word("sym_static"); + s.space(); + s.print_qpath(path, true); } }, AsmArg::Options(opts) => { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b31cc17a9594d..99f9e74b19072 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -526,7 +526,8 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - expr: ExprId, + value: Const<'tcx>, + span: Span, }, SymStatic { def_id: DefId, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 451fa46638771..ea38d8d667966 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -129,8 +129,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp match op { In { expr, reg: _ } | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + | InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]), SplitInOut { in_expr, out_expr, reg: _, late: _ } => { visitor.visit_expr(&visitor.thir()[*in_expr]); if let Some(out_expr) = out_expr { @@ -139,6 +138,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } + | SymFn { value: _, span: _ } | SymStatic { def_id: _ } => {} } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a8f623dbe4693..3537f39d19c26 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -430,9 +430,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }), } } - thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn { - value: Box::new(this.as_constant(&this.thir[expr])), - }, + thir::InlineAsmOperand::SymFn { value, span } => { + mir::InlineAsmOperand::SymFn { + value: Box::new(Constant { + span, + user_ty: None, + literal: value.into(), + }), + } + } thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e6afc89baa03b..82da0bc9f362d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -462,91 +462,48 @@ impl<'tcx> Cx<'tcx> { operands: asm .operands .iter() - .map(|(op, _op_sp)| { - match *op { - hir::InlineAsmOperand::In { reg, ref expr } => { - InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) } - } - hir::InlineAsmOperand::Out { reg, late, ref expr } => { - InlineAsmOperand::Out { - reg, - late, - expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), - } - } - hir::InlineAsmOperand::InOut { reg, late, ref expr } => { - InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } - } - hir::InlineAsmOperand::SplitInOut { - reg, - late, - ref in_expr, - ref out_expr, - } => InlineAsmOperand::SplitInOut { + .map(|(op, _op_sp)| match *op { + hir::InlineAsmOperand::In { reg, ref expr } => { + InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) } + } + hir::InlineAsmOperand::Out { reg, late, ref expr } => { + InlineAsmOperand::Out { reg, late, - in_expr: self.mirror_expr(in_expr), - out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), - }, - hir::InlineAsmOperand::Const { ref anon_const } => { - let anon_const_def_id = - self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); - let span = self.tcx.hir().span(anon_const.hir_id); - - InlineAsmOperand::Const { value, span } - } - hir::InlineAsmOperand::Sym { ref expr } => { - let hir::ExprKind::Path(ref qpath) = expr.kind else { - span_bug!( - expr.span, - "asm `sym` operand should be a path, found {:?}", - expr.kind - ); - }; - let temp_lifetime = - self.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let res = self.typeck_results().qpath_res(qpath, expr.hir_id); - let ty; - match res { - Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => { - ty = self.typeck_results().node_type(expr.hir_id); - let user_ty = - self.user_substs_applied_to_res(expr.hir_id, res); - InlineAsmOperand::SymFn { - expr: self.thir.exprs.push(Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::zero_sized_literal(user_ty), - }), - } - } - - Res::Def(DefKind::Static(_), def_id) => { - InlineAsmOperand::SymStatic { def_id } - } - - _ => { - self.tcx.sess.span_err( - expr.span, - "asm `sym` operand must point to a fn or static", - ); - - // Not a real fn, but we're not reaching codegen anyways... - ty = self.tcx.ty_error(); - InlineAsmOperand::SymFn { - expr: self.thir.exprs.push(Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::zero_sized_literal(None), - }), - } - } - } + expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), } } + hir::InlineAsmOperand::InOut { reg, late, ref expr } => { + InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } + } + hir::InlineAsmOperand::SplitInOut { + reg, + late, + ref in_expr, + ref out_expr, + } => InlineAsmOperand::SplitInOut { + reg, + late, + in_expr: self.mirror_expr(in_expr), + out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), + }, + hir::InlineAsmOperand::Const { ref anon_const } => { + let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let span = self.tcx.hir().span(anon_const.hir_id); + + InlineAsmOperand::Const { value, span } + } + hir::InlineAsmOperand::SymFn { ref anon_const } => { + let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let span = self.tcx.hir().span(anon_const.hir_id); + + InlineAsmOperand::SymFn { value, span } + } + hir::InlineAsmOperand::SymStatic { path: _, def_id } => { + InlineAsmOperand::SymStatic { def_id } + } }) .collect(), options: asm.options, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c777074df4641..0ceccff7cac52 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -537,6 +537,10 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id); } } + hir::ItemKind::GlobalAsm(_) => { + // global_asm! is always live. + self.worklist.push(item.def_id); + } _ => (), } } diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 027eac16bad30..7028fc4412648 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -1,3 +1,4 @@ +use hir::intravisit::walk_inline_asm; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; @@ -483,7 +484,10 @@ impl<'tcx> ExprVisitor<'tcx> { ); } } - hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {} + // These are checked in ItemVisitor. + hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => {} } } } @@ -498,6 +502,42 @@ impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> { ExprVisitor { tcx: self.tcx, param_env, typeck_results }.visit_body(body); self.visit_body(body); } + + fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) { + for (op, op_sp) in asm.operands.iter() { + match *op { + // These are checked in ExprVisitor. + hir::InlineAsmOperand::In { .. } + | hir::InlineAsmOperand::Out { .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { .. } => {} + // No special checking is needed for these: + // - Typeck has checked that Const operands are integers. + // - AST lowering guarantees that SymStatic points to a static. + hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {} + // Check that sym actually points to a function. Later passes + // depend on this. + hir::InlineAsmOperand::SymFn { anon_const } => { + let ty = self.tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + match ty.kind() { + ty::Never | ty::Error(_) => {} + ty::FnDef(..) => {} + _ => { + let mut err = + self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand"); + err.span_label( + self.tcx.hir().span(anon_const.body.hir_id), + &format!("is {} `{}`", ty.kind().article(), ty), + ); + err.help("`sym` operands must refer to either a function or a static"); + err.emit(); + } + }; + } + } + } + walk_inline_asm(self, asm, id); + } } impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7298aba7e8763..99ea73fe2fe10 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1043,7 +1043,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match op { hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Const { .. } - | hir::InlineAsmOperand::Sym { .. } => {} + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { succ = self.write_place(expr, succ, ACC_WRITE); @@ -1064,8 +1065,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut succ = succ; for (op, _op_sp) in asm.operands.iter().rev() { match op { - hir::InlineAsmOperand::In { expr, .. } - | hir::InlineAsmOperand::Sym { expr, .. } => { + hir::InlineAsmOperand::In { expr, .. } => { succ = self.propagate_through_expr(expr, succ) } hir::InlineAsmOperand::Out { expr, .. } => { @@ -1082,7 +1082,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } succ = self.propagate_through_expr(in_expr, succ); } - hir::InlineAsmOperand::Const { .. } => {} + hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => {} } } succ diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index af78fd5a6f212..e85720952da7a 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -252,7 +252,9 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .operands .iter() .filter_map(|&(ref op, op_sp)| match op { - InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None, + InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => None, InlineAsmOperand::In { .. } | InlineAsmOperand::Out { .. } | InlineAsmOperand::InOut { .. } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6c7d4afea67ee..c5cb6ebdacab2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -621,6 +621,12 @@ impl<'a> Resolver<'a> { err.span_label(trait_item_span, "item in trait"); err } + ResolutionError::InvalidAsmSym => { + let mut err = self.session.struct_span_err(span, "invalid `sym` operand"); + err.span_label(span, &format!("is a local variable")); + err.help("`sym` operands must refer to either a function or a static"); + err + } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 400adf20cba7c..c19ccffec98ec 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -140,6 +140,10 @@ crate enum RibKind<'a> { /// We are inside of the type of a const parameter. Can't refer to any /// parameters. ConstParamTyRibKind, + + /// We are inside a `sym` inline assembly operand. Can only refer to + /// globals. + InlineAsmSymRibKind, } impl RibKind<'_> { @@ -153,7 +157,8 @@ impl RibKind<'_> { | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) - | ConstParamTyRibKind => false, + | ConstParamTyRibKind + | InlineAsmSymRibKind => false, AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true, } } @@ -725,6 +730,23 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_where_predicate(self, p); self.diagnostic_metadata.current_where_predicate = previous_value; } + + fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) { + // This is similar to the code for AnonConst. + self.with_rib(ValueNS, InlineAsmSymRibKind, |this| { + this.with_rib(TypeNS, InlineAsmSymRibKind, |this| { + this.with_label_rib(InlineAsmSymRibKind, |this| { + this.smart_resolve_path( + sym.id, + sym.qself.as_ref(), + &sym.path, + PathSource::Expr(None), + ); + visit::walk_inline_asm_sym(this, sym); + }); + }) + }); + } } impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { @@ -888,7 +910,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ConstantItemRibKind(..) | ModuleRibKind(..) | ForwardGenericParamBanRibKind - | ConstParamTyRibKind => { + | ConstParamTyRibKind + | InlineAsmSymRibKind => { return false; } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1f0a6e5ce9716..250d4fc1f06b9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -273,6 +273,8 @@ enum ResolutionError<'a> { trait_item_span: Span, code: rustc_errors::DiagnosticId, }, + /// Inline asm `sym` operand must refer to a `fn` or `static`. + InvalidAsmSym, } enum VisResolutionError<'a> { @@ -2719,6 +2721,12 @@ impl<'a> Resolver<'a> { } return Res::Err; } + InlineAsmSymRibKind => { + if let Some(span) = finalize { + self.report_error(span, InvalidAsmSym); + } + return Res::Err; + } } } if let Some((span, res_err)) = res_err { @@ -2779,6 +2787,22 @@ impl<'a> Resolver<'a> { } return Res::Err; } + InlineAsmSymRibKind => { + let features = self.session.features_untracked(); + if !features.generic_const_exprs { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: true, + }, + ); + } + return Res::Err; + } + continue; + } }; if let Some(span) = finalize { @@ -2843,6 +2867,22 @@ impl<'a> Resolver<'a> { } return Res::Err; } + InlineAsmSymRibKind => { + let features = self.session.features_untracked(); + if !features.generic_const_exprs { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: false, + }, + ); + } + return Res::Err; + } + continue; + } }; // This was an attempt to use a const parameter outside its scope. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 82641a489f66a..4bbfd5f168b03 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2535,12 +2535,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_asm_operand(out_expr, false); } } - hir::InlineAsmOperand::Const { anon_const } => { + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => { self.to_const(anon_const); } - hir::InlineAsmOperand::Sym { expr } => { - self.check_expr(expr); - } + hir::InlineAsmOperand::SymStatic { .. } => {} } } if asm.options.contains(ast::InlineAsmOptions::NORETURN) { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index bf0bf2ed59b5b..3dbf83a453dbd 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -427,16 +427,29 @@ fn typeck_with_fallback<'tcx>( span, }), Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) - | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) - if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } => { - anon_const.hir_id == id - } - _ => false, - }) => - { - // Inline assembly constants must be integers. - fcx.next_int_var() + | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { + let operand_ty = asm + .operands + .iter() + .filter_map(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } + if anon_const.hir_id == id => + { + // Inline assembly constants must be integers. + Some(fcx.next_int_var()) + } + hir::InlineAsmOperand::SymFn { anon_const } + if anon_const.hir_id == id => + { + Some(fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + })) + } + _ => None, + }) + .next(); + operand_ty.unwrap_or_else(fallback) } _ => fallback(), }, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index cb32e88588af2..9cc7a65a98c6e 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -450,7 +450,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } => anon_const.hir_id == hir_id, + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, _ => false, }) => { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 055e391d7069e..2bcf2d3b2ed71 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -358,8 +358,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::InlineAsm(asm) => { for (op, _op_sp) in asm.operands { match op { - hir::InlineAsmOperand::In { expr, .. } - | hir::InlineAsmOperand::Sym { expr, .. } => self.consume_expr(expr), + hir::InlineAsmOperand::In { expr, .. } => self.consume_expr(expr), hir::InlineAsmOperand::Out { expr: Some(expr), .. } | hir::InlineAsmOperand::InOut { expr, .. } => { self.mutate_expr(expr); @@ -371,7 +370,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } hir::InlineAsmOperand::Out { expr: None, .. } - | hir::InlineAsmOperand::Const { .. } => {} + | hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => {} } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index a0b2302662e64..9ba9642fcc833 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -169,13 +169,14 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { .iter() .map(|(o, _)| match o { InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::InOut { expr, .. } - | InlineAsmOperand::Sym { expr } => never_loop_expr(expr, main_loop_id), + | InlineAsmOperand::InOut { expr, .. } => never_loop_expr(expr, main_loop_id), InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id), InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id) }, - InlineAsmOperand::Const { .. } => NeverLoopResult::Otherwise, + InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise, }) .fold(NeverLoopResult::Otherwise, combine_both), ExprKind::Struct(_, _, None) diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index dc48ea3f4f99d..a04288e0a413e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -281,8 +281,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } - | hir::InlineAsmOperand::InOut { expr, .. } - | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), + | hir::InlineAsmOperand::InOut { expr, .. } => { + print_expr(cx, expr, indent + 1); + } hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { print_expr(cx, expr, indent + 1); @@ -294,10 +295,26 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, out_expr, indent + 1); } }, - hir::InlineAsmOperand::Const { anon_const } => { + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => { println!("{}anon_const:", ind); print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); }, + hir::InlineAsmOperand::SymStatic { path, .. } => { + match path { + hir::QPath::Resolved(ref ty, path) => { + println!("{}Resolved Path, {:?}", ind, ty); + println!("{}path: {:?}", ind, path); + }, + hir::QPath::TypeRelative(ty, seg) => { + println!("{}Relative Path, {:?}", ind, ty); + println!("{}seg: {:?}", ind, seg); + }, + hir::QPath::LangItem(lang_item, ..) => { + println!("{}Lang Item Path, {:?}", ind, lang_item.name()); + }, + } + } } } }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 00594f4d42add..c05317f59b716 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -675,7 +675,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, InlineAsmOperand::Const { anon_const } => self.hash_body(anon_const.body), - InlineAsmOperand::Sym { expr } => self.hash_expr(expr), + InlineAsmOperand::SymFn { anon_const } => self.hash_body(anon_const.body), + InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path), } } }, From c1fa773c88109d534509db69ab988109cf4a3a2d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:53:25 +0000 Subject: [PATCH 03/11] Add codegen for global_asm! sym operands --- compiler/rustc_codegen_gcc/src/asm.rs | 32 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/asm.rs | 27 ++++++++++++++-- compiler/rustc_codegen_llvm/src/base.rs | 19 +++++------ compiler/rustc_codegen_llvm/src/consts.rs | 7 ++++ compiler/rustc_codegen_llvm/src/context.rs | 8 +++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 ++ compiler/rustc_codegen_ssa/src/mono_item.rs | 24 +++++++++++++- compiler/rustc_codegen_ssa/src/traits/asm.rs | 8 +++-- compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +-- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 ++++ compiler/rustc_monomorphize/src/collector.rs | 22 ++++++++++++- 11 files changed, 137 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 8a74c4c07e0cf..2af050f0c7533 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -258,9 +258,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } InlineAsmOperandRef::SymFn { instance } => { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). constants_len += self.tcx.symbol_name(instance).name.len(); } InlineAsmOperandRef::SymStatic { def_id } => { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); } } @@ -412,13 +417,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } InlineAsmOperandRef::SymFn { instance } => { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). let name = self.tcx.symbol_name(instance).name; template_str.push_str(name); } InlineAsmOperandRef::SymStatic { def_id } => { - // TODO(@Commeownist): This may not be sufficient for all kinds of statics. - // Some statics may need the `@plt` suffix, like thread-local vars. + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). let instance = Instance::mono(self.tcx, def_id); let name = self.tcx.symbol_name(instance).name; template_str.push_str(name); @@ -656,8 +664,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl } } -impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> { - fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) { +impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span]) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); // Default to Intel syntax on x86 @@ -690,6 +698,22 @@ impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> { // here unlike normal inline assembly. template_str.push_str(string); } + + GlobalAsmOperandRef::SymFn { instance } => { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } + + GlobalAsmOperandRef::SymStatic { def_id } => { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). + let instance = Instance::mono(self.tcx, def_id); + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 96c7d884b7b20..564465a3edb1c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -307,11 +307,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } -impl AsmMethods for CodegenCx<'_, '_> { +impl<'tcx> AsmMethods<'tcx> for CodegenCx<'_, 'tcx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], - operands: &[GlobalAsmOperandRef], + operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], ) { @@ -337,6 +337,29 @@ impl AsmMethods for CodegenCx<'_, '_> { // here unlike normal inline assembly. template_str.push_str(string); } + GlobalAsmOperandRef::SymFn { instance } => { + let llval = self.get_fn(instance); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + template_str.push_str(&symbol); + } + GlobalAsmOperandRef::SymStatic { def_id } => { + let llval = self + .renamed_statics + .borrow() + .get(&def_id) + .copied() + .unwrap_or_else(|| self.get_static(def_id)); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + template_str.push_str(&symbol); + } } } } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index dd3ada443895f..94655421b8c18 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -99,7 +99,16 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } - // Run replace-all-uses-with for statics that need it + // Create the llvm.used and llvm.compiler.used variables. + if !cx.used_statics().borrow().is_empty() { + cx.create_used_variable() + } + if !cx.compiler_used_statics().borrow().is_empty() { + cx.create_compiler_used_variable() + } + + // Run replace-all-uses-with for statics that need it. This must + // happen after the llvm.used variables are created. for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() { unsafe { let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g)); @@ -114,14 +123,6 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen cx.coverageinfo_finalize(); } - // Create the llvm.used and llvm.compiler.used variables. - if !cx.used_statics().borrow().is_empty() { - cx.create_used_variable() - } - if !cx.compiler_used_statics().borrow().is_empty() { - cx.create_compiler_used_variable() - } - // Finalize debuginfo if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 413ef0ba76464..27ef8a490a593 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -409,6 +409,13 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { llvm::LLVMRustSetLinkage(new_g, linkage); llvm::LLVMRustSetVisibility(new_g, visibility); + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); + // To avoid breaking any invariants, we leave around the old // global for the moment; we'll replace all references to it // with the new global later. (See base::codegen_backend.) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 98cf873ebbdc3..d296ee3b42ce1 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -14,6 +14,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, @@ -105,6 +106,12 @@ pub struct CodegenCx<'ll, 'tcx> { /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, + + /// `codegen_static` will sometimes create a second global variable with a + /// different type and clear the symbol name of the original global. + /// `global_asm!` needs to be able to find this new global so that it can + /// compute the correct mangled symbol name to insert into the asm. + pub renamed_statics: RefCell>, } pub struct TypeLowering<'ll> { @@ -436,6 +443,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { rust_try_fn: Cell::new(None), intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), + renamed_statics: Default::default(), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 375b9927c8672..7f533b0552a5d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2537,4 +2537,6 @@ extern "C" { remark_passes_len: usize, ); + #[allow(improper_ctypes)] + pub fn LLVMRustGetMangledName(V: &Value, out: &RustString); } diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 5414c619dcbca..5006a2157fcae 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -4,7 +4,9 @@ use crate::traits::*; use rustc_hir as hir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::Instance; pub trait MonoItemExt<'a, 'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx); @@ -56,7 +58,27 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { ); GlobalAsmOperandRef::Const { string } } - _ => span_bug!(*op_sp, "invalid operand type for global_asm!"), + hir::InlineAsmOperand::SymFn { ref anon_const } => { + let ty = cx + .tcx() + .typeck_body(anon_const.body) + .node_type(anon_const.hir_id); + let instance = match ty.kind() { + &ty::FnDef(def_id, substs) => Instance::new(def_id, substs), + _ => span_bug!(*op_sp, "asm sym is not a function"), + }; + + GlobalAsmOperandRef::SymFn { instance } + } + hir::InlineAsmOperand::SymStatic { path: _, def_id } => { + GlobalAsmOperandRef::SymStatic { def_id } + } + hir::InlineAsmOperand::In { .. } + | hir::InlineAsmOperand::Out { .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { .. } => { + span_bug!(*op_sp, "invalid operand type for global_asm!") + } }) .collect(); diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 11111a7974410..c2ae74b18d81e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -36,8 +36,10 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { } #[derive(Debug)] -pub enum GlobalAsmOperandRef { +pub enum GlobalAsmOperandRef<'tcx> { Const { string: String }, + SymFn { instance: Instance<'tcx> }, + SymStatic { def_id: DefId }, } pub trait AsmBuilderMethods<'tcx>: BackendTypes { @@ -53,11 +55,11 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { ); } -pub trait AsmMethods { +pub trait AsmMethods<'tcx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], - operands: &[GlobalAsmOperandRef], + operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, line_spans: &[Span], ); diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index c529fbbf518b6..396768e0a42d0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -60,7 +60,7 @@ pub trait CodegenMethods<'tcx>: + StaticMethods + CoverageInfoMethods<'tcx> + DebugInfoMethods<'tcx> - + AsmMethods + + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + HasTyCtxt<'tcx> @@ -76,7 +76,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + StaticMethods + CoverageInfoMethods<'tcx> + DebugInfoMethods<'tcx> - + AsmMethods + + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + HasTyCtxt<'tcx> diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 51739df067f9d..3ed4396d1e955 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1835,3 +1835,9 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( unwrap(C)->setDiagnosticHandler(std::make_unique( DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes)); } + +extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { + RawRustStringOstream OS(Str); + GlobalValue *GV = unwrap(V); + Mangler().getNameWithPrefix(OS, GV, true); +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2a659a97db5f9..fdb14e45d981a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -435,7 +435,27 @@ fn collect_items_rec<'tcx>( // are supported. Therefore the value should not // depend on any other items. } - _ => span_bug!(*op_sp, "invalid operand type for global_asm!"), + hir::InlineAsmOperand::SymFn { anon_const } => { + let def_id = tcx.hir().body_owner_def_id(anon_const.body).to_def_id(); + if let Ok(val) = tcx.const_eval_poly(def_id) { + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_const_value(tcx, val, &mut neighbors); + }); + } + } + hir::InlineAsmOperand::SymStatic { path: _, def_id } => { + let instance = Instance::mono(tcx, *def_id); + if should_codegen_locally(tcx, &instance) { + trace!("collecting static {:?}", def_id); + neighbors.push(dummy_spanned(MonoItem::Static(*def_id))); + } + } + hir::InlineAsmOperand::In { .. } + | hir::InlineAsmOperand::Out { .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { .. } => { + span_bug!(*op_sp, "invalid operand type for global_asm!") + } } } } else { From e0ed0f4371265a6ab41a20d4d1b70b4b29e9d238 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:54:28 +0000 Subject: [PATCH 04/11] Update tests for sym support in global_asm! --- src/test/assembly/asm/global_asm.rs | 12 +++++++- src/test/ui/asm/aarch64/parse-error.rs | 2 +- src/test/ui/asm/aarch64/parse-error.stderr | 10 +++--- src/test/ui/asm/aarch64/type-check-2.rs | 15 ++++++--- src/test/ui/asm/aarch64/type-check-2.stderr | 34 ++++++++++++--------- src/test/ui/asm/type-check-1.rs | 9 +++++- src/test/ui/asm/type-check-1.stderr | 29 ++++++++++++++---- src/test/ui/asm/x86_64/parse-error.rs | 2 +- src/test/ui/asm/x86_64/parse-error.stderr | 10 +++--- src/test/ui/asm/x86_64/type-check-2.rs | 15 ++++++--- src/test/ui/asm/x86_64/type-check-2.stderr | 34 ++++++++++++--------- 11 files changed, 114 insertions(+), 58 deletions(-) diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs index 0358bc6d27c29..ae47f7ac391cc 100644 --- a/src/test/assembly/asm/global_asm.rs +++ b/src/test/assembly/asm/global_asm.rs @@ -2,14 +2,24 @@ // assembly-output: emit-asm // compile-flags: -C llvm-args=--x86-asm-syntax=intel -#![feature(asm_const)] +#![feature(asm_const, asm_sym)] #![crate_type = "rlib"] use std::arch::global_asm; +#[no_mangle] +fn my_func() {} + +#[no_mangle] +static MY_STATIC: i32 = 0; + // CHECK: mov eax, eax global_asm!("mov eax, eax"); // CHECK: mov ebx, 5 global_asm!("mov ebx, {}", const 5); // CHECK: mov ecx, 5 global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); +// CHECK: call my_func +global_asm!("call {}", sym my_func); +// CHECK: lea rax, [rip + MY_STATIC] +global_asm!("lea rax, [rip + {}]", sym MY_STATIC); diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs index 59d6b28d0fd99..cbc93cd3f7530 100644 --- a/src/test/ui/asm/aarch64/parse-error.rs +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -29,7 +29,7 @@ fn main() { asm!("{}", in(reg) foo => bar); //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` asm!("{}", sym foo + bar); - //~^ ERROR argument to `sym` must be a path expression + //~^ ERROR expected a path for argument to `sym` asm!("", options(foo)); //~^ ERROR expected one of asm!("", options(nomem foo)); diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr index 3f705ba5b64c2..f2013046cda42 100644 --- a/src/test/ui/asm/aarch64/parse-error.stderr +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -58,7 +58,7 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` LL | asm!("{}", in(reg) foo => bar); | ^^ expected one of 7 possible tokens -error: argument to `sym` must be a path expression +error: expected a path for argument to `sym` --> $DIR/parse-error.rs:31:24 | LL | asm!("{}", sym foo + bar); @@ -350,17 +350,17 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` -error: expected one of `clobber_abi`, `const`, or `options`, found `""` +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` --> $DIR/parse-error.rs:126:28 | LL | global_asm!("", options(), ""); - | ^^ expected one of `clobber_abi`, `const`, or `options` + | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` -error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` --> $DIR/parse-error.rs:128:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); - | ^^^^ expected one of `clobber_abi`, `const`, or `options` + | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal --> $DIR/parse-error.rs:130:13 diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs index 1b91f5d0678b4..9e53a2e0c5230 100644 --- a/src/test/ui/asm/aarch64/type-check-2.rs +++ b/src/test/ui/asm/aarch64/type-check-2.rs @@ -2,7 +2,7 @@ #![feature(repr_simd, never_type, asm_sym)] -use std::arch::asm; +use std::arch::{asm, global_asm}; #[repr(simd)] #[derive(Clone, Copy)] @@ -39,9 +39,7 @@ fn main() { asm!("{}", sym S); asm!("{}", sym main); asm!("{}", sym C); - //~^ ERROR asm `sym` operand must point to a fn or static - asm!("{}", sym x); - //~^ ERROR asm `sym` operand must point to a fn or static + //~^ ERROR invalid `sym` operand // Register operands must be Copy @@ -84,3 +82,12 @@ fn main() { asm!("{}", in(reg) u); } } + +// Sym operands must point to a function or static + +const C: i32 = 0; +static S: i32 = 0; +global_asm!("{}", sym S); +global_asm!("{}", sym main); +global_asm!("{}", sym C); +//~^ ERROR invalid `sym` operand diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr index beb301c7c7417..6047bed6e7802 100644 --- a/src/test/ui/asm/aarch64/type-check-2.stderr +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -1,13 +1,13 @@ error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:48:31 + --> $DIR/type-check-2.rs:46:31 | LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:60:28: 60:38]` for inline assembly - --> $DIR/type-check-2.rs:60:28 +error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly + --> $DIR/type-check-2.rs:58:28 | LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec` for inline assembly - --> $DIR/type-check-2.rs:62:28 + --> $DIR/type-check-2.rs:60:28 | LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ @@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]); = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:64:28 + --> $DIR/type-check-2.rs:62:28 | LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3)); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:66:28 + --> $DIR/type-check-2.rs:64:28 | LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:74:31 + --> $DIR/type-check-2.rs:72:31 | LL | asm!("{}", inout(reg) f); | ^ @@ -48,24 +48,28 @@ LL | asm!("{}", inout(reg) f); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:77:31 + --> $DIR/type-check-2.rs:75:31 | LL | asm!("{}", inout(reg) r); | ^ | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:41:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:41:20 | LL | asm!("{}", sym C); - | ^ + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:43:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:92:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` | -LL | asm!("{}", sym x); - | ^ + = help: `sym` operands must refer to either a function or a static error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/type-check-2.rs:19:28 diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs index 695fd27efd4e3..9f0121e11b447 100644 --- a/src/test/ui/asm/type-check-1.rs +++ b/src/test/ui/asm/type-check-1.rs @@ -3,7 +3,7 @@ // ignore-spirv // ignore-wasm32 -#![feature(asm_const)] +#![feature(asm_const, asm_sym)] use std::arch::{asm, global_asm}; @@ -44,6 +44,8 @@ fn main() { asm!("{}", const const_bar(0)); asm!("{}", const const_bar(x)); //~^ ERROR attempt to use a non-constant value in a constant + asm!("{}", sym x); + //~^ ERROR invalid `sym` operand // Const operands must be integers and must be constants. @@ -59,6 +61,11 @@ fn main() { } } +unsafe fn generic() { + asm!("{}", sym generic::); + //~^ generic parameters may not be used in const operations +} + // Const operands must be integers and must be constants. global_asm!("{}", const 0); diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index d774c78ca9a72..7dba69fb74592 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -25,14 +25,31 @@ LL | let x = 0; LL | asm!("{}", const const_bar(x)); | ^ non-constant value +error: invalid `sym` operand + --> $DIR/type-check-1.rs:47:24 + | +LL | asm!("{}", sym x); + | ^ is a local variable + | + = help: `sym` operands must refer to either a function or a static + +error: generic parameters may not be used in const operations + --> $DIR/type-check-1.rs:65:30 + | +LL | asm!("{}", sym generic::); + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + error[E0308]: mismatched types - --> $DIR/type-check-1.rs:53:26 + --> $DIR/type-check-1.rs:55:26 | LL | asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:55:26 + --> $DIR/type-check-1.rs:57:26 | LL | asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -41,7 +58,7 @@ LL | asm!("{}", const 0 as *mut u8); found raw pointer `*mut u8` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:57:26 + --> $DIR/type-check-1.rs:59:26 | LL | asm!("{}", const &0); | ^^ expected integer, found `&{integer}` @@ -92,13 +109,13 @@ LL | asm!("{}", inout(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0308]: mismatched types - --> $DIR/type-check-1.rs:67:25 + --> $DIR/type-check-1.rs:74:25 | LL | global_asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:69:25 + --> $DIR/type-check-1.rs:76:25 | LL | global_asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -106,7 +123,7 @@ LL | global_asm!("{}", const 0 as *mut u8); = note: expected type `{integer}` found raw pointer `*mut u8` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0277, E0308, E0435. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs index f0629f9f51cdf..9aeb6b2853fba 100644 --- a/src/test/ui/asm/x86_64/parse-error.rs +++ b/src/test/ui/asm/x86_64/parse-error.rs @@ -29,7 +29,7 @@ fn main() { asm!("{}", in(reg) foo => bar); //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` asm!("{}", sym foo + bar); - //~^ ERROR argument to `sym` must be a path expression + //~^ ERROR expected a path for argument to `sym` asm!("", options(foo)); //~^ ERROR expected one of asm!("", options(nomem foo)); diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr index 194cd66a66e96..1fd317a96a8a6 100644 --- a/src/test/ui/asm/x86_64/parse-error.stderr +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -58,7 +58,7 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` LL | asm!("{}", in(reg) foo => bar); | ^^ expected one of 7 possible tokens -error: argument to `sym` must be a path expression +error: expected a path for argument to `sym` --> $DIR/parse-error.rs:31:24 | LL | asm!("{}", sym foo + bar); @@ -362,17 +362,17 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` -error: expected one of `clobber_abi`, `const`, or `options`, found `""` +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` --> $DIR/parse-error.rs:130:28 | LL | global_asm!("", options(), ""); - | ^^ expected one of `clobber_abi`, `const`, or `options` + | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` -error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` --> $DIR/parse-error.rs:132:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); - | ^^^^ expected one of `clobber_abi`, `const`, or `options` + | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal --> $DIR/parse-error.rs:134:13 diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs index f95aebb78b5f8..eb87ea91085f0 100644 --- a/src/test/ui/asm/x86_64/type-check-2.rs +++ b/src/test/ui/asm/x86_64/type-check-2.rs @@ -2,7 +2,7 @@ #![feature(repr_simd, never_type, asm_sym)] -use std::arch::asm; +use std::arch::{asm, global_asm}; #[repr(simd)] struct SimdNonCopy(f32, f32, f32, f32); @@ -35,9 +35,7 @@ fn main() { asm!("{}", sym S); asm!("{}", sym main); asm!("{}", sym C); - //~^ ERROR asm `sym` operand must point to a fn or static - asm!("{}", sym x); - //~^ ERROR asm `sym` operand must point to a fn or static + //~^ ERROR invalid `sym` operand // Register operands must be Copy @@ -80,3 +78,12 @@ fn main() { asm!("{}", in(reg) u); } } + +// Sym operands must point to a function or static + +const C: i32 = 0; +static S: i32 = 0; +global_asm!("{}", sym S); +global_asm!("{}", sym main); +global_asm!("{}", sym C); +//~^ ERROR invalid `sym` operand diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr index cec750fdf9a55..cb3960acdf9d3 100644 --- a/src/test/ui/asm/x86_64/type-check-2.stderr +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -1,13 +1,13 @@ error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:44:32 + --> $DIR/type-check-2.rs:42:32 | LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:56:28: 56:38]` for inline assembly - --> $DIR/type-check-2.rs:56:28 +error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly + --> $DIR/type-check-2.rs:54:28 | LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec` for inline assembly - --> $DIR/type-check-2.rs:58:28 + --> $DIR/type-check-2.rs:56:28 | LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ @@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]); = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:60:28 + --> $DIR/type-check-2.rs:58:28 | LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3)); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:62:28 + --> $DIR/type-check-2.rs:60:28 | LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:70:31 + --> $DIR/type-check-2.rs:68:31 | LL | asm!("{}", inout(reg) f); | ^ @@ -48,24 +48,28 @@ LL | asm!("{}", inout(reg) f); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:73:31 + --> $DIR/type-check-2.rs:71:31 | LL | asm!("{}", inout(reg) r); | ^ | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:37:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:37:20 | LL | asm!("{}", sym C); - | ^ + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:39:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:88:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` | -LL | asm!("{}", sym x); - | ^ + = help: `sym` operands must refer to either a function or a static error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/type-check-2.rs:15:28 From d5440926e2832f810cadeccff6e2ca5332e11466 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 7 Apr 2022 22:46:53 +0400 Subject: [PATCH 05/11] Suggest replacing typeof(...) with an actual type This commit suggests replacing typeof(...) with an actual type of "...", for example in case of `typeof(1)` we suggest replacing it with `i32`. If the expression - Is not const (`{ let a = 1; let _: typeof(a); }`) - Can't be found (`let _: typeof(this_variable_does_not_exist)`) - Or has non-suggestable type (closure, generator, error, etc) we don't suggest anything. --- .../locales/en-US/diagnostics.ftl | 1 + compiler/rustc_typeck/src/astconv/mod.rs | 12 ++++++++++-- compiler/rustc_typeck/src/errors.rs | 7 ++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl index 336e7a6685708..2b1deb3430456 100644 --- a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl +++ b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl @@ -62,6 +62,7 @@ typeck-functional-record-update-on-non-struct = typeck-typeof-reserved-keyword-used = `typeof` is a reserved keyword but unimplemented + .suggestion = consider replacing `typeof(...)` with an actual type .label = reserved keyword typeck-return-stmt-outside-of-fn-body = diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index b6287031665a3..42379055fffd0 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2462,8 +2462,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { - tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); - tcx.type_of(tcx.hir().local_def_id(e.hir_id)) + let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let span = ast_ty.span; + tcx.sess.emit_err(TypeofReservedKeywordUsed { + span, + ty, + opt_sugg: Some((span, Applicability::MachineApplicable)) + .filter(|_| ty.is_suggestable()), + }); + + ty } hir::TyKind::Infer => { // Infer also appears as the type of arguments or return diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 0b78aea9f05bd..1088be5f56657 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,5 +1,7 @@ //! Errors emitted by typeck. +use rustc_errors::Applicability; use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] @@ -127,10 +129,13 @@ pub struct FunctionalRecordUpdateOnNonStruct { #[derive(SessionDiagnostic)] #[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")] -pub struct TypeofReservedKeywordUsed { +pub struct TypeofReservedKeywordUsed<'tcx> { + pub ty: Ty<'tcx>, #[primary_span] #[label] pub span: Span, + #[suggestion_verbose(message = "suggestion", code = "{ty}")] + pub opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] From 71fea61bc9f387d99dd99b1f99d35e1a92f578a7 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <41065217+TaKO8Ki@users.noreply.github.com> Date: Fri, 8 Apr 2022 23:17:57 +0900 Subject: [PATCH 06/11] suggest adding a local for vector to fix borrowck errors --- .../src/diagnostics/conflict_errors.rs | 40 ++++++++++++++----- .../borrowck/suggest-local-var-for-vector.rs | 4 ++ .../suggest-local-var-for-vector.stderr | 24 +++++++++++ .../suggest-storing-local-var-for-vector.rs | 4 ++ ...uggest-storing-local-var-for-vector.stderr | 24 +++++++++++ .../two-phase-nonrecv-autoref.nll.stderr | 22 ++++++++++ 6 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/borrowck/suggest-local-var-for-vector.rs create mode 100644 src/test/ui/borrowck/suggest-local-var-for-vector.stderr create mode 100644 src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs create mode 100644 src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b945d687043b4..9e5fb674772d5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -785,13 +785,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { issued_borrow: &BorrowData<'tcx>, explanation: BorrowExplanation, ) { - let used_in_call = - matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + let used_in_call = matches!( + explanation, + BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + ); if !used_in_call { debug!("not later used in call"); return; } + let use_span = + if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { + Some(use_span) + } else { + None + }; + let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { loc @@ -835,7 +844,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); let inner_call_span = inner_call_term.source_info.span; - let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + let outer_call_span = match use_span { + Some(span) => span, + None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span, + }; if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { // FIXME: This stops the suggestion in some cases where it should be emitted. // Fix the spans for those cases so it's emitted correctly. @@ -845,8 +857,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); return; } - err.span_help(inner_call_span, "try adding a local storing this argument..."); - err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + err.span_help( + inner_call_span, + &format!( + "try adding a local storing this{}...", + if use_span.is_some() { "" } else { " argument" } + ), + ); + err.span_help( + outer_call_span, + &format!( + "...and then using that local {}", + if use_span.is_some() { "here" } else { "as the argument to this call" } + ), + ); } fn suggest_split_at_mut_if_applicable( @@ -1912,10 +1936,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { "cannot assign twice to immutable variable" }; - if span != assigned_span { - if !from_arg { - err.span_label(assigned_span, format!("first assignment to {}", place_description)); - } + if span != assigned_span && !from_arg { + err.span_label(assigned_span, format!("first assignment to {}", place_description)); } if let Some(decl) = local_decl && let Some(name) = local_name diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-local-var-for-vector.rs new file mode 100644 index 0000000000000..40f013f6a78a7 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr new file mode 100644 index 0000000000000..615fffcd578ad --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs new file mode 100644 index 0000000000000..40f013f6a78a7 --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr new file mode 100644 index 0000000000000..e3a16eddfd5ec --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-storing-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index 50d277a12f74f..0f2daaf99d914 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -54,6 +54,17 @@ LL | i[i[3]] = 4; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + | +LL | i[i[3]] = 4; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:138:5 + | +LL | i[i[3]] = 4; + | ^^^^^^^ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable --> $DIR/two-phase-nonrecv-autoref.rs:143:7 @@ -64,6 +75,17 @@ LL | i[i[3]] = i[4]; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:143:7 + | +LL | i[i[3]] = i[4]; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:143:5 + | +LL | i[i[3]] = i[4]; + | ^^^^^^^ error: aborting due to 7 previous errors From ca9ef27ed156d599f6feac0c772cc29d960526ee Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 9 Apr 2022 08:10:34 -0700 Subject: [PATCH 07/11] Check for git submodules in non-git source tree. --- src/bootstrap/bootstrap.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 0b6bdf474195d..00dc7da275a43 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1097,8 +1097,19 @@ def update_submodule(self, module, checked_out, recorded_submodules): def update_submodules(self): """Update submodules""" - if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \ - self.get_toml('submodules') == "false": + has_git = os.path.exists(os.path.join(self.rust_root, ".git")) + # This just arbitrarily checks for cargo, but any workspace member in + # a submodule would work. + has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml")) + if not has_git and not has_submodules: + print("This is not a git repository, and the requisite git submodules were not found.") + print("If you downloaded the source from https://github.com/rust-lang/rust/releases,") + print("those sources will not work. Instead, consider downloading from the source") + print("releases linked at") + print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code") + print("or clone the repository at https://github.com/rust-lang/rust/.") + raise SystemExit(1) + if not has_git or self.get_toml('submodules') == "false": return default_encoding = sys.getdefaultencoding() From 1834c21f88cac45c3b4b8c1c50855b06668516a5 Mon Sep 17 00:00:00 2001 From: niluxv Date: Sat, 9 Apr 2022 17:39:07 +0200 Subject: [PATCH 08/11] Fix missing space in lossy provenance cast lint --- compiler/rustc_typeck/src/check/cast.rs | 2 +- src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 6091b8fee00b6..e73b9c979eb1a 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -1012,7 +1012,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.help(msg); } err.help( - "if you can't comply with strict provenance and need to expose the pointer\ + "if you can't comply with strict provenance and need to expose the pointer \ provenance you can use `.expose_addr()` instead" ); diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr index 489cb03ddd316..e7a6c1837bd56 100644 --- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(lossy_provenance_casts)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22 @@ -17,7 +17,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons LL | let addr_32bit = &x as *const u8 as u32; | ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32` | - = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead error: aborting due to 2 previous errors From cc57656969554bd0dcbf95641bebadc076fac61f Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 9 Apr 2022 20:38:06 +0300 Subject: [PATCH 09/11] support multiple derefs --- .../src/deref_separator.rs | 39 ++++--- .../derefer_test_multiple.main.Derefer.diff | 100 ++++++++++++++++++ src/test/mir-opt/derefer_test_multiple.rs | 9 ++ 3 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 src/test/mir-opt/derefer_test_multiple.main.Derefer.diff create mode 100644 src/test/mir-opt/derefer_test_multiple.rs diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 79aac16355061..d8660d4f2fd86 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -11,6 +11,8 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { for (i, stmt) in data.statements.iter_mut().enumerate() { match stmt.kind { StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => { + let mut place_local = place.local; + let mut last_len = 0; for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() { // The type that we are derefing. @@ -23,14 +25,30 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { patch.add_statement(loc, StatementKind::StorageLive(temp)); // We are adding current p_ref's projections to our - // temp value. - let deref_place = - Place::from(p_ref.local).project_deeper(p_ref.projection, tcx); - patch.add_assign( - loc, - Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), - ); + // temp value, excluding projections we already covered. + if idx == 1 { + let deref_place = Place::from(place_local) + .project_deeper(&p_ref.projection[last_len..], tcx); + patch.add_assign( + loc, + Place::from(temp), + Rvalue::Use(Operand::Move(deref_place)), + ); + + place_local = temp; + last_len = p_ref.projection.len(); + } else { + let deref_place = Place::from(place_local) + .project_deeper(&p_ref.projection[last_len..], tcx); + patch.add_assign( + loc, + Place::from(temp), + Rvalue::Use(Operand::Move(deref_place)), + ); + + place_local = temp; + last_len = p_ref.projection.len(); + } // We are creating a place by using our temp value's location // and copying derefed values which we need to create new statement. @@ -50,11 +68,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Since our job with the temp is done it should be gone let loc = Location { block: block, statement_index: i + 1 }; patch.add_statement(loc, StatementKind::StorageDead(temp)); - - // As all projections are off the base projection, if there are - // multiple derefs in the middle of projection, it might cause - // unsoundness, to not let that happen we break the loop. - break; } } } diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff new file mode 100644 index 0000000000000..d465724326e46 --- /dev/null +++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff @@ -0,0 +1,100 @@ +- // MIR for `main` before Derefer ++ // MIR for `main` after Derefer + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/derefer_test_multiple.rs:2:12: 2:12 + let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28 ++ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + scope 1 { + debug a => _1; // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + scope 2 { + debug b => _2; // in scope 2 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + scope 3 { + debug c => _4; // in scope 3 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + scope 4 { + debug d => _6; // in scope 4 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + let _8: &mut i32; // in scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 + scope 5 { + debug x => _8; // in scope 5 at $DIR/derefer_test_multiple.rs:7:9: 7:10 + let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + scope 6 { + debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + (_1.0: i32) = const 42_i32; // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25 + (_1.1: i32) = const 43_i32; // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25 + StorageLive(_2); // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + StorageLive(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + _3 = &mut _1; // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + (_2.0: i32) = const 99_i32; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29 + (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29 + StorageDead(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29 + StorageLive(_4); // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + StorageLive(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + _5 = &mut _2; // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + (_4.0: i32) = const 11_i32; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29 + (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29 + StorageDead(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29 + StorageLive(_6); // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + StorageLive(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + _7 = &mut _4; // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + (_6.0: i32) = const 13_i32; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29 + (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29 + StorageDead(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29 + StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 +- _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageDead(_10); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 ++ StorageDead(_11); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 ++ StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 +- _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageDead(_13); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 ++ StorageDead(_14); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 ++ StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + _0 = const (); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + StorageDead(_9); // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_8); // scope 4 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_6); // scope 3 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_4); // scope 2 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + return; // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 + } + } + diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs new file mode 100644 index 0000000000000..a27363447fee5 --- /dev/null +++ b/src/test/mir-opt/derefer_test_multiple.rs @@ -0,0 +1,9 @@ +// EMIT_MIR derefer_test_multiple.main.Derefer.diff +fn main () { + let mut a = (42, 43); + let mut b = (99, &mut a); + let mut c = (11, &mut b); + let mut d = (13, &mut c); + let x = &mut (*d.1).1.1.1; + let y = &mut (*d.1).1.1.1; +} From 80afd9db2e3871387ecab9c2bdeffc0f970d32d3 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 9 Apr 2022 22:23:49 +0300 Subject: [PATCH 10/11] remove the if block --- .../src/deref_separator.rs | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index d8660d4f2fd86..24b626ad96658 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -26,29 +26,16 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // We are adding current p_ref's projections to our // temp value, excluding projections we already covered. - if idx == 1 { - let deref_place = Place::from(place_local) - .project_deeper(&p_ref.projection[last_len..], tcx); - patch.add_assign( - loc, - Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), - ); + let deref_place = Place::from(place_local) + .project_deeper(&p_ref.projection[last_len..], tcx); + patch.add_assign( + loc, + Place::from(temp), + Rvalue::Use(Operand::Move(deref_place)), + ); - place_local = temp; - last_len = p_ref.projection.len(); - } else { - let deref_place = Place::from(place_local) - .project_deeper(&p_ref.projection[last_len..], tcx); - patch.add_assign( - loc, - Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), - ); - - place_local = temp; - last_len = p_ref.projection.len(); - } + place_local = temp; + last_len = p_ref.projection.len(); // We are creating a place by using our temp value's location // and copying derefed values which we need to create new statement. From 8412d5dc5c4f284390f89d0352adae56dbc650e9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 10 Apr 2022 16:45:09 +0400 Subject: [PATCH 11/11] --bless tests --- src/test/ui/error-codes/E0516.stderr | 5 +++++ src/test/ui/issues/issue-29184.stderr | 5 +++++ src/test/ui/typeof/type_mismatch.stderr | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/test/ui/error-codes/E0516.stderr b/src/test/ui/error-codes/E0516.stderr index 2e6de5053d576..5243b7caf225b 100644 --- a/src/test/ui/error-codes/E0516.stderr +++ b/src/test/ui/error-codes/E0516.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let x: i32 = 92; + | ~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29184.stderr b/src/test/ui/issues/issue-29184.stderr index 87d3632ee42e2..75b6c64f2ced3 100644 --- a/src/test/ui/issues/issue-29184.stderr +++ b/src/test/ui/issues/issue-29184.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let x: i32 = 92; + | ~~~ error: aborting due to previous error diff --git a/src/test/ui/typeof/type_mismatch.stderr b/src/test/ui/typeof/type_mismatch.stderr index e82b5e4497383..e75214cd31a6d 100644 --- a/src/test/ui/typeof/type_mismatch.stderr +++ b/src/test/ui/typeof/type_mismatch.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let b: typeof(a) = 1i8; | ^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let b: u8 = 1i8; + | ~~ error[E0308]: mismatched types --> $DIR/type_mismatch.rs:5:24