#### MSVC
[windows-msvc]: #windows-msvc
-MSVC builds of Rust additionally require an installation of Visual Studio 2013
-(or later) so `rustc` can use its linker. Make sure to check the “C++ tools”
-option.
+MSVC builds of Rust additionally require an installation of Visual Studio 2017
+(or later) so `rustc` can use its linker. The simplest way is to get the
+[Visual Studio Build Tools] and check the “C++ build tools” workload.
+
+[Visual Studio Build Tools]: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019
+
+At last check (cmake 3.14.3 and msvc 16.0.3) using the 2019 tools fails to
+build the in-tree LLVM build with a CMake error, so use 2017 instead by
+including the “MSVC v141 – VS 2017 C++ x64/x86 build tools (v14.16)” component.
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
fn configure_cmake(builder: &Builder<'_>,
target: Interned<String>,
cfg: &mut cmake::Config) {
+ // Do not print installation messages for up-to-date files.
+ // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
+ cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
+
if builder.config.ninja {
cfg.generator("Ninja");
}
## `-L`: add a directory to the library search path
-When looking for external crates, a directory passed to this flag will be searched.
+When looking for external crates or libraries, a directory passed to this flag
+will be searched.
+
+The kind of search path can optionally be specified with the form `-L
+KIND=PATH` where `KIND` may be one of:
+
+- `dependency` — Only search for transitive dependencies in this directory.
+- `crate` — Only search for this crate's direct dependencies in this
+ directory.
+- `native` — Only search for native libraries in this directory.
+- `framework` — Only search for macOS frameworks in this directory.
+- `all` — Search for all library kinds in this directory. This is the default
+ if `KIND` is not specified.
## `-l`: link the generated crate to a native library
This flag allows you to specify linking to a specific native library when building
a crate.
+The kind of library can optionally be specified with the form `-l KIND=lib`
+where `KIND` may be one of:
+
+- `dylib` — A native dynamic library.
+- `static` — A native static library (such as a `.a` archive).
+- `framework` — A macOS framework.
+
+The kind of library can be specified in a [`#[link]`
+attribute][link-attribute]. If the kind is not specified in the `link`
+attribute or on the command-line, it will link a dynamic library if available,
+otherwise it will use a static library. If the kind is specified on the
+command-line, it will override the kind specified in a `link` attribute.
+
+The name used in a `link` attribute may be overridden using the form `-l
+ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute,
+and `LINK_NAME` is the name of the actual library that will be linked.
+
+[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute
+
## `--crate-type`: a list of types of crates for the compiler to emit
-This instructs `rustc` on which crate type to build.
+This instructs `rustc` on which crate type to build. This flag accepts a
+comma-separated list of values, and may be specified multiple times. The valid
+crate types are:
+
+- `lib` — Generates a library kind preferred by the compiler, currently
+ defaults to `rlib`.
+- `rlib` — A Rust static library.
+- `staticlib` — A native static library.
+- `dylib` — A Rust dynamic library.
+- `cdylib` — A native dynamic library.
+- `bin` — A runnable executable program.
+- `proc-macro` — Generates a format suitable for a procedural macro library
+ that may be loaded by the compiler.
+
+The crate type may be specified with the [`crate_type` attribute][crate_type].
+The `--crate-type` command-line value will override the `crate_type`
+attribute.
+
+More details may be found in the [linkage chapter] of the reference.
+
+[linkage chapter]: ../reference/linkage.html
+[crate_type]: ../reference/linkage.html
## `--crate-name`: specify the name of the crate being built
This informs `rustc` of the name of your crate.
-## `--emit`: emit output other than a crate
-
-Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR.
+## `--edition`: specify the edition to use
+
+This flag takes a value of `2015` or `2018`. The default is `2015`. More
+information about editions may be found in the [edition guide].
+
+[edition guide]: ../edition-guide/introduction.html
+
+## `--emit`: specifies the types of output files to generate
+
+This flag controls the types of output files generated by the compiler. It
+accepts a comma-separated list of values, and may be specified multiple times.
+The valid emit kinds are:
+
+- `asm` — Generates a file with the crate's assembly code. The default output
+ filename is `CRATE_NAME.s`.
+- `dep-info` — Generates a file with Makefile syntax that indicates all the
+ source files that were loaded to generate the crate. The default output
+ filename is `CRATE_NAME.d`.
+- `link` — Generates the crates specified by `--crate-type`. The default
+ output filenames depend on the crate type and platform. This is the default
+ if `--emit` is not specified.
+- `llvm-bc` — Generates a binary file containing the [LLVM bitcode]. The
+ default output filename is `CRATE_NAME.bc`.
+- `llvm-ir` — Generates a file containing [LLVM IR]. The default output
+ filename is `CRATE_NAME.ll`.
+- `metadata` — Generates a file containing metadata about the crate. The
+ default output filename is `CRATE_NAME.rmeta`.
+- `mir` — Generates a file containing rustc's mid-level intermediate
+ representation. The default output filename is `CRATE_NAME.mir`.
+- `obj` — Generates a native object file. The default output filename is
+ `CRATE_NAME.o`.
+
+The output filename can be set with the `-o` flag. A suffix may be added to
+the filename with the `-C extra-filename` flag. The files are written to the
+current directory unless the `--out-dir` flag is used. Each emission type may
+also specify the output filename with the form `KIND=PATH`, which takes
+precedence over the `-o` flag.
+
+[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
+[LLVM IR]: https://llvm.org/docs/LangRef.html
## `--print`: print compiler information
-This flag prints out various information about the compiler.
+This flag prints out various information about the compiler. This flag may be
+specified multiple times, and the information is printed in the order the
+flags are specified. Specifying a `--print` flag will usually disable the
+`--emit` step and will only print the requested information. The valid types
+of print values are:
+
+- `crate-name` — The name of the crate.
+- `file-names` — The names of the files created by the `link` emit kind.
+- `sysroot` — Path to the sysroot.
+- `cfg` — List of cfg values. See [conditional compilation] for more
+ information about cfg values.
+- `target-list` — List of known targets. The target may be selected with the
+ `--target` flag.
+- `target-cpus` — List of available CPU values for the current target. The
+ target CPU may be selected with the `-C target-cpu=val` flag.
+- `target-features` — List of available target features for the current
+ target. Target features may be enabled with the `-C target-feature=val`
+ flag.
+- `relocation-models` — List of relocation models. Relocation models may be
+ selected with the `-C relocation-model=val` flag.
+- `code-models` — List of code models. Code models may be selected with the
+ `-C code-model=val` flag.
+- `tls-models` — List of Thread Local Storage models supported. The model may
+ be selected with the `-Z tls-model=val` flag.
+- `native-static-libs` — This may be used when creating a `staticlib` crate
+ type. If this is the only flag, it will perform a full compilation and
+ include a diagnostic note that indicates the linker flags to use when
+ linking the resulting static library. The note starts with the text
+ `native-static-libs:` to make it easier to fetch the output.
+
+[conditional compilation]: ../reference/conditional-compilation.html
## `-g`: include debug information
## `--out-dir`: directory to write the output in
-The outputted crate will be written to this directory.
+The outputted crate will be written to this directory. This flag is ignored if
+the `-o` flag is used.
## `--explain`: provide a detailed explanation of an error message
## `--extern`: specify where an external library is located
-This flag allows you to pass the name and location of an external crate that will
-be linked into the crate you're buildling.
+This flag allows you to pass the name and location of an external crate that
+will be linked into the crate you are building. This flag may be specified
+multiple times. The format of the value should be `CRATENAME=PATH`.
## `--sysroot`: Override the system root
## `--error-format`: control how errors are produced
-This flag lets you control the format of errors.
+This flag lets you control the format of messages. Messages are printed to
+stderr. The valid options are:
+
+- `human` — Human-readable output. This is the default.
+- `json` — Structured JSON output.
+- `short` — Short, one-line messages.
## `--color`: configure coloring of output
-This flag lets you control color settings of the output.
+This flag lets you control color settings of the output. The valid options
+are:
+
+- `auto` — Use colors if output goes to a tty. This is the default.
+- `always` — Always use colors.
+- `never` — Never colorize output.
+
+## `--remap-path-prefix`: remap source names in output
+
+Remap source path prefixes in all output, including compiler diagnostics,
+debug information, macro expansions, etc. It takes a value of the form
+`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`.
+The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This
+flag may be specified multiple times.
+
+This is useful for normalizing build products, for example by removing the
+current directory out of pathnames emitted into the object files. The
+replacement is purely textual, with no consideration of the current system's
+pathname syntax. For example `--remap-path-prefix foo=bar` will match
+`foo/lib.rs` but not `./foo/lib.rs`.
}
}
+#[stable(feature = "from_ref_string", since = "1.35.0")]
+impl From<&String> for String {
+ #[inline]
+ fn from(s: &String) -> String {
+ s.clone()
+ }
+}
+
// note: test pulls in libstd, which causes errors here
#[cfg(not(test))]
#[stable(feature = "string_from_box", since = "1.18.0")]
/// If you need to do a costly conversion it is better to implement [`From`] with type
/// `&T` or write a custom function.
///
-///
/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects:
///
/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either
/// converted a the specified type `T`.
///
/// For example: By creating a generic function that takes an `AsRef<str>` we express that we
-/// want to accept all references that can be converted to &str as an argument.
+/// want to accept all references that can be converted to `&str` as an argument.
/// Since both [`String`] and `&str` implement `AsRef<str>` we can accept both as input argument.
///
/// [`String`]: ../../std/string/struct.String.html
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
-///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Performs the conversion.
/// write a function `add_one`that takes all arguments that can be converted to `&mut u64`.
/// Because [`Box<T>`] implements `AsMut<T>` `add_one` accepts arguments of type
/// `&mut Box<u64>` as well:
+///
/// ```
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
/// *num.as_mut() += 1;
/// add_one(&mut boxed_num);
/// assert_eq!(*boxed_num, 1);
/// ```
-/// [`Box<T>`]: ../../std/boxed/struct.Box.html
///
+/// [`Box<T>`]: ../../std/boxed/struct.Box.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
/// Performs the conversion.
/// A value-to-value conversion that consumes the input value. The
/// opposite of [`From`].
///
-/// One should only implement [`Into`] if a conversion to a type outside the current crate is
-/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because
-/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to
+/// One should only implement `Into` if a conversion to a type outside the current crate is
+/// required. Otherwise one should always prefer implementing [`From`] over `Into` because
+/// implementing [`From`] automatically provides one with a implementation of `Into` thanks to
/// the blanket implementation in the standard library. [`From`] cannot do these type of
/// conversions because of Rust's orphaning rules.
///
///
/// # Generic Implementations
///
-/// - [`From<T>`]` for U` implies `Into<U> for T`
-/// - [`Into`]` is reflexive, which means that `Into<T> for T` is implemented
+/// - [`From`]`<T> for U` implies `Into<U> for T`
+/// - `Into` is reflexive, which means that `Into<T> for T` is implemented
///
/// # Implementing `Into` for conversions to external types
///
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
-/// [From]: trait.From.html
+/// [`From`]: trait.From.html
/// [`into`]: trait.Into.html#tymethod.into
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of
/// [`Into`].
///
-/// One should always prefer implementing [`From`] over [`Into`]
-/// because implementing [`From`] automatically provides one with a implementation of [`Into`]
+/// One should always prefer implementing `From` over [`Into`]
+/// because implementing `From` automatically provides one with a implementation of [`Into`]
/// thanks to the blanket implementation in the standard library.
///
/// Only implement [`Into`] if a conversion to a type outside the current crate is required.
-/// [`From`] cannot do these type of conversions because of Rust's orphaning rules.
+/// `From` cannot do these type of conversions because of Rust's orphaning rules.
/// See [`Into`] for more details.
///
-/// Prefer using [`Into`] over using [`From`] when specifying trait bounds on a generic function.
+/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function.
/// This way, types that directly implement [`Into`] can be used as arguments as well.
///
-/// The [`From`] is also very useful when performing error handling. When constructing a function
+/// The `From` is also very useful when performing error handling. When constructing a function
/// that is capable of failing, the return type will generally be of the form `Result<T, E>`.
/// The `From` trait simplifies error handling by allowing a function to return a single error type
/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
///
/// # Generic Implementations
///
-/// - [`From<T>`]` for U` implies [`Into<U>`]` for T`
-/// - [`From`] is reflexive, which means that `From<T> for T` is implemented
+/// - `From<T> for U` implies [`Into`]`<U> for T`
+/// - `From` is reflexive, which means that `From<T> for T` is implemented
///
/// # Examples
///
/// [`String`] implements `From<&str>`:
///
-/// An explicit conversion from a &str to a String is done as follows:
+/// An explicit conversion from a `&str` to a String is done as follows:
+///
/// ```
/// let string = "hello".to_string();
/// let other_string = String::from("hello");
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
-/// [`Into<U>`]: trait.Into.html
+/// [`Into`]: trait.Into.html
/// [`from`]: trait.From.html#tymethod.from
/// [book]: ../../book/ch09-00-error-handling.html
#[stable(feature = "rust1", since = "1.0.0")]
///
/// # Generic Implementations
///
-/// - `TryFrom<T> for U` implies [`TryInto<U>`]` for T`
+/// - `TryFrom<T> for U` implies [`TryInto`]`<U> for T`
/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
/// is implemented and cannot fail -- the associated `Error` type for
/// calling `T::try_from()` on a value of type `T` is `Infallible`.
opt::multi_s(
"",
"print",
- "Comma separated list of compiler information to \
- print on stdout",
+ "Compiler information to print on stdout",
"[crate-name|file-names|sysroot|cfg|target-list|\
target-cpus|target-features|relocation-models|\
code-models|tls-models|target-spec-json|native-static-libs]",
StableHasherResult};
pub use rustc_target::abi::*;
+use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
+use rustc_target::abi::call::{
+ ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind
+};
+
+
pub trait IntegerExt {
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>;
}
}
}
+
+pub trait FnTypeExt<'tcx, C>
+where
+ C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+ + HasDataLayout
+ + HasTargetSpec
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+{
+ fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self;
+ fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+ fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+ fn new_internal(
+ cx: &C,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+ ) -> Self;
+ fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
+}
+
+impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>>
+where
+ C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+ + HasDataLayout
+ + HasTargetSpec
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+{
+ fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self {
+ let sig = instance.fn_sig(cx.tcx());
+ let sig = cx
+ .tcx()
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+ call::FnType::new(cx, sig, &[])
+ }
+
+ fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+ call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty)))
+ }
+
+ fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+ FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+ let mut layout = cx.layout_of(ty);
+ // Don't pass the vtable, it's not an argument of the virtual fn.
+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+ if arg_idx == Some(0) {
+ let fat_pointer_ty = if layout.is_unsized() {
+ // unsized `self` is passed as a pointer to `self`
+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+ cx.tcx().mk_mut_ptr(layout.ty)
+ } else {
+ match layout.abi {
+ Abi::ScalarPair(..) => (),
+ _ => bug!("receiver type has unsupported layout: {:?}", layout),
+ }
+
+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+ // elsewhere in the compiler as a method on a `dyn Trait`.
+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+ // get a built-in pointer type
+ let mut fat_pointer_layout = layout;
+ 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+ && !fat_pointer_layout.ty.is_region_ptr()
+ {
+ 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+ let field_layout = fat_pointer_layout.field(cx, i);
+
+ if !field_layout.is_zst() {
+ fat_pointer_layout = field_layout;
+ continue 'descend_newtypes;
+ }
+ }
+
+ bug!(
+ "receiver has no non-zero-sized fields {:?}",
+ fat_pointer_layout
+ );
+ }
+
+ fat_pointer_layout.ty
+ };
+
+ // we now have a type like `*mut RcBox<dyn Trait>`
+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+ // this is understood as a special case elsewhere in the compiler
+ let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+ layout = cx.layout_of(unit_pointer_ty);
+ layout.ty = fat_pointer_ty;
+ }
+ ArgType::new(layout)
+ })
+ }
+
+ fn new_internal(
+ cx: &C,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+ ) -> Self {
+ debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
+
+ use rustc_target::spec::abi::Abi::*;
+ let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C,
+
+ // It's the ABI's job to select this, not ours.
+ System => bug!("system abi should be selected elsewhere"),
+
+ Stdcall => Conv::X86Stdcall,
+ Fastcall => Conv::X86Fastcall,
+ Vectorcall => Conv::X86VectorCall,
+ Thiscall => Conv::X86ThisCall,
+ C => Conv::C,
+ Unadjusted => Conv::C,
+ Win64 => Conv::X86_64Win64,
+ SysV64 => Conv::X86_64SysV,
+ Aapcs => Conv::ArmAapcs,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+
+ // These API constants ought to be more specific...
+ Cdecl => Conv::C,
+ };
+
+ let mut inputs = sig.inputs();
+ let extra_args = if sig.abi == RustCall {
+ assert!(!sig.c_variadic && extra_args.is_empty());
+
+ match sig.inputs().last().unwrap().sty {
+ ty::Tuple(tupled_arguments) => {
+ inputs = &sig.inputs()[0..sig.inputs().len() - 1];
+ tupled_arguments.iter().map(|k| k.expect_ty()).collect()
+ }
+ _ => {
+ bug!(
+ "argument to function with \"rust-call\" ABI \
+ is not a tuple"
+ );
+ }
+ }
+ } else {
+ assert!(sig.c_variadic || extra_args.is_empty());
+ extra_args.to_vec()
+ };
+
+ let target = &cx.tcx().sess.target.target;
+ let win_x64_gnu =
+ target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
+ let linux_s390x =
+ target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu";
+ let linux_sparc64 =
+ target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu";
+ let rust_abi = match sig.abi {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
+ _ => false,
+ };
+
+ // Handle safe Rust thin and fat pointers.
+ let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
+ scalar: &Scalar,
+ layout: TyLayout<'tcx>,
+ offset: Size,
+ is_return: bool| {
+ // Booleans are always an i1 that needs to be zero-extended.
+ if scalar.is_bool() {
+ attrs.set(ArgAttribute::ZExt);
+ return;
+ }
+
+ // Only pointer types handled below.
+ if scalar.value != Pointer {
+ return;
+ }
+
+ if scalar.valid_range.start() < scalar.valid_range.end() {
+ if *scalar.valid_range.start() > 0 {
+ attrs.set(ArgAttribute::NonNull);
+ }
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+ if let Some(kind) = pointee.safe {
+ attrs.pointee_size = pointee.size;
+ attrs.pointee_align = Some(pointee.align);
+
+ // `Box` pointer parameters never alias because ownership is transferred
+ // `&mut` pointer parameters never alias other parameters,
+ // or mutable global data
+ //
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+ // and can be marked as both `readonly` and `noalias`, as
+ // LLVM's definition of `noalias` is based solely on memory
+ // dependencies rather than pointer equality
+ let no_alias = match kind {
+ PointerKind::Shared => false,
+ PointerKind::UniqueOwned => true,
+ PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return,
+ };
+ if no_alias {
+ attrs.set(ArgAttribute::NoAlias);
+ }
+
+ if kind == PointerKind::Frozen && !is_return {
+ attrs.set(ArgAttribute::ReadOnly);
+ }
+ }
+ }
+ };
+
+ // Store the index of the last argument. This is useful for working with
+ // C-compatible variadic arguments.
+ let last_arg_idx = if sig.inputs().is_empty() {
+ None
+ } else {
+ Some(sig.inputs().len() - 1)
+ };
+
+ let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+ let is_return = arg_idx.is_none();
+ let mut arg = mk_arg_type(ty, arg_idx);
+ if arg.layout.is_zst() {
+ // For some forsaken reason, x86_64-pc-windows-gnu
+ // doesn't ignore zero-sized struct arguments.
+ // The same is true for s390x-unknown-linux-gnu
+ // and sparc64-unknown-linux-gnu.
+ if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
+ arg.mode = PassMode::Ignore(IgnoreMode::Zst);
+ }
+ }
+
+ // If this is a C-variadic function, this is not the return value,
+ // and there is one or more fixed arguments; ensure that the `VaList`
+ // is ignored as an argument.
+ if sig.c_variadic {
+ match (last_arg_idx, arg_idx) {
+ (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
+ let va_list_did = match cx.tcx().lang_items().va_list() {
+ Some(did) => did,
+ None => bug!("`va_list` lang item required for C-variadic functions"),
+ };
+ match ty.sty {
+ ty::Adt(def, _) if def.did == va_list_did => {
+ // This is the "spoofed" `VaList`. Set the arguments mode
+ // so that it will be ignored.
+ arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
+ }
+ _ => (),
+ }
+ }
+ _ => {}
+ }
+ }
+
+ // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
+ if !is_return && rust_abi {
+ if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
+ let mut a_attrs = ArgAttributes::new();
+ let mut b_attrs = ArgAttributes::new();
+ adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
+ adjust_for_rust_scalar(
+ &mut b_attrs,
+ b,
+ arg.layout,
+ a.value.size(cx).align_to(b.value.align(cx).abi),
+ false,
+ );
+ arg.mode = PassMode::Pair(a_attrs, b_attrs);
+ return arg;
+ }
+ }
+
+ if let Abi::Scalar(ref scalar) = arg.layout.abi {
+ if let PassMode::Direct(ref mut attrs) = arg.mode {
+ adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
+ }
+ }
+
+ arg
+ };
+
+ let mut fn_ty = FnType {
+ ret: arg_of(sig.output(), None),
+ args: inputs
+ .iter()
+ .cloned()
+ .chain(extra_args)
+ .enumerate()
+ .map(|(i, ty)| arg_of(ty, Some(i)))
+ .collect(),
+ c_variadic: sig.c_variadic,
+ conv,
+ };
+ fn_ty.adjust_for_abi(cx, sig.abi);
+ fn_ty
+ }
+
+ fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+ if abi == SpecAbi::Unadjusted {
+ return;
+ }
+
+ if abi == SpecAbi::Rust
+ || abi == SpecAbi::RustCall
+ || abi == SpecAbi::RustIntrinsic
+ || abi == SpecAbi::PlatformIntrinsic
+ {
+ let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
+ if arg.is_ignore() {
+ return;
+ }
+
+ match arg.layout.abi {
+ Abi::Aggregate { .. } => {}
+
+ // This is a fun case! The gist of what this is doing is
+ // that we want callers and callees to always agree on the
+ // ABI of how they pass SIMD arguments. If we were to *not*
+ // make these arguments indirect then they'd be immediates
+ // in LLVM, which means that they'd used whatever the
+ // appropriate ABI is for the callee and the caller. That
+ // means, for example, if the caller doesn't have AVX
+ // enabled but the callee does, then passing an AVX argument
+ // across this boundary would cause corrupt data to show up.
+ //
+ // This problem is fixed by unconditionally passing SIMD
+ // arguments through memory between callers and callees
+ // which should get them all to agree on ABI regardless of
+ // target feature sets. Some more information about this
+ // issue can be found in #44367.
+ //
+ // Note that the platform intrinsic ABI is exempt here as
+ // that's how we connect up to LLVM and it's unstable
+ // anyway, we control all calls to it in libstd.
+ Abi::Vector { .. }
+ if abi != SpecAbi::PlatformIntrinsic
+ && cx.tcx().sess.target.target.options.simd_types_indirect =>
+ {
+ arg.make_indirect();
+ return;
+ }
+
+ _ => return,
+ }
+
+ let size = arg.layout.size;
+ if arg.layout.is_unsized() || size > Pointer.size(cx) {
+ arg.make_indirect();
+ } else {
+ // We want to pass small aggregates as immediates, but using
+ // a LLVM aggregate type for this leads to bad optimizations,
+ // so we pick an appropriately sized integer type instead.
+ arg.cast_to(Reg {
+ kind: RegKind::Integer,
+ size,
+ });
+ }
+ };
+ fixup(&mut self.ret);
+ for arg in &mut self.args {
+ fixup(arg);
+ }
+ if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
+ attrs.set(ArgAttribute::StructRet);
+ }
+ return;
+ }
+
+ if let Err(msg) = self.adjust_for_cabi(cx, abi) {
+ cx.tcx().sess.fatal(&msg);
+ }
+ }
+}
use rustc_codegen_ssa::traits::*;
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
-use rustc::ty::{self, Ty, Instance};
-use rustc::ty::layout::{self, PointerKind};
+use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc::ty::{Ty};
+use rustc::ty::layout::{self};
use libc::c_uint;
}
}
-pub trait FnTypeExt<'tcx> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self;
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi);
+pub trait FnTypeLlvmExt<'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
- let sig = instance.fn_sig(cx.tcx);
- let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- FnType::new(cx, sig, &[])
- }
-
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, _| {
- ArgType::new(cx.layout_of(ty))
- })
- }
-
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
- let mut layout = cx.layout_of(ty);
- // Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
- // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
- if arg_idx == Some(0) {
- let fat_pointer_ty = if layout.is_unsized() {
- // unsized `self` is passed as a pointer to `self`
- // FIXME (mikeyhew) change this to use &own if it is ever added to the language
- cx.tcx.mk_mut_ptr(layout.ty)
- } else {
- match layout.abi {
- LayoutAbi::ScalarPair(..) => (),
- _ => bug!("receiver type has unsupported layout: {:?}", layout)
- }
-
- // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
- // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
- // elsewhere in the compiler as a method on a `dyn Trait`.
- // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
- // get a built-in pointer type
- let mut fat_pointer_layout = layout;
- 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
- && !fat_pointer_layout.ty.is_region_ptr()
- {
- 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
- let field_layout = fat_pointer_layout.field(cx, i);
-
- if !field_layout.is_zst() {
- fat_pointer_layout = field_layout;
- continue 'descend_newtypes
- }
- }
-
- bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
- }
-
- fat_pointer_layout.ty
- };
-
- // we now have a type like `*mut RcBox<dyn Trait>`
- // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
- // this is understood as a special case elsewhere in the compiler
- let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
- layout = cx.layout_of(unit_pointer_ty);
- layout.ty = fat_pointer_ty;
- }
- ArgType::new(layout)
- })
- }
-
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self {
- debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
-
- use self::Abi::*;
- let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
- RustIntrinsic | PlatformIntrinsic |
- Rust | RustCall => Conv::C,
-
- // It's the ABI's job to select this, not ours.
- System => bug!("system abi should be selected elsewhere"),
-
- Stdcall => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
- Thiscall => Conv::X86ThisCall,
- C => Conv::C,
- Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
-
- // These API constants ought to be more specific...
- Cdecl => Conv::C,
- };
-
- let mut inputs = sig.inputs();
- let extra_args = if sig.abi == RustCall {
- assert!(!sig.c_variadic && extra_args.is_empty());
-
- match sig.inputs().last().unwrap().sty {
- ty::Tuple(tupled_arguments) => {
- inputs = &sig.inputs()[0..sig.inputs().len() - 1];
- tupled_arguments.iter().map(|k| k.expect_ty()).collect()
- }
- _ => {
- bug!("argument to function with \"rust-call\" ABI \
- is not a tuple");
- }
- }
- } else {
- assert!(sig.c_variadic || extra_args.is_empty());
- extra_args.to_vec()
- };
-
- let target = &cx.sess().target.target;
- let win_x64_gnu = target.target_os == "windows"
- && target.arch == "x86_64"
- && target.target_env == "gnu";
- let linux_s390x = target.target_os == "linux"
- && target.arch == "s390x"
- && target.target_env == "gnu";
- let linux_sparc64 = target.target_os == "linux"
- && target.arch == "sparc64"
- && target.target_env == "gnu";
- let rust_abi = match sig.abi {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
- _ => false
- };
-
- // Handle safe Rust thin and fat pointers.
- let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
- scalar: &layout::Scalar,
- layout: TyLayout<'tcx, Ty<'tcx>>,
- offset: Size,
- is_return: bool| {
- // Booleans are always an i1 that needs to be zero-extended.
- if scalar.is_bool() {
- attrs.set(ArgAttribute::ZExt);
- return;
- }
-
- // Only pointer types handled below.
- if scalar.value != layout::Pointer {
- return;
- }
-
- if scalar.valid_range.start() < scalar.valid_range.end() {
- if *scalar.valid_range.start() > 0 {
- attrs.set(ArgAttribute::NonNull);
- }
- }
-
- if let Some(pointee) = layout.pointee_info_at(cx, offset) {
- if let Some(kind) = pointee.safe {
- attrs.pointee_size = pointee.size;
- attrs.pointee_align = Some(pointee.align);
-
- // `Box` pointer parameters never alias because ownership is transferred
- // `&mut` pointer parameters never alias other parameters,
- // or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
- // and can be marked as both `readonly` and `noalias`, as
- // LLVM's definition of `noalias` is based solely on memory
- // dependencies rather than pointer equality
- let no_alias = match kind {
- PointerKind::Shared => false,
- PointerKind::UniqueOwned => true,
- PointerKind::Frozen |
- PointerKind::UniqueBorrowed => !is_return
- };
- if no_alias {
- attrs.set(ArgAttribute::NoAlias);
- }
-
- if kind == PointerKind::Frozen && !is_return {
- attrs.set(ArgAttribute::ReadOnly);
- }
- }
- }
- };
-
- // Store the index of the last argument. This is useful for working with
- // C-compatible variadic arguments.
- let last_arg_idx = if sig.inputs().is_empty() {
- None
- } else {
- Some(sig.inputs().len() - 1)
- };
-
- let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
- let is_return = arg_idx.is_none();
- let mut arg = mk_arg_type(ty, arg_idx);
- if arg.layout.is_zst() {
- // For some forsaken reason, x86_64-pc-windows-gnu
- // doesn't ignore zero-sized struct arguments.
- // The same is true for s390x-unknown-linux-gnu
- // and sparc64-unknown-linux-gnu.
- if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
- arg.mode = PassMode::Ignore(IgnoreMode::Zst);
- }
- }
-
- // If this is a C-variadic function, this is not the return value,
- // and there is one or more fixed arguments; ensure that the `VaList`
- // is ignored as an argument.
- if sig.c_variadic {
- match (last_arg_idx, arg_idx) {
- (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
- let va_list_did = match cx.tcx.lang_items().va_list() {
- Some(did) => did,
- None => bug!("`va_list` lang item required for C-variadic functions"),
- };
- match ty.sty {
- ty::Adt(def, _) if def.did == va_list_did => {
- // This is the "spoofed" `VaList`. Set the arguments mode
- // so that it will be ignored.
- arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
- },
- _ => (),
- }
- }
- _ => {}
- }
- }
-
- // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
- if !is_return && rust_abi {
- if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
- let mut a_attrs = ArgAttributes::new();
- let mut b_attrs = ArgAttributes::new();
- adjust_for_rust_scalar(&mut a_attrs,
- a,
- arg.layout,
- Size::ZERO,
- false);
- adjust_for_rust_scalar(&mut b_attrs,
- b,
- arg.layout,
- a.value.size(cx).align_to(b.value.align(cx).abi),
- false);
- arg.mode = PassMode::Pair(a_attrs, b_attrs);
- return arg;
- }
- }
-
- if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- adjust_for_rust_scalar(attrs,
- scalar,
- arg.layout,
- Size::ZERO,
- is_return);
- }
- }
-
- arg
- };
-
- let mut fn_ty = FnType {
- ret: arg_of(sig.output(), None),
- args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| {
- arg_of(ty, Some(i))
- }).collect(),
- c_variadic: sig.c_variadic,
- conv,
- };
- fn_ty.adjust_for_abi(cx, sig.abi);
- fn_ty
- }
-
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi) {
- if abi == Abi::Unadjusted { return }
-
- if abi == Abi::Rust || abi == Abi::RustCall ||
- abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
- if arg.is_ignore() { return; }
-
- match arg.layout.abi {
- layout::Abi::Aggregate { .. } => {}
-
- // This is a fun case! The gist of what this is doing is
- // that we want callers and callees to always agree on the
- // ABI of how they pass SIMD arguments. If we were to *not*
- // make these arguments indirect then they'd be immediates
- // in LLVM, which means that they'd used whatever the
- // appropriate ABI is for the callee and the caller. That
- // means, for example, if the caller doesn't have AVX
- // enabled but the callee does, then passing an AVX argument
- // across this boundary would cause corrupt data to show up.
- //
- // This problem is fixed by unconditionally passing SIMD
- // arguments through memory between callers and callees
- // which should get them all to agree on ABI regardless of
- // target feature sets. Some more information about this
- // issue can be found in #44367.
- //
- // Note that the platform intrinsic ABI is exempt here as
- // that's how we connect up to LLVM and it's unstable
- // anyway, we control all calls to it in libstd.
- layout::Abi::Vector { .. }
- if abi != Abi::PlatformIntrinsic &&
- cx.sess().target.target.options.simd_types_indirect =>
- {
- arg.make_indirect();
- return
- }
-
- _ => return
- }
-
- let size = arg.layout.size;
- if arg.layout.is_unsized() || size > layout::Pointer.size(cx) {
- arg.make_indirect();
- } else {
- // We want to pass small aggregates as immediates, but using
- // a LLVM aggregate type for this leads to bad optimizations,
- // so we pick an appropriately sized integer type instead.
- arg.cast_to(Reg {
- kind: RegKind::Integer,
- size
- });
- }
- };
- fixup(&mut self.ret);
- for arg in &mut self.args {
- fixup(arg);
- }
- if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
- attrs.set(ArgAttribute::StructRet);
- }
- return;
- }
-
- if let Err(msg) = self.adjust_for_cabi(cx, abi) {
- cx.sess().fatal(&msg);
- }
- }
-
+impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
let args_capacity: usize = self.args.iter().map(|arg|
if arg.pad.is_some() { 1 } else { 0 } +
}
}
-impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> {
- fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new(&self, sig, extra_args)
- }
- fn new_vtable(
- &self,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]
- ) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new_vtable(&self, sig, extra_args)
- }
- fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> {
- FnType::of_instance(&self, instance)
- }
-}
-
impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn apply_attrs_callsite(
&mut self,
use rustc_codegen_ssa::base::to_immediate;
use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ops::{Deref, Range};
use std::ptr;
}
}
+impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.cx.target_spec()
+ }
+}
+
impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyLayout = TyLayout<'tcx>;
use crate::llvm;
use crate::llvm::AttributePlace::Function;
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType, FnTypeLlvmExt};
use crate::attributes;
use crate::context::CodegenCx;
use crate::type_::Type;
use crate::value::Value;
use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{FnTypeExt, LayoutOf};
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_codegen_ssa::traits::*;
use crate::common;
use crate::type_of::LayoutLlvmExt;
-use crate::abi::{LlvmType, FnTypeExt};
+use crate::abi::{LlvmType, FnTypeLlvmExt};
use syntax::ast;
use rustc::ty::Ty;
use rustc::ty::layout::{self, Align, Size, TyLayout};
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType};
use crate::common::*;
use crate::type_::Type;
use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
use rustc_target::abi::{FloatTy, TyLayoutMethods};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
use rustc::middle::lang_items;
use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
use rustc::mir::interpret::InterpError;
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
ty::ParamEnv::reveal_all(),
&sig,
);
- let fn_ty = bx.new_vtable(sig, &[]);
+ let fn_ty = FnType::new_vtable(&bx, sig, &[]);
let vtable = args[1];
args = &args[..1];
(meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
}
_ => {
(bx.get_fn(drop_fn),
- bx.fn_type_of_instance(&drop_fn))
+ FnType::of_instance(&bx, &drop_fn))
}
};
helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
// Obtain the panic entry point.
let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
let instance = ty::Instance::mono(bx.tcx(), def_id);
- let fn_ty = bx.fn_type_of_instance(&instance);
+ let fn_ty = FnType::of_instance(&bx, &instance);
let llfn = bx.get_fn(instance);
// Codegen the actual panic invoke/call.
let fn_ty = match def {
Some(ty::InstanceDef::Virtual(..)) => {
- bx.new_vtable(sig, &extra_args)
+ FnType::new_vtable(&bx, sig, &extra_args)
}
Some(ty::InstanceDef::DropGlue(_, None)) => {
// Empty drop glue; a no-op.
helper.funclet_br(self, &mut bx, target);
return;
}
- _ => bx.new_fn_type(sig, &extra_args)
+ _ => FnType::new(&bx, sig, &extra_args)
};
// Emit a panic or a no-op for `panic_if_uninhabited`.
let def_id =
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
let instance = ty::Instance::mono(bx.tcx(), def_id);
- let fn_ty = bx.fn_type_of_instance(&instance);
+ let fn_ty = FnType::of_instance(&bx, &instance);
let llfn = bx.get_fn(instance);
// Codegen the actual panic invoke/call.
use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
-use rustc::ty::layout::{TyLayout, HasTyCtxt};
+use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Mir};
use rustc::session::config::DebugInfo;
use rustc_mir::monomorphize::Instance;
) {
assert!(!instance.substs.needs_infer());
- let fn_ty = cx.new_fn_type(sig, &[]);
+ let fn_ty = FnType::new(cx, sig, &[]);
debug!("fn_ty: {:?}", fn_ty);
let mut debug_context =
cx.create_function_debug_context(instance, sig, llfn, mir);
use super::BackendTypes;
-use rustc::ty::{FnSig, Instance, Ty};
+use rustc::ty::{Ty};
use rustc_target::abi::call::FnType;
-pub trait AbiMethods<'tcx> {
- fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
- fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
- fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>;
-}
-
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value);
fn get_param(&self, index: usize) -> Self::Value;
use crate::MemFlags;
use rustc::ty::Ty;
use rustc::ty::layout::{Align, Size, HasParamEnv};
+use rustc_target::spec::{HasTargetSpec};
use std::ops::Range;
use std::iter::TrustedLen;
+ AsmBuilderMethods<'tcx>
+ StaticBuilderMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTargetSpec
{
fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
mod type_;
mod write;
-pub use self::abi::{AbiBuilderMethods, AbiMethods};
+pub use self::abi::{AbiBuilderMethods};
pub use self::asm::{AsmBuilderMethods, AsmMethods};
pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods};
pub use self::builder::{BuilderMethods, OverflowOp};
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc::ty::layout::{HasParamEnv};
+use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::{HasTargetSpec};
use std::fmt;
+ ConstMethods<'tcx>
+ StaticMethods
+ DebugInfoMethods<'tcx>
- + AbiMethods<'tcx>
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTyCtxt<'tcx>
+ + HasTargetSpec
{
}
+ ConstMethods<'tcx>
+ StaticMethods
+ DebugInfoMethods<'tcx>
- + AbiMethods<'tcx>
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTyCtxt<'tcx>
+ + HasTargetSpec
{
}
// cache a direct reference to the source text, so that we don't have to
// retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
src: Lrc<String>,
- token: token::Token,
- span: Span,
- /// The raw source span which *does not* take `override_span` into account
- span_src_raw: Span,
- /// Stack of open delimiters and their spans. Used for error message.
- open_braces: Vec<(token::DelimToken, Span)>,
- crate unmatched_braces: Vec<UnmatchedBrace>,
- /// The type and spans for all braces
- ///
- /// Used only for error recovery when arriving to EOF with mismatched braces.
- matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
- crate override_span: Option<Span>,
- last_unclosed_found_span: Option<Span>,
+ override_span: Option<Span>,
}
impl<'a> StringReader<'a> {
sp: self.peek_span,
};
self.advance_token()?;
- self.span_src_raw = self.peek_span_src_raw;
-
Ok(ret_val)
}
}
}
- self.token = t.tok.clone();
- self.span = t.sp;
-
Ok(t)
}
peek_span_src_raw: syntax_pos::DUMMY_SP,
src,
fatal_errs: Vec::new(),
- token: token::Eof,
- span: syntax_pos::DUMMY_SP,
- span_src_raw: syntax_pos::DUMMY_SP,
- open_braces: Vec::new(),
- unmatched_braces: Vec::new(),
- matching_delim_spans: Vec::new(),
override_span,
- last_unclosed_found_span: None,
}
}
+use syntax_pos::Span;
+
use crate::print::pprust::token_to_string;
use crate::parse::lexer::{StringReader, UnmatchedBrace};
use crate::parse::{token, PResult};
use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
impl<'a> StringReader<'a> {
+ crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+ let mut tt_reader = TokenTreesReader {
+ string_reader: self,
+ token: token::Eof,
+ span: syntax_pos::DUMMY_SP,
+ open_braces: Vec::new(),
+ unmatched_braces: Vec::new(),
+ matching_delim_spans: Vec::new(),
+ last_unclosed_found_span: None,
+ };
+ let res = tt_reader.parse_all_token_trees();
+ (res, tt_reader.unmatched_braces)
+ }
+}
+
+struct TokenTreesReader<'a> {
+ string_reader: StringReader<'a>,
+ token: token::Token,
+ span: Span,
+ /// Stack of open delimiters and their spans. Used for error message.
+ open_braces: Vec<(token::DelimToken, Span)>,
+ unmatched_braces: Vec<UnmatchedBrace>,
+ /// The type and spans for all braces
+ ///
+ /// Used only for error recovery when arriving to EOF with mismatched braces.
+ matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
+ last_unclosed_found_span: Option<Span>,
+}
+
+impl<'a> TokenTreesReader<'a> {
// Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
- crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
+ fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
let mut tts = Vec::new();
+ self.real_token();
while self.token != token::Eof {
tts.push(self.parse_token_tree()?);
}
}
fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
- let sm = self.sess.source_map();
+ let sm = self.string_reader.sess.source_map();
match self.token {
token::Eof => {
let msg = "this file contains an un-closed delimiter";
- let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
+ let mut err = self.string_reader.sess.span_diagnostic
+ .struct_span_err(self.span, msg);
for &(_, sp) in &self.open_braces {
err.span_label(sp, "un-closed delimiter");
}
if let Some((delim, _)) = self.open_braces.last() {
if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
.filter(|(d, open_sp, close_sp)| {
-
- if let Some(close_padding) = sm.span_to_margin(*close_sp) {
- if let Some(open_padding) = sm.span_to_margin(*open_sp) {
- return delim == d && close_padding != open_padding;
+ if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+ if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+ return delim == d && close_padding != open_padding;
+ }
}
- }
- false
+ false
}).next() // these are in reverse order as they get inserted on close, but
{ // we want the last open/first close
err.span_label(
// matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected close delimiter: `{}`", token_str);
- let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
+ let mut err = self.string_reader.sess.span_diagnostic
+ .struct_span_err(self.span, &msg);
err.span_label(self.span, "unexpected close delimiter");
Err(err)
},
// Note that testing for joint-ness here is done via the raw
// source span as the joint-ness is a property of the raw source
// rather than wanting to take `override_span` into account.
- let raw = self.span_src_raw;
+ // Additionally, we actually check if the *next* pair of tokens
+ // is joint, but this is equivalent to checking the current pair.
+ let raw = self.string_reader.peek_span_src_raw;
self.real_token();
- let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+ let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo()
+ && token::is_op(&self.token);
Ok((tt, if is_joint { Joint } else { NonJoint }))
}
}
}
+
+ fn real_token(&mut self) {
+ let t = self.string_reader.real_token();
+ self.token = t.tok;
+ self.span = t.sp;
+ }
}
}
/// Given a source file, produces a sequence of token trees. Returns any buffered errors from
-/// parsing the token tream.
+/// parsing the token stream.
pub fn maybe_file_to_stream(
sess: &ParseSess,
source_file: Lrc<SourceFile>,
override_span: Option<Span>,
) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
- let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
- srdr.real_token();
+ let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
+ let (token_trees, unmatched_braces) = srdr.into_token_trees();
- match srdr.parse_all_token_trees() {
- Ok(stream) => Ok((stream, srdr.unmatched_braces)),
+ match token_trees {
+ Ok(stream) => Ok((stream, unmatched_braces)),
Err(err) => {
let mut buffer = Vec::with_capacity(1);
err.buffer(&mut buffer);
// Not using `emit_unclosed_delims` to use `db.buffer`
- for unmatched in srdr.unmatched_braces {
+ for unmatched in unmatched_braces {
let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
"incorrect close delimiter: `{}`",
token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
self.expect(&token::OpenDelim(token::Paren))?;
let expr = self.parse_expr()?;
self.expect(&token::CloseDelim(token::Paren))?;
+ hi = self.prev_span;
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
} else if self.token.is_path_start() {
let path = self.parse_path(PathStyle::Expr)?;
--> $DIR/await-macro.rs:9:5
|
LL | await!(bar());
- | ^^^^^
+ | ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/50547
= help: add #![feature(await_macro)] to the crate attributes to enable