Merge pull request #4120 from rust-lang/rustup-2025-01-03

Automatic Rustup
This commit is contained in:
Ben Kimock 2025-01-03 05:49:42 +00:00 committed by GitHub
commit 26f09b571b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
571 changed files with 351710 additions and 1377 deletions

4
.gitmodules vendored
View file

@ -22,10 +22,6 @@
path = library/stdarch
url = https://github.com/rust-lang/stdarch.git
shallow = true
[submodule "src/doc/rustc-dev-guide"]
path = src/doc/rustc-dev-guide
url = https://github.com/rust-lang/rustc-dev-guide.git
shallow = true
[submodule "src/doc/edition-guide"]
path = src/doc/edition-guide
url = https://github.com/rust-lang/edition-guide.git

View file

@ -48,6 +48,7 @@ Andrew Poelstra <asp11@sfu.ca> <apoelstra@wpsoftware.net>
Anhad Singh <andypythonappdeveloper@gmail.com>
Antoine Plaskowski <antoine.plaskowski@epitech.eu>
Anton Löfgren <anton.lofgren@gmail.com> <alofgren@op5.com>
apiraino <apiraino@users.noreply.github.com> <apiraino@protonmail.com>
Araam Borhanian <avborhanian@gmail.com>
Araam Borhanian <avborhanian@gmail.com> <dobbybabee@gmail.com>
Areski Belaid <areski@gmail.com> areski <areski@gmail.com>
@ -62,7 +63,10 @@ Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org>
Ayaz Hafiz <ayaz.hafiz.1@gmail.com>
Aydin Kim <ladinjin@hanmail.net> aydin.kim <aydin.kim@samsung.com>
Ayush Mishra <ayushmishra2005@gmail.com>
Ashley Mannix <kodraus@hey.com> <ashleymannix@live.com.au>
asrar <aszenz@gmail.com>
b-naber <bn263@gmx.de>
b-naber <bn263@gmx.de> <b_naber@gmx.de>
BaoshanPang <pangbw@gmail.com>
Barosl Lee <vcs@barosl.com> Barosl LEE <github@barosl.com>
Bastian Kersting <bastian@cmbt.de>
@ -98,6 +102,8 @@ Caleb Cartwright <caleb.cartwright@outlook.com>
Caleb Jones <code@calebjones.net>
Noah Lev <camelidcamel@gmail.com>
Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
Catherine <catherine3.flores@gmail.com>
Catherine <catherine3.flores@gmail.com> <catherine.3.flores@gmail.com>
cameron1024 <cameron.studdstreet@gmail.com>
Camille Gillot <gillot.camille@gmail.com>
Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
@ -133,11 +139,13 @@ Clement Miao <clementmiao@gmail.com>
Clément Renault <renault.cle@gmail.com>
Cliff Dyer <jcd@sdf.org>
Clinton Ryan <clint.ryan3@gmail.com>
Taylor Cramer <cramertaylorj@gmail.com> <cramertj@google.com>
ember arlynx <ember@lunar.town> <corey@octayn.net>
Crazycolorz5 <Crazycolorz5@gmail.com>
csmoe <35686186+csmoe@users.noreply.github.com>
Cyryl Płotnicki <cyplo@cyplo.net>
Damien Schoof <damien.schoof@gmail.com>
Dan Gohman <dev@sunfishcode.online> <sunfish@mozilla.com>
Dan Robertson <danlrobertson89@gmail.com>
Daniel Campoverde <alx741@riseup.net>
Daniel J Rollins <drollins@financialforce.com>
@ -179,10 +187,17 @@ Eduardo Bautista <me@eduardobautista.com> <=>
Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
Eduardo Broto <ebroto@tutanota.com>
Edward Shen <code@eddie.sh> <xes@meta.com>
Jacob Finkelman <eh2406@wayne.edu>
Jacob Finkelman <eh2406@wayne.edu> <YeomanYaacov@gmail.com>
Jacob Finkelman <eh2406@wayne.edu> <jfinkelm@amazon.com>
Jacob Finkelman <eh2406@wayne.edu> <finkelman@semcog.org>
Jacob Finkelman <eh2406@wayne.edu> <Eh2406@users.noreply.github.com>
Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com>
Elly Fong-Jones <elly@leptoquark.net>
Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu>
Eric Holk <eric.holk@gmail.com> <eholk@mozilla.com>
Eric Holk <eric.holk@gmail.com> <eric@theincredibleholk.org>
Eric Holk <eric.holk@gmail.com> <ericholk@microsoft.com>
Eric Holmes <eric@ejholmes.net>
Eric Reed <ecreed@cs.washington.edu> <ereed@mozilla.com>
Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org>
@ -206,6 +221,7 @@ Felix S. Klock II <pnkfelix@pnkfx.org> <pnkfelix@mozilla.com>
Félix Saparelli <felix@passcod.name>
Flaper Fesp <flaper87@gmail.com>
Florian Berger <fbergr@gmail.com>
Florian Gilcher <florian.gilcher@asquera.de> <flo@andersground.net>
Florian Wilkens <mrfloya_github@outlook.com> Florian Wilkens <floya@live.de>
François Mockers <mockersf@gmail.com>
Frank Steffahn <fdsteffahn@gmail.com> <frank.steffahn@stu.uni-kiel.de>
@ -240,6 +256,8 @@ Herman J. Radtke III <herman@hermanradtke.com> Herman J. Radtke III <hermanradtk
Hirochika Matsumoto <git@hkmatsumoto.com> <matsujika@gmail.com>
Hrvoje Nikšić <hniksic@gmail.com>
Hsiang-Cheng Yang <rick68@users.noreply.github.com>
Huon Wilson <dbau.pp@gmail.com>
Huon Wilson <dbau.pp@gmail.com> <wilson.huon@gmail.com>
Ian Jackson <ijackson@chiark.greenend.org.uk> <ian.jackson@citrix.com>
Ian Jackson <ijackson@chiark.greenend.org.uk> <ijackson+github@slimy.greenend.org.uk>
Ian Jackson <ijackson@chiark.greenend.org.uk> <iwj@xenproject.org>
@ -252,9 +270,13 @@ ivan tkachenko <me@ratijas.tk>
J. J. Weber <jjweber@gmail.com>
Jack Huey <jack.huey@umassmed.edu> <jackh726@gmail.com>
Jacob <jacob.macritchie@gmail.com>
Jacob Hoffman-Andrews <rust@hoffman-andrews.com> <github@hoffman-andrews.com>
Jacob Greenfield <xales@naveria.com>
Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com>
Jacob Pratt <jacob@jhpratt.dev> <jacopratt@tesla.com>
Jake Goulding <jake.goulding@integer32.com>
Jake Goulding <jake.goulding@integer32.com> <jake.goulding@gmail.com>
Jake Goulding <jake.goulding@integer32.com> <shepmaster@mac.com>
Jake Vossen <jake@vossen.dev>
Jakob Degen <jakob.e.degen@gmail.com> <jakob@degen.com>
Jakob Lautrup Nysom <jako3047@gmail.com>
@ -287,6 +309,7 @@ Jerry Hardee <hardeejj9@gmail.com>
Jesús Rubio <jesusprubio@gmail.com>
Jethro Beekman <github@jbeekman.nl>
Jian Zeng <knight42@mail.ustc.edu.cn>
Jieyou Xu <jieyouxu@outlook.com>
Jieyou Xu <jieyouxu@outlook.com> <39484203+jieyouxu@users.noreply.github.com>
Jihyun Yu <j.yu@navercorp.com> <yjh0502@gmail.com>
Jihyun Yu <j.yu@navercorp.com> jihyun <jihyun@nablecomm.com>
@ -322,9 +345,12 @@ Josh Holmer <jholmer.in@gmail.com>
Josh Stone <cuviper@gmail.com> <jistone@redhat.com>
Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org>
Julia Ryan <juliaryan3.14@gmail.com> <josephryan3.14@gmail.com>
Jubilee Young <workingjubilee@gmail.com> <46493976+workingjubilee@users.noreply.github.com>
Jubilee Young <workingjubilee@gmail.com>
Julian Knodt <julianknodt@gmail.com>
jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com>
Junyoung Cho <june0.cho@samsung.com>
Jynn Nelson <github@jyn.dev> <rust@jyn.dev>
Jynn Nelson <github@jyn.dev> <jyn514@gmail.com>
Jynn Nelson <github@jyn.dev> <joshua@yottadb.com>
Jynn Nelson <github@jyn.dev> <jyn.nelson@redjack.com>
@ -385,12 +411,14 @@ Marcell Pardavi <marcell.pardavi@gmail.com>
Marcus Klaas de Vries <mail@marcusklaas.nl>
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> <mmeyerho@andrew>
Mark Mansi <markm@cs.wisc.edu>
Mark Mansi <markm@cs.wisc.edu> <m.mim95@gmail.com>
Mark Rousskov <mark.simulacrum@gmail.com>
Mark Sinclair <mark.edward.x@gmail.com>
Mark Sinclair <mark.edward.x@gmail.com> =Mark Sinclair <=125axel125@gmail.com>
Markus Legner <markus@legner.ch>
Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
Martin Carton <cartonmartin+git@gmail.com>
Martin Carton <cartonmartin+git@gmail.com> <cartonmartin@gmail.com>
Martin Habovštiak <martin.habovstiak@gmail.com>
Martin Hafskjold Thoresen <martinhath@gmail.com>
Martin Nordholts <martin.nordholts@codetale.se> <enselic@gmail.com>
@ -415,6 +443,7 @@ Melody Horn <melody@boringcactus.com> <mathphreak@gmail.com>
Mendes <pedro.mendes.26@gmail.com>
mental <m3nta1@yahoo.com>
mibac138 <5672750+mibac138@users.noreply.github.com>
Michael Howell <michael@notriddle.com> <notriddle+rust-mod@protonmail.com>
Michael Williams <m.t.williams@live.com>
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail>
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail.com>
@ -431,6 +460,7 @@ Ms2ger <ms2ger@gmail.com> <Ms2ger@gmail.com>
msizanoen1 <qtmlabs@protonmail.com>
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
Nadrieril Feneanar <Nadrieril@users.noreply.github.com>
Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+rust@gmail.com>
Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+git@gmail.com>
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm+github@gmail.com>
@ -447,15 +477,23 @@ Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@gmail.com>
Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@google.com>
Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@apple.com>
Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@mozilla.com>
Nick Cameron <nrc@ncameron.org> <ncameron@mozilla.com>
Nick Fitzgerald <fitzgen@gmail.com> <nfitzgerald@mozilla.com>
Nick Platt <platt.nicholas@gmail.com>
Niclas Schwarzlose <15schnic@gmail.com>
Nicolas Abram <abramlujan@gmail.com>
Nicole Mazzuca <npmazzuca@gmail.com>
Niko Matsakis <rust@nikomatsakis.com>
Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu>
Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <rust@noratrieb.dev>
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nora@noratrieb.dev>
Nif Ward <nif.ward@gmail.com>
Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
Nikita Popov <nikita.ppv@gmail.com>
Nikita Popov <nikita.ppv@gmail.com> <npopov@redhat.com>
NODA Kai <nodakai@gmail.com>
Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <oguz.agcayazi@gmail.com>
Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <ouz.agz@gmail.com>
@ -516,6 +554,7 @@ Ricky Hosfelt <ricky@hosfelt.io>
Ritiek Malhotra <ritiekmalhotra123@gmail.com>
Rob Arnold <robarnold@cs.cmu.edu>
Rob Arnold <robarnold@cs.cmu.edu> Rob Arnold <robarnold@68-26-94-7.pools.spcsdns.net>
Robert Collins <robertc@robertcollins.net> <robertc+rust@robertcollins.net>
Robert Foss <dev@robertfoss.se> robertfoss <dev@robertfoss.se>
Robert Gawdzik <rgawdzik@hotmail.com> Robert Gawdzik ☢ <rgawdzik@hotmail.com>
Robert Habermeier <rphmeier@gmail.com>
@ -553,7 +592,15 @@ Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me>
Simonas Kazlauskas <git@kazlauskas.me> <simonas+t-compiler@kazlauskas.me>
Siva Prasad <sivaauturic@gmail.com>
Skgland <3877590+Skgland@users.noreply.github.com>
Skgland <3877590+Skgland@users.noreply.github.com> <bb-github@t-online.de>
Skgland <3877590+Skgland@users.noreply.github.com> <bennet.blessmann+github@googlemail.com>
Smittyvb <me@smitop.com>
Sophia June Turner <547158+sophiajt@users.noreply.github.com>
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <547158+jntrnr@users.noreply.github.com>
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathandturner@users.noreply.github.com>
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jturner@mozilla.com>
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathan.d.turner@gmail.com>
Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
Stanislav Tkach <stanislav.tkach@gmail.com>
startling <tdixon51793@gmail.com>
@ -586,8 +633,10 @@ Tim Diekmann <t.diekmann.3dv@gmail.com>
Tim Hutt <tdhutt@gmail.com>
Tim JIANG <p90eri@gmail.com>
Tim Joseph Dumol <tim@timdumol.com>
Tim Neumann <mail@timnn.me> <timnn@google.com>
Timothy Maloney <tmaloney@pdx.edu>
Tomas Koutsky <tomas@stepnivlk.net>
Tomasz Miąsko <tomasz.miasko@gmail.com>
Torsten Weber <TorstenWeber12@gmail.com>
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
@ -607,7 +656,9 @@ Valerii Lashmanov <vflashm@gmail.com>
Vitali Haravy <HumaneProgrammer@gmail.com> Vitali Haravy <humaneprogrammer@gmail.com>
Vitaly Shukela <vi0oss@gmail.com>
Waffle Lapkin <waffle.lapkin@gmail.com>
Waffle Lapkin <waffle.lapkin@tasking.com>
Waffle Lapkin <waffle.lapkin@gmail.com> <waffle.lapkin@tasking.com>
Weihang Lo <me@weihanglo.tw>
Weihang Lo <me@weihanglo.tw> <weihanglo@users.noreply.github.com>
Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com>
whitequark <whitequark@whitequark.org>
William Ting <io@williamting.com> <william.h.ting@gmail.com>

