Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #96816

Merged
merged 23 commits into from
May 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a26cb61
Fix regression in link-to-definition introduced in #93803
GuillaumeGomez May 2, 2022
3dac70f
typeck: port "unconstrained opaque type" diag
davidtwco May 4, 2022
859079f
macros: allow `Vec` fields in diagnostic derive
davidtwco May 6, 2022
3f413d2
sess: add `create_{err,warning}`
davidtwco May 6, 2022
af47257
typeck: port "explicit generic args w/ impl trait"
davidtwco May 6, 2022
bd31ba0
make Size and Align debug-printing a bit more compact
RalfJung Apr 30, 2022
22cc6c3
don't debug-print ConstValue in MIR pretty-printer
RalfJung May 6, 2022
d455752
bless mir-opt
RalfJung May 6, 2022
5289bbe
Expand validator to be more precise on checked binary ops
JakobDegen May 6, 2022
5c7ce84
Remove unneeded SpanMapVisitor::visit_generics function
GuillaumeGomez May 6, 2022
fd6b01f
Add regression test for jump-to-def
GuillaumeGomez May 2, 2022
3bfa2eb
Add rustdoc documentation about unstable feature "jump to def"
GuillaumeGomez May 2, 2022
c4168fd
Check that field projections have the correct type
JakobDegen May 6, 2022
a8ede12
Change eslint rules from configuration comments to configuration files
Folyd May 7, 2022
59d5c20
update Miri
RalfJung May 7, 2022
7c1d241
Fix a minor typo in the description of Formatter
createyourpersonalaccount May 7, 2022
c29f857
Rollup merge of #96581 - RalfJung:debug-size-align, r=oli-obk
GuillaumeGomez May 7, 2022
3346d11
Rollup merge of #96636 - GuillaumeGomez:fix-jump-to-def-regression, r…
GuillaumeGomez May 7, 2022
a644197
Rollup merge of #96760 - davidtwco:diagnostic-translation-vec, r=oli-obk
GuillaumeGomez May 7, 2022
27a2bae
Rollup merge of #96788 - JakobDegen:checked-binop, r=oli-obk
GuillaumeGomez May 7, 2022
f98f92f
Rollup merge of #96805 - Folyd:eslint, r=GuillaumeGomez
GuillaumeGomez May 7, 2022
af2f944
Rollup merge of #96807 - RalfJung:miri, r=RalfJung
GuillaumeGomez May 7, 2022
c6007d6
Rollup merge of #96811 - createyourpersonalaccount:doc-typofix, r=Joh…
GuillaumeGomez May 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 96 additions & 4 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::AlwaysLiveLocals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
use rustc_target::abi::Size;
use rustc_target::abi::{Size, VariantIdx};

#[derive(Copy, Clone, Debug)]
enum EdgeKind {
Expand Down Expand Up @@ -244,6 +244,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(location, format!("bad index ({:?} != usize)", index_ty))
}
}
if let ProjectionElem::Field(f, ty) = elem {
let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds = |this: &Self, location| {
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
};
let check_equal = |this: &Self, location, f_ty| {
if !this.mir_assign_valid_types(ty, f_ty) {
this.fail(
location,
format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
parent, f, ty, f_ty
)
)
}
};
match parent_ty.ty.kind() {
ty::Tuple(fields) => {
let Some(f_ty) = fields.get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, *f_ty);
}
ty::Adt(adt_def, substs) => {
let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0));
let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, field.ty(self.tcx, substs));
}
ty::Closure(_, substs) => {
let substs = substs.as_closure();
let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, f_ty);
}
ty::Generator(_, substs, _) => {
let substs = substs.as_generator();
let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, f_ty);
}
_ => {
self.fail(location, format!("{:?} does not have fields", parent_ty.ty));
}
}
}
self.super_projection_elem(local, proj_base, elem, context, location);
}