View file

@ -8,6 +8,38 @@
#![warn(unreachable_pub)]
// tidy-alphabetical-end
/*! ABI handling for rustc
## What is an "ABI"?
Literally, "application binary interface", which means it is everything about how code interacts,
at the machine level, with other code. This means it technically covers all of the following:
- object binary format for e.g. relocations or offset tables
- in-memory layout of types
- procedure calling conventions
When we discuss "ABI" in the context of rustc, we are probably discussing calling conventions.
To describe those `rustc_abi` also covers type layout, as it must for values passed on the stack.
Despite `rustc_abi` being about calling conventions, it is good to remember these usages exist.
You will encounter all of them and more if you study target-specific codegen enough!
Even in general conversation, when someone says "the Rust ABI is unstable", it may allude to
either or both of
- `repr(Rust)` types have a mostly-unspecified layout
- `extern "Rust" fn(A) -> R` has an unspecified calling convention
## Crate Goal
ABI is a foundational concept, so the `rustc_abi` crate serves as an equally foundational crate.
It cannot carry all details relevant to an ABI: those permeate code generation and linkage.
Instead, `rustc_abi` is intended to provide the interface for reasoning about the binary interface.
It should contain traits and types that other crates then use in their implementation.
For example, a platform's `extern "C" fn` calling convention will be implemented in `rustc_target`
but `rustc_abi` contains the types for calculating layout and describing register-passing.
This makes it easier to describe things in the same way across targets, codegen backends, and
even other Rust compilers, such as rust-analyzer!
*/
use std::fmt;
#[cfg(feature = "nightly")]
use std::iter::Step;

View file

@ -241,15 +241,15 @@ impl AngleBracketedArg {
}
}
impl Into<P<GenericArgs>> for AngleBracketedArgs {
fn into(self) -> P<GenericArgs> {
P(GenericArgs::AngleBracketed(self))
impl From<AngleBracketedArgs> for P<GenericArgs> {
fn from(val: AngleBracketedArgs) -> Self {
P(GenericArgs::AngleBracketed(val))
}
}
impl Into<P<GenericArgs>> for ParenthesizedArgs {
fn into(self) -> P<GenericArgs> {
P(GenericArgs::Parenthesized(self))
impl From<ParenthesizedArgs> for P<GenericArgs> {
fn from(val: ParenthesizedArgs) -> Self {
P(GenericArgs::Parenthesized(val))
}
}

View file

@ -6,7 +6,6 @@
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use crate::expand::typetree::TypeTree;
use crate::expand::{Decodable, Encodable, HashStable_Generic};
use crate::ptr::P;
use crate::{Ty, TyKind};
@ -79,10 +78,6 @@ pub struct AutoDiffItem {
/// The name of the function being generated
pub target: String,
pub attrs: AutoDiffAttrs,
/// Describe the memory layout of input types
pub inputs: Vec<TypeTree>,
/// Describe the memory layout of the output type
pub output: TypeTree,
}
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AutoDiffAttrs {
@ -262,22 +257,14 @@ impl AutoDiffAttrs {
!matches!(self.mode, DiffMode::Error | DiffMode::Source)
}
pub fn into_item(
self,
source: String,
target: String,
inputs: Vec<TypeTree>,
output: TypeTree,
) -> AutoDiffItem {
AutoDiffItem { source, target, inputs, output, attrs: self }
pub fn into_item(self, source: String, target: String) -> AutoDiffItem {
AutoDiffItem { source, target, attrs: self }
}
}
impl fmt::Display for AutoDiffItem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Differentiating {} -> {}", self.source, self.target)?;
write!(f, " with attributes: {:?}", self.attrs)?;
write!(f, " with inputs: {:?}", self.inputs)?;
write!(f, " with output: {:?}", self.output)
write!(f, " with attributes: {:?}", self.attrs)
}
}

View file

@ -4,6 +4,7 @@ use rustc_span::{Ident, Span, Symbol};
use crate::Expr;
use crate::ptr::P;
use crate::token::LitKind;
// Definitions:
//
@ -45,6 +46,10 @@ pub struct FormatArgs {
pub span: Span,
pub template: Vec<FormatArgsPiece>,
pub arguments: FormatArguments,
/// The raw, un-split format string literal, with no escaping or processing.
///
/// Generally only useful for lints that care about the raw bytes the user wrote.
pub uncooked_fmt_str: (LitKind, Symbol),
}
/// A piece of a format template string.

View file

@ -1596,7 +1596,7 @@ fn walk_inline_asm_sym<T: MutVisitor>(
fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
// FIXME: visit the template exhaustively.
let FormatArgs { span, template: _, arguments } = fmt;
let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
for FormatArgument { kind, expr } in arguments.all_args_mut() {
match kind {
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {

View file

@ -158,9 +158,9 @@ impl<T> From<Vec<T>> for P<[T]> {
}
}
impl<T> Into<Vec<T>> for P<[T]> {
fn into(self) -> Vec<T> {
self.into_vec()
impl<T> From<P<[T]>> for Vec<T> {
fn from(val: P<[T]>) -> Self {
val.into_vec()
}
}

View file

@ -1061,7 +1061,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
}
pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result {
let FormatArgs { span: _, template: _, arguments } = fmt;
let FormatArgs { span: _, template: _, arguments, uncooked_fmt_str: _ } = fmt;
for FormatArgument { kind, expr } in arguments.all_args() {
match kind {
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {

View file

@ -1845,11 +1845,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericParamKind::Lifetime => {
// AST resolution emitted an error on those parameters, so we lower them using
// `ParamName::Error`.
let ident = self.lower_ident(param.ident);
let param_name =
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
ParamName::Error
ParamName::Error(ident)
} else {
let ident = self.lower_ident(param.ident);
ParamName::Plain(ident)
};
let kind =

View file

@ -1,9 +1,10 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{CaptureBy, ExprKind, HirId, Node};
use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node};
use rustc_middle::bug;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
@ -683,48 +684,126 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) {
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
/// A HIR visitor to associate each binding with a `&` or `&mut` that could be removed to
/// make it bind by reference instead (if possible)
struct BindingFinder<'tcx> {
typeck_results: &'tcx ty::TypeckResults<'tcx>,
hir: rustc_middle::hir::map::Map<'tcx>,
/// Input: the span of the pattern we're finding bindings in
pat_span: Span,
/// Input: the spans of the bindings we're providing suggestions for
binding_spans: Vec<Span>,
/// Internal state: have we reached the pattern we're finding bindings in?
found_pat: bool,
/// Internal state: the innermost `&` or `&mut` "above" the visitor
ref_pat: Option<&'tcx hir::Pat<'tcx>>,
/// Internal state: could removing a `&` give bindings unexpected types?
has_adjustments: bool,
/// Output: for each input binding, the `&` or `&mut` to remove to make it by-ref
ref_pat_for_binding: Vec<(Span, Option<&'tcx hir::Pat<'tcx>>)>,
/// Output: ref patterns that can't be removed straightforwardly
cannot_remove: FxHashSet<HirId>,
}
impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.hir
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
// Don't walk into const patterns or anything else that might confuse this
if !self.found_pat {
hir::intravisit::walk_expr(self, ex)
}
}
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
if p.span == self.pat_span {
self.found_pat = true;
}
let parent_has_adjustments = self.has_adjustments;
self.has_adjustments |=
self.typeck_results.pat_adjustments().contains_key(p.hir_id);
// Track the innermost `&` or `&mut` enclosing bindings, to suggest removing it.
let parent_ref_pat = self.ref_pat;
if let hir::PatKind::Ref(..) = p.kind {
self.ref_pat = Some(p);
// To avoid edition-dependent logic to figure out how many refs this `&` can
// peel off, simply don't remove the "parent" `&`.
self.cannot_remove.extend(parent_ref_pat.map(|r| r.hir_id));
if self.has_adjustments {
// Removing this `&` could give child bindings unexpected types, so don't.
self.cannot_remove.insert(p.hir_id);
// As long the `&` stays, child patterns' types should be as expected.
self.has_adjustments = false;
}
}
if let hir::PatKind::Binding(_, _, ident, _) = p.kind {
// the spans in `binding_spans` encompass both the ident and binding mode
if let Some(&bind_sp) =
self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span))
{
self.ref_pat_for_binding.push((bind_sp, self.ref_pat));
} else {
// we've encountered a binding that we're not reporting a move error for.
// we don't want to change its type, so don't remove the surrounding `&`.
if let Some(ref_pat) = self.ref_pat {
self.cannot_remove.insert(ref_pat.hir_id);
}
}
}
hir::intravisit::walk_pat(self, p);
self.ref_pat = parent_ref_pat;
self.has_adjustments = parent_has_adjustments;
}
}
let mut pat_span = None;
let mut binding_spans = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) =
if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span: pat_sp, .. })) =
*bind_to.local_info()
{
let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
else {
continue;
};
let Some(stripped) = pat_snippet.strip_prefix('&') else {
suggestions.push((
bind_to.source_info.span.shrink_to_lo(),
"consider borrowing the pattern binding".to_string(),
"ref ".to_string(),
));
continue;
};
let inner_pat_snippet = stripped.trim_start();
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
let pat_span = pat_span.with_hi(
pat_span.lo()
+ BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
);
(pat_span, String::new(), "mutable borrow")
} else {
let pat_span = pat_span.with_hi(
pat_span.lo()
+ BytePos(
(pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
),
);
(pat_span, String::new(), "borrow")
};
suggestions.push((
pat_span,
format!("consider removing the {to_remove}"),
suggestion,
));
pat_span = Some(pat_sp);
binding_spans.push(bind_to.source_info.span);
}
}
let Some(pat_span) = pat_span else { return };
let hir = self.infcx.tcx.hir();
let Some(body) = hir.maybe_body_owned_by(self.mir_def_id()) else { return };
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
let mut finder = BindingFinder {
typeck_results,
hir,
pat_span,
binding_spans,
found_pat: false,
ref_pat: None,
has_adjustments: false,
ref_pat_for_binding: Vec::new(),
cannot_remove: FxHashSet::default(),
};
finder.visit_body(body);
let mut suggestions = Vec::new();
for (binding_span, opt_ref_pat) in finder.ref_pat_for_binding {
if let Some(ref_pat) = opt_ref_pat
&& !finder.cannot_remove.contains(&ref_pat.hir_id)
&& let hir::PatKind::Ref(subpat, mutbl) = ref_pat.kind
&& let Some(ref_span) = ref_pat.span.trim_end(subpat.span)
{
let mutable_str = if mutbl.is_mut() { "mutable " } else { "" };
let msg = format!("consider removing the {mutable_str}borrow");
suggestions.push((ref_span, msg, "".to_string()));
} else {
let msg = "consider borrowing the pattern binding".to_string();
suggestions.push((binding_span.shrink_to_lo(), msg, "ref ".to_string()));
}
}
suggestions.sort_unstable_by_key(|&(span, _, _)| span);

View file

@ -575,7 +575,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// ---------- place
self.err.multipart_suggestions(
format!(
"to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
"use `.insert()` to insert a value into a `{}`, `.get_mut()` \
to modify it, or the entry API for more flexibility",
self.ty,
),
vec![
@ -592,16 +593,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
(rv.span.shrink_to_hi(), ")".to_string()),
],
vec![
// val.get_mut(index).map(|v| { *v = rv; });
// if let Some(v) = val.get_mut(index) { *v = rv; }
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(place.span.hi()),
").map(|val| { *val".to_string(),
") { *val".to_string(),
),
(rv.span.shrink_to_hi(), "; })".to_string()),
(rv.span.shrink_to_hi(), "; }".to_string()),
],
vec![
// let x = val.entry(index).or_insert(rv);
@ -622,21 +624,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggested = true;
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
&& let hir::ExprKind::Index(val, index, _) = receiver.kind
&& expr.span == self.assign_span
&& receiver.span == self.assign_span
{
// val[index].path(args..);
self.err.multipart_suggestion(
format!("to modify a `{}` use `.get_mut()`", self.ty),
vec![
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
").map(|val| val".to_string(),
") { val".to_string(),
),
(sp.shrink_to_hi(), ")".to_string()),
(sp.shrink_to_hi(), "; }".to_string()),
],
Applicability::MachineApplicable,
);

View file

@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n ->
builtin_macros_format_remove_raw_ident = remove the `r#`
builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`?
builtin_macros_format_requires_string = requires at least a format string argument
builtin_macros_format_string_invalid = invalid format string: {$desc}

View file

@ -16,7 +16,7 @@ use smallvec::smallvec;
use {rustc_ast as ast, rustc_parse_format as parse};
use crate::errors;
use crate::util::expr_to_spanned_string;
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
pub struct AsmArgs {
pub templates: Vec<P<ast::Expr>>,
@ -527,7 +527,12 @@ fn expand_preparsed_asm(
let msg = "asm template must be a string literal";
let template_sp = template_expr.span;
let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_));
let (template_str, template_style, template_span) = {
let ExprToSpannedString {
symbol: template_str,
style: template_style,
span: template_span,
..
} = {
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
return ExpandResult::Retry(());
};

View file

@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion {
#[primary_span]
span: Span,
},
#[suggestion(
builtin_macros_format_reorder_format_parameter,
code = "{replacement}",
style = "verbose",
applicability = "machine-applicable"
)]
ReorderFormatParameter {
#[primary_span]
span: Span,
replacement: String,
},
}
#[derive(Diagnostic)]

View file

@ -17,7 +17,7 @@ use rustc_parse_format as parse;
use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
use crate::errors;
use crate::util::expr_to_spanned_string;
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
// The format_args!() macro is expanded in three steps:
// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
@ -166,13 +166,18 @@ fn make_format_args(
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
let (fmt_str, fmt_style, fmt_span) = {
let ExprToSpannedString {
symbol: fmt_str,
span: fmt_span,
style: fmt_style,
uncooked_symbol: uncooked_fmt_str,
} = {
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
return ExpandResult::Retry(());
};
match mac {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
fmt.symbol = Symbol::intern(&format!("{}\n", fmt.symbol));
fmt
}
Ok(fmt) => fmt,
@ -316,6 +321,13 @@ fn make_format_args(
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
}
}
parse::Suggestion::ReorderFormatParameter(span, replacement) => {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter {
span,
replacement,
});
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));
@ -584,7 +596,12 @@ fn make_format_args(
}
}
ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args }))
ExpandResult::Ready(Ok(FormatArgs {
span: fmt_span,
template,
arguments: args,
uncooked_fmt_str,
}))
}
fn invalid_placeholder_type_error(

View file

@ -57,7 +57,17 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
/// `Ok` represents successfully retrieving the string literal at the correct
/// position, e.g., `println("abc")`.
type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
pub(crate) type ExprToSpannedStringResult<'a> = Result<ExprToSpannedString, UnexpectedExprKind<'a>>;
pub(crate) struct ExprToSpannedString {
pub symbol: Symbol,
pub style: ast::StrStyle,
pub span: Span,
/// The raw string literal, with no escaping or processing.
///
/// Generally only useful for lints that care about the raw bytes the user wrote.
pub uncooked_symbol: (ast::token::LitKind, Symbol),
}
/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
/// but another type of expression is obtained instead.
@ -90,7 +100,12 @@ pub(crate) fn expr_to_spanned_string<'a>(
ExpandResult::Ready(Err(match expr.kind {
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Str(s, style)) => {
return ExpandResult::Ready(Ok((s, style, expr.span)));
return ExpandResult::Ready(Ok(ExprToSpannedString {
symbol: s,
style,
span: expr.span,
uncooked_symbol: (token_lit.kind, token_lit.symbol),
}));
}
Ok(ast::LitKind::ByteStr(..)) => {
let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
@ -128,7 +143,7 @@ pub(crate) fn expr_to_string(
Ok((err, _)) => err.emit(),
Err(guar) => guar,
})
.map(|(symbol, style, _)| (symbol, style))
.map(|ExprToSpannedString { symbol, style, .. }| (symbol, style))
})
}
@ -183,7 +198,7 @@ pub(crate) fn get_single_str_spanned_from_tts(
Ok((err, _)) => err.emit(),
Err(guar) => guar,
})
.map(|(symbol, _style, span)| (symbol, span))
.map(|ExprToSpannedString { symbol, span, .. }| (symbol, span))
})
}

View file

@ -93,6 +93,7 @@ use gccjit::{CType, Context, OptimizationLevel};
#[cfg(feature = "master")]
use gccjit::{TargetInfo, Version};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
@ -439,6 +440,15 @@ impl WriteBackendMethods for GccCodegenBackend {
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::write::link(cgcx, dcx, modules)
}
fn autodiff(
_cgcx: &CodegenContext<Self>,
_tcx: TyCtxt<'_>,
_module: &ModuleCodegen<Self::Module>,
_diff_fncs: Vec<AutoDiffItem>,
_config: &ModuleConfig,
) -> Result<(), FatalError> {
unimplemented!()
}
}
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit

View file

@ -1,3 +1,5 @@
codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
codegen_llvm_dynamic_linking_with_lto =
@ -47,6 +49,8 @@ codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO modul
codegen_llvm_parse_target_machine_config =
failed to parse target machine config to target machine: {$error}
codegen_llvm_prepare_autodiff = failed to prepare autodiff: src: {$src}, target: {$target}, {$error}
codegen_llvm_prepare_autodiff_with_llvm_err = failed to prepare autodiff: {$llvm_err}, src: {$src}, target: {$target}, {$error}
codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}

View file

@ -604,7 +604,14 @@ pub(crate) fn run_pass_manager(
debug!("running the pass manager");
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
// If this rustc version was build with enzyme/autodiff enabled, and if users applied the
// `#[autodiff]` macro at least once, then we will later call llvm_optimize a second time.
let first_run = true;
debug!("running llvm pm opt pipeline");
unsafe {
write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, first_run)?;
}
debug!("lto done");
Ok(())
}

View file