Expand Down Expand Up @@ -291,7 +345,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ty::Array(..) | ty::Slice(..)
);
}
Rvalue::BinaryOp(op, vals) | Rvalue::CheckedBinaryOp(op, vals) => {
Rvalue::BinaryOp(op, vals) => {
use BinOp::*;
let a = vals.0.ty(&self.body.local_decls, self.tcx);
let b = vals.1.ty(&self.body.local_decls, self.tcx);
Expand Down Expand Up @@ -355,17 +409,55 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
for x in [a, b] {
check_kinds!(
x,
"Cannot perform op on type {:?}",
"Cannot perform arithmetic on type {:?}",
ty::Uint(..) | ty::Int(..) | ty::Float(..)
)
}
if a != b {
self.fail(
location,
format!("Cannot perform op on unequal types {:?} and {:?}", a, b),
format!(
"Cannot perform arithmetic on unequal types {:?} and {:?}",
a, b
),
);
}
}
}
}
Rvalue::CheckedBinaryOp(op, vals) => {
use BinOp::*;
let a = vals.0.ty(&self.body.local_decls, self.tcx);
let b = vals.1.ty(&self.body.local_decls, self.tcx);
match op {
Add | Sub | Mul => {
for x in [a, b] {
check_kinds!(
x,
"Cannot perform checked arithmetic on type {:?}",
ty::Uint(..) | ty::Int(..)
)
}
if a != b {
self.fail(
location,
format!(
"Cannot perform checked arithmetic on unequal types {:?} and {:?}",
a, b
),
);
}
}
Shl | Shr => {
for x in [a, b] {
check_kinds!(
x,
"Cannot perform checked shift on non-integer type {:?}",
ty::Uint(..) | ty::Int(..)
)
}
}
_ => self.fail(location, format!("There is no checked version of {:?}", op)),
}
}
Rvalue::UnaryOp(op, operand) => {
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/typeck.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,14 @@ typeck-add-return-type-missing-here = a return type might be missing here
typeck-expected-default-return-type = expected `()` because of default return type

typeck-expected-return-type = expected `{$expected}` because of return type

typeck-unconstrained-opaque-type = unconstrained opaque type
.note = `{$name}` must be used in combination with a concrete type within the same module

typeck-explicit-generic-args-with-impl-trait =
cannot provide explicit generic arguments when `impl Trait` is used in argument position
.label = explicit generic argument not allowed
.note = see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information

typeck-explicit-generic-args-with-impl-trait-feature =
add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
45 changes: 25 additions & 20 deletions compiler/rustc_macros/src/diagnostics/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::diagnostics::error::{
SessionDiagnosticDeriveError,
};
use crate::diagnostics::utils::{
option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, Applicability,
FieldInfo, HasFieldMap, SetOnce,
report_error_if_not_applied_to_span, type_matches_path, Applicability, FieldInfo, FieldInnerTy,
HasFieldMap, SetOnce,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
Expand Down Expand Up @@ -353,35 +353,40 @@ impl SessionDiagnosticDeriveBuilder {
info: FieldInfo<'_>,
) -> Result<TokenStream, SessionDiagnosticDeriveError> {
let field_binding = &info.binding.binding;
let option_ty = option_inner_ty(&info.ty);
let generated_code = self.generate_non_option_field_code(

let inner_ty = FieldInnerTy::from_type(&info.ty);
let name = attr.path.segments.last().unwrap().ident.to_string();
let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
("primary_span", FieldInnerTy::Vec(_)) => (quote! { #field_binding.clone() }, false),
_ => (quote! { *#field_binding }, true),
};

let generated_code = self.generate_inner_field_code(
attr,
FieldInfo {
vis: info.vis,
binding: info.binding,
ty: option_ty.unwrap_or(&info.ty),
ty: inner_ty.inner_type().unwrap_or(&info.ty),
span: info.span,
},
binding,
)?;

if option_ty.is_none() {
Ok(quote! { #generated_code })
if needs_destructure {
Ok(inner_ty.with(field_binding, generated_code))
} else {
Ok(quote! {
if let Some(#field_binding) = #field_binding {
#generated_code
}
})
Ok(generated_code)
}
}

fn generate_non_option_field_code(
fn generate_inner_field_code(
&mut self,
attr: &Attribute,
info: FieldInfo<'_>,
binding: TokenStream,
) -> Result<TokenStream, SessionDiagnosticDeriveError> {
let diag = &self.diag;
let field_binding = &info.binding.binding;

let name = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
Expand All @@ -397,14 +402,14 @@ impl SessionDiagnosticDeriveBuilder {
"primary_span" => {
report_error_if_not_applied_to_span(attr, &info)?;
Ok(quote! {
#diag.set_span(*#field_binding);
#diag.set_span(#binding);
})
}
"label" | "note" | "help" => {
report_error_if_not_applied_to_span(attr, &info)?;
Ok(self.add_subdiagnostic(field_binding, name, name))
Ok(self.add_subdiagnostic(binding, name, name))
}
"subdiagnostic" => Ok(quote! { #diag.subdiagnostic(*#field_binding); }),
"subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
_ => throw_invalid_attr!(attr, &meta, |diag| {
diag
.help("only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes")
Expand All @@ -413,7 +418,7 @@ impl SessionDiagnosticDeriveBuilder {
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
"label" | "note" | "help" => {
report_error_if_not_applied_to_span(attr, &info)?;
Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
Ok(self.add_subdiagnostic(binding, name, &s.value()))
}
_ => throw_invalid_attr!(attr, &meta, |diag| {
diag.help("only `label`, `note` and `help` are valid field attributes")
Expand Down Expand Up @@ -509,7 +514,7 @@ impl SessionDiagnosticDeriveBuilder {
/// `fluent_attr_identifier`.
fn add_subdiagnostic(
&self,
field_binding: &proc_macro2::Ident,
field_binding: TokenStream,
kind: &str,
fluent_attr_identifier: &str,
) -> TokenStream {
Expand All @@ -520,7 +525,7 @@ impl SessionDiagnosticDeriveBuilder {
let fn_name = format_ident!("span_{}", kind);
quote! {
#diag.#fn_name(
*#field_binding,
#field_binding,
rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)
);
}
Expand Down
18 changes: 5 additions & 13 deletions compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::diagnostics::error::{
SessionDiagnosticDeriveError,
};
use crate::diagnostics::utils::{
option_inner_ty, report_error_if_not_applied_to_applicability,
report_error_if_not_applied_to_span, Applicability, FieldInfo, HasFieldMap, SetOnce,
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
Expand Down Expand Up @@ -301,11 +301,11 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
) -> Result<TokenStream, SessionDiagnosticDeriveError> {
let ast = binding.ast();

let option_ty = option_inner_ty(&ast.ty);
let inner_ty = FieldInnerTy::from_type(&ast.ty);
let info = FieldInfo {
vis: &ast.vis,
binding: binding,
ty: option_ty.unwrap_or(&ast.ty),
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
span: &ast.span(),
};

Expand Down Expand Up @@ -353,15 +353,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
);
};

if option_ty.is_none() {
Ok(quote! { #generated })
} else {
Ok(quote! {
if let Some(#binding) = #binding {
#generated
}
})
}
Ok(inner_ty.with(binding, generated))
}

fn into_tokens(&mut self) -> Result<TokenStream, SessionDiagnosticDeriveError> {
Expand Down
61 changes: 55 additions & 6 deletions compiler/rustc_macros/src/diagnostics/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriveError};
use proc_macro::Span;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use quote::{format_ident, quote, ToTokens};
use std::collections::BTreeSet;
use std::str::FromStr;
use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility};
Expand Down Expand Up @@ -76,22 +76,71 @@ pub(crate) fn report_error_if_not_applied_to_span(
report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "Span")
}

/// If `ty` is an Option, returns `Some(inner type)`, otherwise returns `None`.
pub(crate) fn option_inner_ty(ty: &Type) -> Option<&Type> {
if type_matches_path(ty, &["std", "option", "Option"]) {
/// Inner type of a field and type of wrapper.
pub(crate) enum FieldInnerTy<'ty> {
/// Field is wrapped in a `Option<$inner>`.
Option(&'ty Type),
/// Field is wrapped in a `Vec<$inner>`.
Vec(&'ty Type),
/// Field isn't wrapped in an outer type.
None,
}

impl<'ty> FieldInnerTy<'ty> {
/// Returns inner type for a field, if there is one.
///
/// - If `ty` is an `Option`, returns `FieldInnerTy::Option { inner: (inner type) }`.
/// - If `ty` is a `Vec`, returns `FieldInnerTy::Vec { inner: (inner type) }`.
/// - Otherwise returns `None`.
pub(crate) fn from_type(ty: &'ty Type) -> Self {
let variant: &dyn Fn(&'ty Type) -> FieldInnerTy<'ty> =
if type_matches_path(ty, &["std", "option", "Option"]) {
&FieldInnerTy::Option
} else if type_matches_path(ty, &["std", "vec", "Vec"]) {
&FieldInnerTy::Vec
} else {
return FieldInnerTy::None;
};

if let Type::Path(ty_path) = ty {
let path = &ty_path.path;
let ty = path.segments.iter().last().unwrap();
if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments {
if bracketed.args.len() == 1 {
if let syn::GenericArgument::Type(ty) = &bracketed.args[0] {
return Some(ty);
return variant(ty);
}
}
}
}

unreachable!();
}

/// Returns `Option` containing inner type if there is one.
pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
match self {
FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) => Some(inner),
FieldInnerTy::None => None,
}
}

/// Surrounds `inner` with destructured wrapper type, exposing inner type as `binding`.
pub(crate) fn with(&self, binding: impl ToTokens, inner: impl ToTokens) -> TokenStream {
match self {
FieldInnerTy::Option(..) => quote! {
if let Some(#binding) = #binding {
#inner
}
},
FieldInnerTy::Vec(..) => quote! {
for #binding in #binding {
#inner
}
},
FieldInnerTy::None => quote! { #inner },
}
}
None
}

/// Field information passed to the builder. Deliberately omits attrs to discourage the
Expand Down
Loading