@ -25,7 +25,7 @@ impl OwnedTargetMachine {
model: llvm::CodeModel,
reloc: llvm::RelocModel,
level: llvm::CodeGenOptLevel,
use_soft_fp: bool,
float_abi: llvm::FloatAbi,
function_sections: bool,
data_sections: bool,
unique_section_names: bool,
@ -57,7 +57,7 @@ impl OwnedTargetMachine {
model,
reloc,
level,
use_soft_fp,
float_abi,
function_sections,
data_sections,
unique_section_names,

View file

@ -26,8 +26,8 @@ use rustc_session::config::{
self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath,
};
use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext, sym};
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
use tracing::debug;
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
use tracing::{debug, trace};
use crate::back::lto::ThinBuffer;
use crate::back::owned_target_machine::OwnedTargetMachine;
@ -181,6 +181,14 @@ pub(crate) fn to_llvm_code_model(code_model: Option<CodeModel>) -> llvm::CodeMod
}
}
fn to_llvm_float_abi(float_abi: Option<FloatAbi>) -> llvm::FloatAbi {
match float_abi {
None => llvm::FloatAbi::Default,
Some(FloatAbi::Soft) => llvm::FloatAbi::Soft,
Some(FloatAbi::Hard) => llvm::FloatAbi::Hard,
}
}
pub(crate) fn target_machine_factory(
sess: &Session,
optlvl: config::OptLevel,
@ -189,12 +197,12 @@ pub(crate) fn target_machine_factory(
let reloc_model = to_llvm_relocation_model(sess.relocation_model());
let (opt_level, _) = to_llvm_opt_settings(optlvl);
let use_softfp = if sess.target.arch == "arm" {
sess.opts.cg.soft_float
let float_abi = if sess.target.arch == "arm" && sess.opts.cg.soft_float {
llvm::FloatAbi::Soft
} else {
// `validate_commandline_args_with_session_available` has already warned about this being
// ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets.
false
to_llvm_float_abi(sess.target.llvm_floatabi)
};
let ffunction_sections =
@ -290,7 +298,7 @@ pub(crate) fn target_machine_factory(
code_model,
reloc_model,
opt_level,
use_softfp,
float_abi,
ffunction_sections,
fdata_sections,
funique_section_names,
@ -529,9 +537,35 @@ pub(crate) unsafe fn llvm_optimize(
config: &ModuleConfig,
opt_level: config::OptLevel,
opt_stage: llvm::OptStage,
skip_size_increasing_opts: bool,
) -> Result<(), FatalError> {
let unroll_loops =
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
// Enzyme:
// The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized
// source code. However, benchmarks show that optimizations increasing the code size
// tend to reduce AD performance. Therefore deactivate them before AD, then differentiate the code
// and finally re-optimize the module, now with all optimizations available.
// FIXME(ZuseZ4): In a future update we could figure out how to only optimize individual functions getting
// differentiated.
let unroll_loops;
let vectorize_slp;
let vectorize_loop;
// When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
// optimizations until after differentiation. FIXME(ZuseZ4): Before shipping on nightly,
// we should make this more granular, or at least check that the user has at least one autodiff
// call in their code, to justify altering the compilation pipeline.
if skip_size_increasing_opts && cfg!(llvm_enzyme) {
unroll_loops = false;
vectorize_slp = false;
vectorize_loop = false;
} else {
unroll_loops =
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
vectorize_slp = config.vectorize_slp;
vectorize_loop = config.vectorize_loop;
}
trace!(?unroll_loops, ?vectorize_slp, ?vectorize_loop);
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
let pgo_gen_path = get_pgo_gen_path(config);
let pgo_use_path = get_pgo_use_path(config);
@ -595,8 +629,8 @@ pub(crate) unsafe fn llvm_optimize(
using_thin_buffers,
config.merge_functions,
unroll_loops,
config.vectorize_slp,
config.vectorize_loop,
vectorize_slp,
vectorize_loop,
config.no_builtins,
config.emit_lifetime_markers,
sanitizer_options.as_ref(),
@ -640,6 +674,8 @@ pub(crate) unsafe fn optimize(
unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) };
}
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
if let Some(opt_level) = config.opt_level {
let opt_stage = match cgcx.lto {
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
@ -647,7 +683,20 @@ pub(crate) unsafe fn optimize(
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
_ => llvm::OptStage::PreLinkNoLTO,
};
return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) };
// If we know that we will later run AD, then we disable vectorization and loop unrolling
let skip_size_increasing_opts = cfg!(llvm_enzyme);
return unsafe {
llvm_optimize(
cgcx,
dcx,
module,
config,
opt_level,
opt_stage,
skip_size_increasing_opts,
)
};
}
Ok(())
}

View file

@ -2,6 +2,8 @@ use std::borrow::Cow;
use std::ops::Deref;
use std::{iter, ptr};
pub(crate) mod autodiff;
use libc::{c_char, c_uint};
use rustc_abi as abi;
use rustc_abi::{Align, Size, WrappingRange};
@ -608,14 +610,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
if self.sess().target.arch == "amdgpu" {
// amdgpu/LLVM does something weird and thinks an i64 value is
// split into a v2i32, halving the bitwidth LLVM expects,
// tripping an assertion. So, for now, just disable this
// optimization.
return;
}
if self.cx.sess().opts.optimize == OptLevel::No {
// Don't emit metadata we're not going to use
return;

View file

@ -0,0 +1,344 @@
use std::ptr;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::back::write::ModuleConfig;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_errors::FatalError;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::Lto;
use tracing::{debug, trace};
use crate::back::write::{llvm_err, llvm_optimize};
use crate::builder::Builder;
use crate::declare::declare_raw_fn;
use crate::errors::LlvmError;
use crate::llvm::AttributePlace::Function;
use crate::llvm::{Metadata, True};
use crate::value::Value;
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, context, llvm};
fn get_params(fnc: &Value) -> Vec<&Value> {
unsafe {
let param_num = llvm::LLVMCountParams(fnc) as usize;
let mut fnc_args: Vec<&Value> = vec![];
fnc_args.reserve(param_num);
llvm::LLVMGetParams(fnc, fnc_args.as_mut_ptr());
fnc_args.set_len(param_num);
fnc_args
}
}
/// When differentiating `fn_to_diff`, take a `outer_fn` and generate another
/// function with expected naming and calling conventions[^1] which will be
/// discovered by the enzyme LLVM pass and its body populated with the differentiated
/// `fn_to_diff`. `outer_fn` is then modified to have a call to the generated
/// function and handle the differences between the Rust calling convention and
/// Enzyme.
/// [^1]: <https://enzyme.mit.edu/getting_started/CallingConvention/>
// FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to
// cover some assumptions of enzyme/autodiff, which could lead to UB otherwise.
fn generate_enzyme_call<'ll, 'tcx>(
cx: &context::CodegenCx<'ll, 'tcx>,
fn_to_diff: &'ll Value,
outer_fn: &'ll Value,
attrs: AutoDiffAttrs,
) {
let inputs = attrs.input_activity;
let output = attrs.ret_activity;
// We have to pick the name depending on whether we want forward or reverse mode autodiff.
// FIXME(ZuseZ4): The new pass based approach should not need the {Forward/Reverse}First method anymore, since
// it will handle higher-order derivatives correctly automatically (in theory). Currently
// higher-order derivatives fail, so we should debug that before adjusting this code.
let mut ad_name: String = match attrs.mode {
DiffMode::Forward => "__enzyme_fwddiff",
DiffMode::Reverse => "__enzyme_autodiff",
DiffMode::ForwardFirst => "__enzyme_fwddiff",
DiffMode::ReverseFirst => "__enzyme_autodiff",
_ => panic!("logic bug in autodiff, unrecognized mode"),
}
.to_string();
// add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple
// functions. Unwrap will only panic, if LLVM gave us an invalid string.
let name = llvm::get_value_name(outer_fn);
let outer_fn_name = std::ffi::CStr::from_bytes_with_nul(name).unwrap().to_str().unwrap();
ad_name.push_str(outer_fn_name.to_string().as_str());
// Let us assume the user wrote the following function square:
//
// ```llvm
// define double @square(double %x) {
// entry:
// %0 = fmul double %x, %x
// ret double %0
// }
// ```
//
// The user now applies autodiff to the function square, in which case fn_to_diff will be `square`.
// Our macro generates the following placeholder code (slightly simplified):
//
// ```llvm
// define double @dsquare(double %x) {
// ; placeholder code
// return 0.0;
// }
// ```
//
// so our `outer_fn` will be `dsquare`. The unsafe code section below now removes the placeholder
// code and inserts an autodiff call. We also add a declaration for the __enzyme_autodiff call.
// Again, the arguments to all functions are slightly simplified.
// ```llvm
// declare double @__enzyme_autodiff_square(...)
//
// define double @dsquare(double %x) {
// entry:
// %0 = tail call double (...) @__enzyme_autodiff_square(double (double)* nonnull @square, double %x)
// ret double %0
// }
// ```
unsafe {
// On LLVM-IR, we can luckily declare __enzyme_ functions without specifying the input
// arguments. We do however need to declare them with their correct return type.
// We already figured the correct return type out in our frontend, when generating the outer_fn,
// so we can now just go ahead and use that. FIXME(ZuseZ4): This doesn't handle sret yet.
let fn_ty = llvm::LLVMGlobalGetValueType(outer_fn);
let ret_ty = llvm::LLVMGetReturnType(fn_ty);
// LLVM can figure out the input types on it's own, so we take a shortcut here.
let enzyme_ty = llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True);
//FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and
// think a bit more about what should go here.
let cc = llvm::LLVMGetFunctionCallConv(outer_fn);
let ad_fn = declare_raw_fn(
cx,
&ad_name,
llvm::CallConv::try_from(cc).expect("invalid callconv"),
llvm::UnnamedAddr::No,
llvm::Visibility::Default,
enzyme_ty,
);
// Otherwise LLVM might inline our temporary code before the enzyme pass has a chance to
// do it's work.
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
// first, remove all calls from fnc
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
let br = llvm::LLVMRustGetTerminator(entry);
llvm::LLVMRustEraseInstFromParent(br);
let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap();
let mut builder = Builder::build(cx, entry);
let num_args = llvm::LLVMCountParams(&fn_to_diff);
let mut args = Vec::with_capacity(num_args as usize + 1);
args.push(fn_to_diff);
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap();
match output {
DiffActivity::Dual => {
args.push(cx.get_metadata_value(enzyme_primal_ret));
}
DiffActivity::Active => {
args.push(cx.get_metadata_value(enzyme_primal_ret));
}
_ => {}
}
trace!("matching autodiff arguments");
// We now handle the issue that Rust level arguments not always match the llvm-ir level
// arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on
// llvm-ir level. The number of activities matches the number of Rust level arguments, so we
// need to match those.
// FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it
// using iterators and peek()?
let mut outer_pos: usize = 0;
let mut activity_pos = 0;
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
while activity_pos < inputs.len() {
let activity = inputs[activity_pos as usize];
// Duplicated arguments received a shadow argument, into which enzyme will write the
// gradient.
let (activity, duplicated): (&Metadata, bool) = match activity {
DiffActivity::None => panic!("not a valid input activity"),
DiffActivity::Const => (enzyme_const, false),
DiffActivity::Active => (enzyme_out, false),
DiffActivity::ActiveOnly => (enzyme_out, false),
DiffActivity::Dual => (enzyme_dup, true),
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
DiffActivity::Duplicated => (enzyme_dup, true),
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
DiffActivity::FakeActivitySize => (enzyme_const, false),
};
let outer_arg = outer_args[outer_pos];
args.push(cx.get_metadata_value(activity));
args.push(outer_arg);
if duplicated {
// We know that duplicated args by construction have a following argument,
// so this can not be out of bounds.
let next_outer_arg = outer_args[outer_pos + 1];
let next_outer_ty = cx.val_ty(next_outer_arg);
// FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since
// vectors behind references (&Vec<T>) are already supported. Users can not pass a
// Vec by value for reverse mode, so this would only help forward mode autodiff.
let slice = {
if activity_pos + 1 >= inputs.len() {
// If there is no arg following our ptr, it also can't be a slice,
// since that would lead to a ptr, int pair.
false
} else {
let next_activity = inputs[activity_pos + 1];
// We analyze the MIR types and add this dummy activity if we visit a slice.
next_activity == DiffActivity::FakeActivitySize
}
};
if slice {
// A duplicated slice will have the following two outer_fn arguments:
// (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call:
// (..., metadata! enzyme_dup, ptr, ptr, int1, ...).
// FIXME(ZuseZ4): We will upstream a safety check later which asserts that
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer);
let next_outer_arg2 = outer_args[outer_pos + 2];
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer);
let next_outer_arg3 = outer_args[outer_pos + 3];
let next_outer_ty3 = cx.val_ty(next_outer_arg3);
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer);
args.push(next_outer_arg2);
args.push(cx.get_metadata_value(enzyme_const));
args.push(next_outer_arg);
outer_pos += 4;
activity_pos += 2;
} else {
// A duplicated pointer will have the following two outer_fn arguments:
// (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call:
// (..., metadata! enzyme_dup, ptr, ptr, ...).
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer);
args.push(next_outer_arg);
outer_pos += 2;
activity_pos += 1;
}
} else {
// We do not differentiate with resprect to this argument.
// We already added the metadata and argument above, so just increase the counters.
outer_pos += 1;
activity_pos += 1;
}
}
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
// This part is a bit iffy. LLVM requires that a call to an inlineable function has some
// metadata attachted to it, but we just created this code oota. Given that the
// differentiated function already has partly confusing metadata, and given that this
// affects nothing but the auttodiff IR, we take a shortcut and just steal metadata from the
// dummy code which we inserted at a higher level.
// FIXME(ZuseZ4): Work with Enzyme core devs to clarify what debug metadata issues we have,
// and how to best improve it for enzyme core and rust-enzyme.
let md_ty = cx.get_md_kind_id("dbg");
if llvm::LLVMRustHasMetadata(last_inst, md_ty) {
let md = llvm::LLVMRustDIGetInstMetadata(last_inst)
.expect("failed to get instruction metadata");
let md_todiff = cx.get_metadata_value(md);
llvm::LLVMSetMetadata(call, md_ty, md_todiff);
} else {
// We don't panic, since depending on whether we are in debug or release mode, we might
// have no debug info to copy, which would then be ok.
trace!("no dbg info");
}
// Now that we copied the metadata, get rid of dummy code.
llvm::LLVMRustEraseInstBefore(entry, last_inst);
llvm::LLVMRustEraseInstFromParent(last_inst);
if cx.val_ty(outer_fn) != cx.type_void() {
builder.ret(call);
} else {
builder.ret_void();
}
// Let's crash in case that we messed something up above and generated invalid IR.
llvm::LLVMRustVerifyFunction(
outer_fn,
llvm::LLVMRustVerifierFailureAction::LLVMAbortProcessAction,
);
}
}
pub(crate) fn differentiate<'ll, 'tcx>(
module: &'ll ModuleCodegen<ModuleLlvm>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
tcx: TyCtxt<'tcx>,
diff_items: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
for item in &diff_items {
trace!("{}", item);
}
let diag_handler = cgcx.create_dcx();
let (_, cgus) = tcx.collect_and_partition_mono_items(());
let cx = context::CodegenCx::new(tcx, &cgus.first().unwrap(), &module.module_llvm);
// Before dumping the module, we want all the TypeTrees to become part of the module.
for item in diff_items.iter() {
let name = item.source.clone();
let fn_def: Option<&llvm::Value> = cx.get_function(&name);
let Some(fn_def) = fn_def else {
return Err(llvm_err(diag_handler.handle(), LlvmError::PrepareAutoDiff {
src: item.source.clone(),
target: item.target.clone(),
error: "could not find source function".to_owned(),
}));
};
debug!(?item.target);
let fn_target: Option<&llvm::Value> = cx.get_function(&item.target);
let Some(fn_target) = fn_target else {
return Err(llvm_err(diag_handler.handle(), LlvmError::PrepareAutoDiff {
src: item.source.clone(),
target: item.target.clone(),
error: "could not find target function".to_owned(),
}));
};
generate_enzyme_call(&cx, fn_def, fn_target, item.attrs.clone());
}
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
if let Some(opt_level) = config.opt_level {
let opt_stage = match cgcx.lto {
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
_ => llvm::OptStage::PreLinkNoLTO,
};
// This is our second opt call, so now we run all opts,
// to make sure we get the best performance.
let skip_size_increasing_opts = false;
trace!("running Module Optimization after differentiation");
unsafe {
llvm_optimize(
cgcx,
diag_handler.handle(),
module,
config,
opt_level,
opt_stage,
skip_size_increasing_opts,
)?
};
}
trace!("done with differentiate()");
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::ffi::{CStr, c_uint};
use std::ffi::{CStr, c_char, c_uint};
use std::str;
use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
@ -600,6 +600,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::set_section(g, c"llvm.metadata");
}
}
pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
}
pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) }
}
pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 {
unsafe {
llvm::LLVMGetMDKindIDInContext(
self.llcx,
name.as_ptr() as *const c_char,
name.len() as c_uint,
)
}
}
pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
Some(unsafe {
llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
})
}
}
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {

View file

@ -32,7 +32,7 @@ use crate::{attributes, llvm};
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
fn declare_raw_fn<'ll>(
pub(crate) fn declare_raw_fn<'ll>(
cx: &CodegenCx<'ll, '_>,
name: &str,
callconv: llvm::CallConv,

View file

@ -89,6 +89,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
}
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_without_lto)]
#[note]
pub(crate) struct AutoDiffWithoutLTO;
#[derive(Diagnostic)]
#[diag(codegen_llvm_lto_disallowed)]
pub(crate) struct LtoDisallowed;
@ -131,6 +136,8 @@ pub enum LlvmError<'a> {
PrepareThinLtoModule,
#[diag(codegen_llvm_parse_bitcode)]
ParseBitcode,
#[diag(codegen_llvm_prepare_autodiff)]
PrepareAutoDiff { src: String, target: String, error: String },
}
pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
@ -152,6 +159,7 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
}
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
PrepareAutoDiff { .. } => fluent::codegen_llvm_prepare_autodiff_with_llvm_err,
};
self.0
.into_diag(dcx, level)

View file

@ -28,9 +28,10 @@ use std::mem::ManuallyDrop;
use back::owned_target_machine::OwnedTargetMachine;
use back::write::{create_informational_target_machine, create_target_machine};
use errors::ParseTargetMachineConfig;
use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
pub use llvm_util::target_features_cfg;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
@ -44,7 +45,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::Providers;
use rustc_session::Session;
use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest};
use rustc_span::Symbol;
mod back {
@ -233,6 +234,20 @@ impl WriteBackendMethods for LlvmCodegenBackend {
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
}
/// Generate autodiff rules
fn autodiff(
cgcx: &CodegenContext<Self>,
tcx: TyCtxt<'_>,
module: &ModuleCodegen<Self::Module>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
if cgcx.lto != Lto::Fat {
let dcx = cgcx.create_dcx();
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
}
builder::autodiff::differentiate(module, cgcx, tcx, diff_fncs, config)
}
}
unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis

View file

@ -0,0 +1,29 @@
#![allow(non_camel_case_types)]
use libc::{c_char, c_uint};
use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
use crate::llvm::Bool;
extern "C" {
// Enzyme
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
pub fn LLVMRustEraseInstBefore(BB: &BasicBlock, I: &Value);
pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
pub fn LLVMRustEraseInstFromParent(V: &Value);
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
pub fn LLVMGetReturnType(T: &Type) -> &Type;
pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
pub fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
}
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum LLVMRustVerifierFailureAction {
LLVMAbortProcessAction = 0,
LLVMPrintMessageAction = 1,
LLVMReturnStatusAction = 2,
}

View file

@ -99,7 +99,7 @@ pub enum ModuleFlagMergeBehavior {
/// LLVM CallingConv::ID. Should we wrap this?
///
/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h>
#[derive(Copy, Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Debug, TryFromU32)]
#[repr(C)]
pub enum CallConv {
CCallConv = 0,
@ -526,7 +526,7 @@ pub struct SanitizerOptions {
pub sanitize_kernel_address_recover: bool,
}
/// LLVMRelocMode
/// LLVMRustRelocModel
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum RelocModel {
@ -538,6 +538,15 @@ pub enum RelocModel {
ROPI_RWPI,
}
/// LLVMRustFloatABI
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum FloatAbi {
Default,
Soft,
Hard,
}
/// LLVMRustCodeModel
#[derive(Copy, Clone)]
#[repr(C)]
@ -2192,7 +2201,7 @@ unsafe extern "C" {
Model: CodeModel,
Reloc: RelocModel,
Level: CodeGenOptLevel,
UseSoftFP: bool,
FloatABIType: FloatAbi,
FunctionSections: bool,
DataSections: bool,
UniqueSectionNames: bool,

View file

@ -22,8 +22,11 @@ use crate::common::AsCCharPtr;
pub mod archive_ro;
pub mod diagnostic;
pub mod enzyme_ffi;
mod ffi;
pub use self::enzyme_ffi::*;
impl LLVMRustResult {
pub fn into_result(self) -> Result<(), ()> {
match self {

View file

@ -1,11 +1,14 @@
use std::ffi::CString;
use std::sync::Arc;
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_data_structures::memmap::Mmap;
use rustc_errors::FatalError;
use rustc_middle::ty::TyCtxt;
use super::write::CodegenContext;
use crate::ModuleCodegen;
use crate::back::write::ModuleConfig;
use crate::traits::*;
pub struct ThinModule<B: WriteBackendMethods> {
@ -81,6 +84,24 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
LtoModuleCodegen::Thin(ref m) => m.cost(),
}
}
/// Run autodiff on Fat LTO module
pub unsafe fn autodiff(
self,
cgcx: &CodegenContext<B>,
tcx: TyCtxt<'_>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<LtoModuleCodegen<B>, FatalError> {
match &self {
LtoModuleCodegen::Fat(module) => {
B::autodiff(cgcx, tcx, &module, diff_fncs, config)?;
}
_ => panic!("autodiff called with non-fat LTO module"),
}
Ok(self)
}
}
pub enum SerializedModule<M: ModuleBufferMethods> {

View file

@ -1,5 +1,7 @@
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_errors::{DiagCtxtHandle, FatalError};
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::ty::TyCtxt;
use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
@ -61,6 +63,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
want_summary: bool,
) -> (String, Self::ThinBuffer);
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
fn autodiff(
cgcx: &CodegenContext<Self>,
tcx: TyCtxt<'_>,
module: &ModuleCodegen<Self::Module>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<(), FatalError>;
}
pub trait ThinBufferMethods: Send + Sync {

View file

@ -2,7 +2,7 @@
//! Primarily used to extract a backtrace from stack overflow
use std::alloc::{Layout, alloc};
use std::{fmt, mem, ptr};
use std::{fmt, mem, ptr, slice};
use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
@ -35,20 +35,22 @@ macro raw_errln($tokens:tt) {
}
/// Signal handler installed for SIGSEGV
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#[allow(static_mut_refs)]
extern "C" fn print_stack_trace(_: libc::c_int) {
///
/// # Safety
///
/// Caller must ensure that this function is not re-entered.
unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
const MAX_FRAMES: usize = 256;
// Reserve data segment so we don't have to malloc in a signal handler, which might fail
// in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
let stack = unsafe {
// Reserve data segment so we don't have to malloc in a signal handler, which might fail
// in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
// Collect return addresses
let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
let depth = libc::backtrace(&raw mut STACK_TRACE as _, MAX_FRAMES as i32);
if depth == 0 {
return;
}
&STACK_TRACE.as_slice()[0..(depth as _)]
slice::from_raw_parts(&raw const STACK_TRACE as _, depth as _)
};
// Just a stack trace is cryptic. Explain what we're doing.

View file

@ -357,9 +357,9 @@ impl From<Cow<'static, str>> for DiagMessage {
/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be
/// able to convert between these, as much as they'll be converted back into `DiagMessage`
/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
impl Into<SubdiagMessage> for DiagMessage {
fn into(self) -> SubdiagMessage {
match self {
impl From<DiagMessage> for SubdiagMessage {
fn from(val: DiagMessage) -> Self {
match val {
DiagMessage::Str(s) => SubdiagMessage::Str(s),
DiagMessage::Translated(s) => SubdiagMessage::Translated(s),
DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id),

View file

@ -156,9 +156,9 @@ impl IntoDiagArg for DiagArgValue {
}
}
impl Into<FluentValue<'static>> for DiagArgValue {
fn into(self) -> FluentValue<'static> {
match self {
impl From<DiagArgValue> for FluentValue<'static> {
fn from(val: DiagArgValue) -> Self {
match val {
DiagArgValue::Str(s) => From::from(s),
DiagArgValue::Number(n) => From::from(n),
DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),

View file

@ -52,6 +52,13 @@ pub enum ParamName {
/// Some user-given name like `T` or `'x`.
Plain(Ident),
/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors).
///
/// Occurs when, e.g., `'_` is used in the wrong place, or a
/// lifetime name is duplicated.
Error(Ident),
/// Synthetic name generated when user elided a lifetime in an impl header.
///
/// E.g., the lifetimes in cases like these:
@ -67,18 +74,13 @@ pub enum ParamName {
/// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous.
Fresh,
/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs
/// when, e.g., `'_` is used in the wrong place.
Error,
}
impl ParamName {
pub fn ident(&self) -> Ident {
match *self {
ParamName::Plain(ident) => ident,
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
ParamName::Plain(ident) | ParamName::Error(ident) => ident,
ParamName::Fresh => Ident::with_dummy_span(kw::UnderscoreLifetime),
}
}
}
@ -4072,33 +4074,33 @@ impl<'hir> OwnerNode<'hir> {
}
}
impl<'hir> Into<OwnerNode<'hir>> for &'hir Item<'hir> {
fn into(self) -> OwnerNode<'hir> {
OwnerNode::Item(self)
impl<'hir> From<&'hir Item<'hir>> for OwnerNode<'hir> {
fn from(val: &'hir Item<'hir>) -> Self {
OwnerNode::Item(val)
}
}
impl<'hir> Into<OwnerNode<'hir>> for &'hir ForeignItem<'hir> {
fn into(self) -> OwnerNode<'hir> {
OwnerNode::ForeignItem(self)
impl<'hir> From<&'hir ForeignItem<'hir>> for OwnerNode<'hir> {
fn from(val: &'hir ForeignItem<'hir>) -> Self {
OwnerNode::ForeignItem(val)
}
}
impl<'hir> Into<OwnerNode<'hir>> for &'hir ImplItem<'hir> {
fn into(self) -> OwnerNode<'hir> {
OwnerNode::ImplItem(self)
impl<'hir> From<&'hir ImplItem<'hir>> for OwnerNode<'hir> {
fn from(val: &'hir ImplItem<'hir>) -> Self {
OwnerNode::ImplItem(val)
}
}
impl<'hir> Into<OwnerNode<'hir>> for &'hir TraitItem<'hir> {
fn into(self) -> OwnerNode<'hir> {
OwnerNode::TraitItem(self)
impl<'hir> From<&'hir TraitItem<'hir>> for OwnerNode<'hir> {
fn from(val: &'hir TraitItem<'hir>) -> Self {
OwnerNode::TraitItem(val)
}
}
impl<'hir> Into<Node<'hir>> for OwnerNode<'hir> {
fn into(self) -> Node<'hir> {
match self {
impl<'hir> From<OwnerNode<'hir>> for Node<'hir> {
fn from(val: OwnerNode<'hir>) -> Self {
match val {
OwnerNode::Item(n) => Node::Item(n),
OwnerNode::ForeignItem(n) => Node::ForeignItem(n),
OwnerNode::ImplItem(n) => Node::ImplItem(n),

View file

@ -928,8 +928,8 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
) -> V::Result {
try_visit!(visitor.visit_id(param.hir_id));
match param.name {
ParamName::Plain(ident) => try_visit!(visitor.visit_ident(ident)),
ParamName::Error | ParamName::Fresh => {}
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
ParamName::Fresh => {}
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}

View file

@ -2007,7 +2007,10 @@ fn check_variances_for_type_defn<'tcx>(
}
match hir_param.name {
hir::ParamName::Error => {}
hir::ParamName::Error(_) => {
// Don't report a bivariance error for a lifetime that isn't
// even valid to name.
}
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
report_bivariance(tcx, hir_param, has_explicit_bounds, item);

View file

@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::infer;
use rustc_infer::traits::{self, Obligation, ObligationCause, ObligationCauseCode};
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_bound(
ty,
self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
traits::ObligationCause::new(sp, self.body_id, ObligationCauseCode::RustCall),
self.cause(sp, ObligationCauseCode::RustCall),
);
self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall);
} else {

View file

@ -580,11 +580,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let mut selcx = traits::SelectionContext::new(self);
// Create an obligation for `Source: CoerceUnsized<Target>`.
let cause =
ObligationCause::new(self.cause.span, self.body_id, ObligationCauseCode::Coercion {
source,
target,
});
let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target });
// Use a FIFO queue for this custom fulfillment procedure.
//

View file

@ -22,7 +22,6 @@ use rustc_hir::{ExprKind, HirId, QPath};
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
use rustc_infer::infer;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -1174,9 +1173,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for err in errors {
let cause = &mut err.obligation.cause;
if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {
let new_cause = ObligationCause::new(
let new_cause = self.cause(
cause.span,
cause.body_id,
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
);
*cause = new_cause;
@ -3856,7 +3854,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Enums are anyway always sized. But just to safeguard against future
// language extensions, let's double-check.
self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc);
self.require_type_is_sized(
field_ty,
expr.span,
ObligationCauseCode::FieldSized {
adt_kind: AdtKind::Enum,
span: self.tcx.def_span(field.did),
last: false,
},
);
if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
@ -3884,11 +3890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let field_ty = self.field_ty(expr.span, field, args);
if self.tcx.features().offset_of_slice() {
self.require_type_has_static_alignment(
field_ty,
expr.span,
ObligationCauseCode::Misc,
);
self.require_type_has_static_alignment(field_ty, expr.span);
} else {
self.require_type_is_sized(
field_ty,
@ -3917,11 +3919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if let Some(&field_ty) = tys.get(index) {
if self.tcx.features().offset_of_slice() {
self.require_type_has_static_alignment(
field_ty,
expr.span,
ObligationCauseCode::Misc,
);
self.require_type_has_static_alignment(field_ty, expr.span);
} else {
self.require_type_is_sized(
field_ty,

View file

@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
code: traits::ObligationCauseCode<'tcx>,
def_id: DefId,
) {
self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
self.register_bound(ty, def_id, self.cause(span, code));
}
pub(crate) fn require_type_is_sized(
@ -410,12 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
pub(crate) fn require_type_has_static_alignment(
&self,
ty: Ty<'tcx>,
span: Span,
code: traits::ObligationCauseCode<'tcx>,
) {
pub(crate) fn require_type_has_static_alignment(&self, ty: Ty<'tcx>, span: Span) {
if !ty.references_error() {
let tail = self.tcx.struct_tail_raw(
ty,
@ -434,7 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// We can't be sure, let's required full `Sized`.
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
self.require_type_meets(ty, span, code, lang_item);
self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item);
}
}
}
@ -572,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
code: traits::ObligationCauseCode<'tcx>,
) {
// WF obligations never themselves fail, so no real need to give a detailed cause:
let cause = traits::ObligationCause::new(span, self.body_id, code);
let cause = self.cause(span, code);
self.register_predicate(traits::Obligation::new(
self.tcx,
cause,
@ -1426,9 +1421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let bounds = self.instantiate_bounds(span, def_id, args);
for obligation in traits::predicates_for_generics(
|idx, predicate_span| {
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
},
|idx, predicate_span| self.cause(span, code(idx, predicate_span)),
param_env,
bounds,
) {
@ -1561,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
) -> InferResult<'tcx, Ty<'tcx>> {
self.instantiate_query_response_and_region_obligations(
&traits::ObligationCause::misc(span, self.body_id),
&self.misc(span),
self.param_env,
original_values,
query_result,

View file

@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_wf_obligation(
fn_input_ty.into(),
arg_expr.span,
ObligationCauseCode::Misc,
ObligationCauseCode::WellFormed(None),
);
}

View file

@ -601,7 +601,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.call_expr.hir_id,
idx,
);
traits::ObligationCause::new(self.span, self.body_id, code)
self.cause(self.span, code)
},
self.param_env,
method_predicates,

View file

@ -1739,8 +1739,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
trait_ref: ty::TraitRef<'tcx>,
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, trait_ref);
let obligation =
traits::Obligation::new(self.tcx, self.misc(self.span), self.param_env, trait_ref);
traits::SelectionContext::new(self).select(&obligation)
}
@ -1841,7 +1841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.scope_expr_id,
idx,
);
ObligationCause::new(self.span, self.body_id, code)
self.cause(self.span, code)
},
self.param_env,
impl_bounds,

View file

@ -105,8 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
};
let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]);
let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::Misc);
let obligation = Obligation::new(self.tcx, cause, self.param_env, trait_ref);
let obligation = Obligation::new(self.tcx, self.misc(span), self.param_env, trait_ref);
if !self.predicate_must_hold_modulo_regions(&obligation) {
return false;
}
@ -3489,7 +3488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pred = ty::TraitRef::new(self.tcx, unpin_trait, [*rcvr_ty]);
let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
self.tcx,
ObligationCause::misc(rcvr.span, self.body_id),
self.misc(rcvr.span),
self.param_env,
pred,
));

View file

@ -1,9 +1,11 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diag;
use rustc_errors::{Applicability, Diag};
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::Symbol;
use rustc_span::def_id::DefId;
use rustc_span::symbol::sym;
use crate::{LateContext, LateLintPass};
@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
let hir_id = cx.tcx.local_def_id_to_hir_id(local);
let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
mk_lint(diag, orig_fields, fields);
mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
});
}
}
fn mk_lint(
tcx: TyCtxt<'_>,
diag: &mut Diag<'_, ()>,
type_def_id: DefId,
impl_def_id: DefId,
orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
fields: &[hir::ExprField<'_>],
) {
@ -175,11 +180,24 @@ fn mk_lint(
}
}
diag.help(if removed_all_fields {
"to avoid divergence in behavior between `Struct { .. }` and \
`<Struct as Default>::default()`, derive the `Default`"
if removed_all_fields {
let msg = "to avoid divergence in behavior between `Struct { .. }` and \
`<Struct as Default>::default()`, derive the `Default`";
if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
diag.multipart_suggestion_verbose(
msg,
vec![
(tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
(impl_.span, String::new()),
],
Applicability::MachineApplicable,
);
} else {
diag.help(msg);
}
} else {
"use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \
diverging over time"
});
let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
avoid them diverging over time";
diag.help(msg);
}
}

View file

@ -82,7 +82,36 @@ impl HiddenUnicodeCodepoints {
sub,
});
}
fn check_literal(
&mut self,
cx: &EarlyContext<'_>,
text: Symbol,
lit_kind: ast::token::LitKind,
span: Span,
label: &'static str,
) {
if !contains_text_flow_control_chars(text.as_str()) {
return;
}
let (padding, point_at_inner_spans) = match lit_kind {
// account for `"` or `'`
ast::token::LitKind::Str | ast::token::LitKind::Char => (1, true),
// account for `c"`
ast::token::LitKind::CStr => (2, true),
// account for `r###"`
ast::token::LitKind::StrRaw(n) => (n as u32 + 2, true),
// account for `cr###"`
ast::token::LitKind::CStrRaw(n) => (n as u32 + 3, true),
// suppress bad literals.
ast::token::LitKind::Err(_) => return,
// Be conservative just in case new literals do support these.
_ => (0, false),
};
self.lint_text_direction_codepoint(cx, text, span, padding, point_at_inner_spans, label);
}
}
impl EarlyLintPass for HiddenUnicodeCodepoints {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if let ast::AttrKind::DocComment(_, comment) = attr.kind {
@ -97,18 +126,11 @@ impl EarlyLintPass for HiddenUnicodeCodepoints {
// byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
match &expr.kind {
ast::ExprKind::Lit(token_lit) => {
let text = token_lit.symbol;
if !contains_text_flow_control_chars(text.as_str()) {
return;
}
let padding = match token_lit.kind {
// account for `"` or `'`
ast::token::LitKind::Str | ast::token::LitKind::Char => 1,
// account for `r###"`
ast::token::LitKind::StrRaw(n) => n as u32 + 2,
_ => return,
};
self.lint_text_direction_codepoint(cx, text, expr.span, padding, true, "literal");
self.check_literal(cx, token_lit.symbol, token_lit.kind, expr.span, "literal");
}
ast::ExprKind::FormatArgs(args) => {
let (lit_kind, text) = args.uncooked_fmt_str;
self.check_literal(cx, text, lit_kind, args.span, "format string");
}
_ => {}
};

View file

@ -308,6 +308,24 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
report_fatal_error("Bad RelocModel.");
}
enum class LLVMRustFloatABI {
Default,
Soft,
Hard,
};
static FloatABI::ABIType fromRust(LLVMRustFloatABI RustFloatAbi) {
switch (RustFloatAbi) {
case LLVMRustFloatABI::Default:
return FloatABI::Default;
case LLVMRustFloatABI::Soft:
return FloatABI::Soft;
case LLVMRustFloatABI::Hard:
return FloatABI::Hard;
}
report_fatal_error("Bad FloatABI.");
}
/// getLongestEntryLength - Return the length of the longest entry in the table.
template <typename KV> static size_t getLongestEntryLength(ArrayRef<KV> Table) {
size_t MaxLen = 0;
@ -358,7 +376,7 @@ extern "C" const char *LLVMRustGetHostCPUName(size_t *OutLen) {
extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
const char *TripleStr, const char *CPU, const char *Feature,
const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc,
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
LLVMRustCodeGenOptLevel RustOptLevel, LLVMRustFloatABI RustFloatABIType,
bool FunctionSections, bool DataSections, bool UniqueSectionNames,
bool TrapUnreachable, bool Singlethread, bool VerboseAsm,
bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
@ -369,6 +387,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
auto OptLevel = fromRust(RustOptLevel);
auto RM = fromRust(RustReloc);
auto CM = fromRust(RustCM);
auto FloatABIType = fromRust(RustFloatABIType);
std::string Error;
auto Trip = Triple(Triple::normalize(TripleStr));
@ -381,10 +400,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Trip);
Options.FloatABIType = FloatABI::Default;
if (UseSoftFloat) {
Options.FloatABIType = FloatABI::Soft;
}
Options.FloatABIType = FloatABIType;
Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections;
Options.UniqueSectionNames = UniqueSectionNames;

View file

@ -1,5 +1,6 @@
#include "LLVMWrapper.h"
#include "llvm-c/Analysis.h"
#include "llvm-c/Core.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@ -165,6 +166,30 @@ extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name,
return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen)));
}
enum class LLVMRustVerifierFailureAction {
AbortProcessAction = 0,
PrintMessageAction = 1,
ReturnStatusAction = 2,
};
static LLVMVerifierFailureAction
fromRust(LLVMRustVerifierFailureAction Action) {
switch (Action) {
case LLVMRustVerifierFailureAction::AbortProcessAction:
return LLVMAbortProcessAction;
case LLVMRustVerifierFailureAction::PrintMessageAction:
return LLVMPrintMessageAction;
case LLVMRustVerifierFailureAction::ReturnStatusAction:
return LLVMReturnStatusAction;
}
report_fatal_error("Invalid LLVMVerifierFailureAction value!");
}
extern "C" LLVMBool
LLVMRustVerifyFunction(LLVMValueRef Fn, LLVMRustVerifierFailureAction Action) {
return LLVMVerifyFunction(Fn, fromRust(Action));
}
enum class LLVMRustTailCallKind {
None,
Tail,
@ -388,6 +413,17 @@ extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr,
AddAttributes(Call, Index, Attrs, AttrsLen);
}
extern "C" LLVMValueRef LLVMRustGetTerminator(LLVMBasicBlockRef BB) {
Instruction *ret = unwrap(BB)->getTerminator();
return wrap(ret);
}
extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) {
I->eraseFromParent();
}
}
extern "C" LLVMAttributeRef
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
@ -954,6 +990,47 @@ extern "C" void LLVMRustAddModuleFlagString(
MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen)));
}
extern "C" LLVMValueRef LLVMRustGetLastInstruction(LLVMBasicBlockRef BB) {
auto Point = unwrap(BB)->rbegin();
if (Point != unwrap(BB)->rend())
return wrap(&*Point);
return nullptr;
}
extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
auto &BB = *unwrap(bb);
auto &Inst = *unwrap<Instruction>(I);
auto It = BB.begin();
while (&*It != &Inst)
++It;
// Make sure we found the Instruction.
assert(It != BB.end());
// We don't want to erase the instruction itself.
It--;
// Delete in rev order to ensure no dangling references.
while (It != BB.begin()) {
auto Prev = std::prev(It);
It->eraseFromParent();
It = Prev;
}
It->eraseFromParent();
}
extern "C" bool LLVMRustHasMetadata(LLVMValueRef inst, unsigned kindID) {
if (auto *I = dyn_cast<Instruction>(unwrap<Value>(inst))) {
return I->hasMetadata(kindID);
}
return false;
}
extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
if (auto *I = dyn_cast<Instruction>(unwrap<Value>(x))) {
auto *MD = I->getDebugLoc().getAsMDNode();
return wrap(MD);
}
return nullptr;
}
extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
LLVMMetadataRef MD) {
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));

View file

@ -303,9 +303,9 @@ pub(crate) struct RawDefId {
index: u32,
}
impl Into<RawDefId> for DefId {
fn into(self) -> RawDefId {
RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }
impl From<DefId> for RawDefId {
fn from(val: DefId) -> Self {
RawDefId { krate: val.krate.as_u32(), index: val.index.as_u32() }
}
}

View file

@ -88,10 +88,10 @@ impl ReportedErrorInfo {
}
}
impl Into<ErrorGuaranteed> for ReportedErrorInfo {
impl From<ReportedErrorInfo> for ErrorGuaranteed {
#[inline]
fn into(self) -> ErrorGuaranteed {
self.error
fn from(val: ReportedErrorInfo) -> Self {
val.error
}
}

View file

@ -16,12 +16,12 @@ use crate::ty::{self, GenericArgs, TyCtxt};
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, args);
@ -32,12 +32,12 @@ impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, args);
@ -201,12 +201,12 @@ impl<'tcx> TyCtxt<'tcx> {
impl<'tcx> TyCtxtEnsure<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self.tcx, def_id);
let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args));

View file

@ -249,9 +249,9 @@ pub enum AdtKind {
Enum,
}
impl Into<DataTypeKind> for AdtKind {
fn into(self) -> DataTypeKind {
match self {
impl From<AdtKind> for DataTypeKind {
fn from(val: AdtKind) -> Self {
match val {
AdtKind::Struct => DataTypeKind::Struct,
AdtKind::Union => DataTypeKind::Union,
AdtKind::Enum => DataTypeKind::Enum,

View file

@ -221,6 +221,11 @@ pub enum Suggestion {
/// Remove `r#` from identifier:
/// `format!("{r#foo}")` -> `format!("{foo}")`
RemoveRawIdent(InnerSpan),
/// Reorder format parameter:
/// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
/// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
/// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
ReorderFormatParameter(InnerSpan, string::String),
}
/// The parser structure for interpreting the input format string. This is
@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
}
} else if self.consume('?') {
spec.ty = "?";
if let Some(&(_, maybe)) = self.cur.peek() {
match maybe {
'#' | 'x' | 'X' => self.suggest_format_parameter(maybe),
_ => (),
}
}
} else {
spec.ty = self.word();
if !spec.ty.is_empty() {
@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
}
}
}
fn suggest_format_parameter(&mut self, c: char) {
let replacement = match c {
'#' => "#?",
'x' => "x?",
'X' => "X?",
_ => return,
};
let Some(pos) = self.consume_pos(c) else {
return;
};
let span = self.span(pos - 1, pos + 1);
let pos = self.to_span_index(pos);
self.errors.insert(0, ParseError {
description: format!("expected `}}`, found `{c}`"),
note: None,
label: "expected `'}'`".into(),
span: pos.to(pos),
secondary_label: None,
suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")),
})
}
}
/// Finds the indices of all characters that have been processed and differ between the actual

View file

@ -2,8 +2,8 @@ use std::borrow::Cow;
use std::env;
use crate::spec::{
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
TargetOptions, cvs,
Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType,
StaticCow, TargetOptions, cvs,
};
#[cfg(test)]
@ -105,6 +105,7 @@ pub(crate) fn base(
) -> (TargetOptions, StaticCow<str>, StaticCow<str>) {
let opts = TargetOptions {
abi: abi.target_abi().into(),
llvm_floatabi: Some(FloatAbi::Hard),
os: os.into(),
cpu: arch.target_cpu(abi).into(),
link_env_remove: link_env_remove(os),

View file

@ -116,6 +116,18 @@ impl Target {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, FloatAbi) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<super::FloatAbi>() {
Ok(float_abi) => base.$key_name = Some(float_abi),
_ => return Some(Err(format!("'{}' is not a valid value for \
llvm-floatabi. Use 'soft' or 'hard'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, RelocModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@ -598,6 +610,7 @@ impl Target {
key!(mcount = "target-mcount");
key!(llvm_mcount_intrinsic, optional);
key!(llvm_abiname);
key!(llvm_floatabi, FloatAbi)?;
key!(relax_elf_relocations, bool);
key!(llvm_args, list);
key!(use_ctors_section, bool);
@ -772,6 +785,7 @@ impl ToJson for Target {
target_option_val!(mcount, "target-mcount");
target_option_val!(llvm_mcount_intrinsic);
target_option_val!(llvm_abiname);
target_option_val!(llvm_floatabi);
target_option_val!(relax_elf_relocations);
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);

View file

@ -1085,6 +1085,35 @@ impl ToJson for CodeModel {
}
}
/// The float ABI setting to be configured in the LLVM target machine.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum FloatAbi {
Soft,
Hard,
}
impl FromStr for FloatAbi {
type Err = ();
fn from_str(s: &str) -> Result<FloatAbi, ()> {
Ok(match s {
"soft" => FloatAbi::Soft,
"hard" => FloatAbi::Hard,
_ => return Err(()),
})
}
}
impl ToJson for FloatAbi {
fn to_json(&self) -> Json {
match *self {
FloatAbi::Soft => "soft",
FloatAbi::Hard => "hard",
}
.to_json()
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TlsModel {
GeneralDynamic,
@ -2150,6 +2179,8 @@ pub struct TargetOptions {
pub env: StaticCow<str>,
/// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
/// or `"eabihf"`. Defaults to "".
/// This field is *not* forwarded directly to LLVM; its primary purpose is `cfg(target_abi)`.
/// However, parts of the backend do check this field for specific values to enable special behavior.
pub abi: StaticCow<str>,
/// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
pub vendor: StaticCow<str>,
@ -2446,8 +2477,17 @@ pub struct TargetOptions {
pub llvm_mcount_intrinsic: Option<StaticCow<str>>,
/// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
/// and the `-target-abi` flag in llc. In the LLVM API this is `MCOptions.ABIName`.
pub llvm_abiname: StaticCow<str>,
/// Control the float ABI to use, for architectures that support it. The only architecture we
/// currently use this for is ARM. Corresponds to the `-float-abi` flag in llc. In the LLVM API
/// this is `FloatABIType`. (clang's `-mfloat-abi` is similar but more complicated since it
/// can also affect the `soft-float` target feature.)
///
/// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`).
pub llvm_floatabi: Option<FloatAbi>,
/// Whether or not RelaxElfRelocation flag will be passed to the linker
pub relax_elf_relocations: bool,
@ -2719,6 +2759,7 @@ impl Default for TargetOptions {
mcount: "mcount".into(),
llvm_mcount_intrinsic: None,
llvm_abiname: "".into(),
llvm_floatabi: None,
relax_elf_relocations: false,
llvm_args: cvs![],
use_ctors_section: false,
@ -3153,7 +3194,8 @@ impl Target {
);
}
// Check that RISC-V targets always specify which ABI they use.
// Check that RISC-V targets always specify which ABI they use,
// and that ARM targets specify their float ABI.
match &*self.arch {
"riscv32" => {
check_matches!(
@ -3170,6 +3212,9 @@ impl Target {
"invalid RISC-V ABI name"
);
}
"arm" => {
check!(self.llvm_floatabi.is_some(), "ARM targets must specify their float ABI",)
}
_ => {}
}

View file

@ -1,4 +1,4 @@
use crate::spec::{SanitizerSet, Target, TargetOptions, base};
use crate::spec::{FloatAbi, SanitizerSet, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// https://developer.android.com/ndk/guides/abis.html#armeabi
features: "+strict-align,+v5te".into(),
supported_sanitizers: SanitizerSet::ADDRESS,

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+strict-align,+v6".into(),
max_atomic_width: Some(64),
mcount: "\u{1}__gnu_mcount_nc".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+strict-align,+v6,+vfp2,-d32".into(),
max_atomic_width: Some(64),
mcount: "\u{1}__gnu_mcount_nc".into(),

View file

@ -1,11 +1,8 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
// to determine the calling convention and float ABI, and it doesn't
// support the "musleabi" value.
llvm_target: "arm-unknown-linux-gnueabi".into(),
llvm_target: "arm-unknown-linux-musleabi".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv6 Linux with musl 1.2.3".into()),
tier: Some(2),
@ -17,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// Most of these settings are copied from the arm_unknown_linux_gnueabi
// target.
features: "+strict-align,+v6".into(),

View file

@ -1,11 +1,8 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
// uses it to determine the calling convention and float ABI, and it
// doesn't support the "musleabihf" value.
llvm_target: "arm-unknown-linux-gnueabihf".into(),
llvm_target: "arm-unknown-linux-musleabihf".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()),
tier: Some(2),
@ -17,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
// target.
features: "+strict-align,+v6,+vfp2,-d32".into(),

View file

@ -1,5 +1,5 @@
use crate::abi::Endian;
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+strict-align,+v8,+crc".into(),
endian: Endian::Big,
max_atomic_width: Some(64),

View file

@ -1,7 +1,9 @@
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
use crate::abi::Endian;
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
endian: Endian::Big,
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),

View file

@ -1,7 +1,9 @@
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
use crate::abi::Endian;
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
endian: Endian::Big,
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),

View file

@ -9,7 +9,9 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
};
pub(crate) fn target() -> Target {
Target {
@ -34,6 +36,7 @@ pub(crate) fn target() -> Target {
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,+strict-align".into(),
// Atomic operations provided by compiler-builtins
max_atomic_width: Some(32),

View file

@ -1,6 +1,6 @@
//! Targets the ARMv5TE, with code as `a32` code by default.
use crate::spec::{FramePointer, Target, TargetOptions, base, cvs};
use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking
// * use arch ARMv5TE

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,+strict-align".into(),
// Atomic operations provided by compiler-builtins
max_atomic_width: Some(32),

View file

@ -1,12 +1,8 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
// FIXME: this comment below does not seem applicable?
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
// uses it to determine the calling convention and float ABI, and LLVM
// doesn't support the "musleabihf" value.
llvm_target: "armv5te-unknown-linux-gnueabi".into(),
llvm_target: "armv5te-unknown-linux-musleabi".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv5TE Linux with musl 1.2.3".into()),
tier: Some(2),
@ -18,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,+strict-align".into(),
// Atomic operations provided by compiler-builtins
max_atomic_width: Some(32),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,+strict-align".into(),
// Atomic operations provided by compiler-builtins
max_atomic_width: Some(32),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+v6,+vfp2,-d32".into(),
max_atomic_width: Some(64),
mcount: "\u{1}__gnu_mcount_nc".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+v6,+vfp2,-d32".into(),
max_atomic_width: Some(64),
mcount: "__mcount".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
@ -28,8 +28,9 @@ pub(crate) fn target() -> Target {
os: "horizon".into(),
env: "newlib".into(),
vendor: "nintendo".into(),
abi: "eabihf".into(),
cpu: "mpcore".into(),
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
families: cvs!["unix"],
linker: Some("arm-none-eabi-gcc".into()),
relocation_model: RelocModel::Static,

View file

@ -1,4 +1,4 @@
use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions, base};
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions, base};
// This target if is for the baseline of the Android v7a ABI
// in thumb mode. It's named armv7-* instead of thumbv7-*
@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".into(),
supported_sanitizers: SanitizerSet::ADDRESS,
max_atomic_width: Some(64),

View file

@ -1,4 +1,6 @@
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
os: "rtems".into(),
families: cvs!["unix"],
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
linker: None,
relocation_model: RelocModel::Static,

View file

@ -1,5 +1,5 @@
use crate::abi::Endian;
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
/// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
///
@ -32,6 +32,7 @@ pub(crate) fn target() -> Target {
env: "newlib".into(),
vendor: "sony".into(),
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
no_default_libraries: false,
cpu: "cortex-a9".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}__gnu_mcount_nc".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
// hardfloat.
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb2,+soft-float,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}__gnu_mcount_nc".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for glibc Linux on ARMv7 without NEON or
// thumb-mode. See the thumbv7neon variant for enabling both.
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
// Info about features at https://wiki.debian.org/ArmHardFloatPort
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
max_atomic_width: Some(64),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for musl Linux on ARMv7 without thumb-mode, NEON or
// hardfloat.
@ -7,10 +7,7 @@ pub(crate) fn target() -> Target {
// Most of these settings are copied from the armv7_unknown_linux_gnueabi
// target.
Target {
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
// to determine the calling convention and float ABI, and it doesn't
// support the "musleabi" value.
llvm_target: "armv7-unknown-linux-gnueabi".into(),
llvm_target: "armv7-unknown-linux-musleabi".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv7-A Linux with musl 1.2.3".into()),
tier: Some(2),
@ -23,6 +20,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb2,+soft-float,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}mcount".into(),

View file

@ -1,13 +1,10 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for musl Linux on ARMv7 without thumb-mode or NEON.
pub(crate) fn target() -> Target {
Target {
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
// uses it to determine the calling convention and float ABI, and LLVM
// doesn't support the "musleabihf" value.
llvm_target: "armv7-unknown-linux-gnueabihf".into(),
llvm_target: "armv7-unknown-linux-musleabihf".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()),
tier: Some(2),
@ -22,6 +19,7 @@ pub(crate) fn target() -> Target {
// target.
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}mcount".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for OpenHarmony on ARMv7 Linux with thumb-mode, but no NEON or
// hardfloat.
@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb2,+soft-float,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}mcount".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for uclibc Linux on ARMv7 without NEON,
// thumb-mode or hardfloat.
@ -18,11 +18,12 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb2,+soft-float,-neon".into(),
cpu: "generic".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
abi: "eabi".into(),
..base
},
}

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
// This target is for uclibc Linux on ARMv7 without NEON or
// thumb-mode. See the thumbv7neon variant for enabling both.
@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
max_atomic_width: Some(64),
mcount: "_mcount".into(),
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
..base
},
}

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
max_atomic_width: Some(64),
mcount: "__mcount".into(),

View file

@ -1,4 +1,6 @@
use crate::spec::{LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions};
use crate::spec::{
FloatAbi, LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
features: "+v7,+thumb2,+soft-float,-neon".into(),
max_atomic_width: Some(64),
mcount: "\u{1}mcount".into(),

View file

@ -1,4 +1,4 @@
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
// Info about features at https://wiki.debian.org/ArmHardFloatPort
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
max_atomic_width: Some(64),

View file

@ -1,4 +1,4 @@
use crate::spec::{RelocModel, Target, TargetOptions, base};
use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
let base = base::solid::opts("asp3");
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
linker: Some("arm-kmc-eabi-gcc".into()),
features: "+v7,+soft-float,+thumb2,-neon".into(),
relocation_model: RelocModel::Static,

View file

@ -1,4 +1,4 @@
use crate::spec::{RelocModel, Target, TargetOptions, base};
use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
let base = base::solid::opts("asp3");
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
arch: "arm".into(),
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker: Some("arm-kmc-eabi-gcc".into()),
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
relocation_model: RelocModel::Static,

View file

@ -14,11 +14,14 @@
// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
// linking. rationale: matches `thumb` targets
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),

View file

@ -5,11 +5,14 @@
// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal
// `thumb` & `aarch64` targets.
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".into(),

View file

@ -1,6 +1,8 @@
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,

View file

@ -1,6 +1,8 @@
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,

View file

@ -1,6 +1,8 @@
// Targets the Little-endian Cortex-R52 processor (ARMv8-R)
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,

View file

@ -9,7 +9,9 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
use crate::spec::{FramePointer, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs};
use crate::spec::{
FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs,
};
pub(crate) fn target() -> Target {
Target {
@ -34,6 +36,7 @@ pub(crate) fn target() -> Target {
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking

View file

@ -1,6 +1,6 @@
//! Targets the ARMv5TE, with code as `t32` code by default.
use crate::spec::{FramePointer, Target, TargetOptions, base, cvs};
use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking
// * use arch ARMv5TE

View file

@ -1,6 +1,6 @@
// Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
use crate::spec::{Target, TargetOptions, base};
use crate::spec::{FloatAbi, Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
// with +strict-align.
// Also force-enable 32-bit atomics, which allows the use of atomic load/store only.

Some files were not shown because too many files have changed in this diff Show more