Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;

use crate::attributes::AttributeSafety;
use crate::attributes::diagnostic::check_cfg;
use crate::context::{AcceptContext, ShouldEmit};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
Expand All @@ -29,7 +28,7 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
ParsedDescription,
};
use crate::{AttributeParser, parse_version, session_diagnostics};
use crate::{AttributeParser, check_cfg, parse_version, session_diagnostics};

pub const CFG_TEMPLATE: AttributeTemplate = template!(
List: &["predicate"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use crate::errors::{
};
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};

pub(crate) mod check_cfg;
pub(crate) mod do_not_recommend;
pub(crate) mod on_const;
pub(crate) mod on_move;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ mod interface;
/// like lists or name-value pairs.
pub mod parser;

mod check_cfg;
mod early_parsed;
mod errors;
mod safety;
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
Int {
#[primary_span]
span: Span,

#[skip_arg]
name: Symbol,

#[skip_arg]
value: u128,
},

Expand All @@ -290,11 +286,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
Symbol {
#[primary_span]
span: Span,

#[skip_arg]
name: Symbol,

#[skip_arg]
value: Symbol,
},
}
Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// then that's equivalent to there existing a LUB.
let cause = self.pattern_cause(ti, span);
if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
if let Err(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
// If scrutinee is String and pattern is &str, suggest .as_str()
let expected = self.resolve_vars_with_obligations(expected);
if let ty::Adt(adt, _) = expected.kind()
&& self.tcx.is_lang_item(adt.did(), LangItem::String)
&& pat_ty.is_ref()
&& pat_ty.peel_refs().is_str()
&& let Some(origin_expr) = ti.origin_expr
{
err.span_suggestion_verbose(
origin_expr.span.shrink_to_hi(),
"consider converting the `String` to a `&str` using `.as_str()`",
".as_str()",
Applicability::MachineApplicable,
);
}
err.emit();
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,8 @@ where
predicate: TraitRef::new(ecx.cx(), sized_trait, [ty]).upcast(ecx.cx()),
},
);
// FIXME(field_projections): This function does some questionable incomplete stuff by
// returning `Err(NoSolution)` on ambiguity.
ecx.try_evaluate_added_goals()? == Certainty::Yes
}
&& match base.kind() {
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4639,3 +4639,28 @@ pub(crate) struct ReservedMultihashLint {
)]
pub suggestion: Span,
}

#[derive(Subdiagnostic)]
#[suggestion(
"if you meant to write a path, use a double colon:",
code = "::",
applicability = "maybe-incorrect"
)]
pub(crate) struct UseDoubleColonSuggestion {
#[primary_span]
pub colon: Span,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
"if you meant to create a regular struct, use curly braces:",
applicability = "maybe-incorrect"
)]
pub(crate) struct UseRegularStructSuggestion {
#[suggestion_part(code = "{{")]
pub open: Span,
#[suggestion_part(code = "}}")]
pub close: Span,
#[suggestion_part(code = "")]
pub semicolon: Option<Span>,
}
27 changes: 23 additions & 4 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ use super::{
AllowConstBlockItems, AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect,
Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,
};
use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
use crate::errors::{
self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField,
UseDoubleColonSuggestion, UseRegularStructSuggestion,
};
use crate::exp;

impl<'a> Parser<'a> {
Expand Down Expand Up @@ -2084,10 +2087,11 @@ impl<'a> Parser<'a> {
Safety::Default
}
}

/// This is the case where we find `struct Foo<T>(T) where T: Copy;`
/// Unit like structs are handled in parse_item_struct function
pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec<FieldDef>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
// Unit like structs are handled in parse_item_struct function
let openparen_span = self.token.span;
let mut encountered_colon = false;
self.parse_paren_comma_seq(|p| {
let attrs = p.parse_outer_attributes()?;
p.collect_tokens(None, attrs, ForceCollect::No, |p, attrs| {
Expand All @@ -2109,6 +2113,8 @@ impl<'a> Parser<'a> {
}
};
let mut_restriction = p.parse_mut_restriction()?;
encountered_colon |=
p.token.is_ident() && p.look_ahead(1, |tok| tok == &token::Colon);
// Unsafe fields are not supported in tuple structs, as doing so would result in a
// parsing ambiguity for `struct X(unsafe fn())`.
let ty = match p.parse_ty() {
Expand Down Expand Up @@ -2156,6 +2162,19 @@ impl<'a> Parser<'a> {
})
})
.map(|(r, _)| r)
.map_err(|mut error| {
if encountered_colon {
error.subdiagnostic(UseDoubleColonSuggestion { colon: self.token.span });
self.eat_to_tokens(&[exp!(CloseParen)]);
self.bump();
error.subdiagnostic(UseRegularStructSuggestion {
open: openparen_span,
close: self.prev_token.span,
semicolon: if self.token == token::Semi { Some(self.token.span) } else { None },
});
}
error
})
}

/// Parses an element of a struct declaration.
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ impl<'input> Parser<'input> {
('<' | '^' | '>', _) => self.suggest_format_align(c),
(',', _) => self.suggest_unsupported_python_numeric_grouping(),
('=', '}') => self.suggest_rust_debug_printing_macro(),
('+', _) => self.suggest_format_missing_colon_for_sign(),
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
}
}
Expand Down Expand Up @@ -939,6 +940,23 @@ impl<'input> Parser<'input> {
}
}

fn suggest_format_missing_colon_for_sign(&mut self) {
if let Some((range, _)) = self.consume_pos('+') {
self.errors.insert(
0,
ParseError {
description: "the `+` sign flag must appear after `:` in a format string"
.to_owned(),
note: Some("`+` comes after `:`, try `{:+}` instead of `{+}`".to_owned()),
label: "expected `:` before `+` sign flag".to_owned(),
span: range,
secondary_label: None,
suggestion: Suggestion::None,
},
);
}
}

fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) {
// If the argument is not an identifier, it is not a field access.
if !arg.is_identifier() {
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_parse_format/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,3 +595,13 @@ fn diagnostic_format_mod() {
assert_eq!(parser.line_spans, &[]);
assert!(parser.errors.is_empty());
}
#[test]
fn format_plus_sign_missing_colon_error() {
// `{+}` should produce an error suggesting `:` before `+`
let mut p = Parser::new("{+}", None, None, false, ParseMode::Format);
let _ = p.by_ref().collect::<Vec<Piece<'static>>>();
assert!(!p.errors.is_empty());
assert!(p.errors[0].description.contains("`+` sign flag must appear after `:`"));
assert!(p.errors[0].label.contains("expected `:` before `+` sign flag"));
assert_eq!(p.errors[0].span, 2..3);
}
9 changes: 0 additions & 9 deletions compiler/rustc_trait_selection/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,6 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
style = "verbose"
)]
new_ty_span: Span,
#[skip_arg]
new_ty: Ty<'a>,
},
#[diag("explicit lifetime required in parameter type", code = E0621)]
Expand All @@ -885,7 +884,6 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
style = "verbose"
)]
new_ty_span: Span,
#[skip_arg]
new_ty: Ty<'a>,
},
}
Expand Down Expand Up @@ -1519,7 +1517,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
RemoveRef {
#[primary_span]
span: Span,
#[skip_arg]
fn_name: String,
},
#[suggestion(
Expand All @@ -1531,9 +1528,7 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
CastRef {
#[primary_span]
span: Span,
#[skip_arg]
fn_name: String,
#[skip_arg]
sig: Binder<'a, FnSig<'a>>,
},
#[suggestion(
Expand All @@ -1545,7 +1540,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
Cast {
#[primary_span]
span: Span,
#[skip_arg]
sig: Binder<'a, FnSig<'a>>,
},
#[suggestion(
Expand All @@ -1557,7 +1551,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
CastBoth {
#[primary_span]
span: Span,
#[skip_arg]
found_sig: Binder<'a, FnSig<'a>>,
expected_sig: Binder<'a, FnSig<'a>>,
},
Expand All @@ -1570,9 +1563,7 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
CastBothRef {
#[primary_span]
span: Span,
#[skip_arg]
fn_name: String,
#[skip_arg]
found_sig: Binder<'a, FnSig<'a>>,
expected_sig: Binder<'a, FnSig<'a>>,
},
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,10 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
pub(crate) fn print_const(tcx: TyCtxt<'_>, n: ty::Const<'_>) -> String {
match n.kind() {
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => {
if let Some(def) = def.as_local() {
rendered_const(tcx, tcx.hir_body_owned_by(def), def)
if let Some(def) = def.as_local()
&& let Some(body_id) = tcx.hir_maybe_body_owned_by(def)
{
rendered_const(tcx, body_id, def)
} else {
inline::print_inlined_const(tcx, def)
}
Expand Down
16 changes: 16 additions & 0 deletions tests/rustdoc-ui/type-const-associated-const-no-body.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/149287>
//! Ensure that rustdoc does not ICE when a body-less type const is used
//! as an associated const.
//@ check-pass

#![feature(min_generic_const_args)]

pub trait Tr {
type const SIZE: usize;
}

fn mk_array<T: Tr>() -> [(); <T as Tr>::SIZE] {
[(); T::SIZE]
}

fn main() {}
4 changes: 4 additions & 0 deletions tests/ui/fmt/format-string-wrong-order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ fn main() {
//~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}`
println!("{0:#X>18}", 12345);
//~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}`
format!("{+:}");
//~^ ERROR invalid format string: the `+` sign flag must appear after `:` in a format string
format!("{bar+:}");
//~^ ERROR invalid format string: the `+` sign flag must appear after `:` in a format string
}
18 changes: 17 additions & 1 deletion tests/ui/fmt/format-string-wrong-order.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,21 @@ error: invalid format string: expected alignment specifier after `:` in format s
LL | println!("{0:#X>18}", 12345);
| ^ expected `>` to occur after `:` in format string

error: aborting due to 10 previous errors
error: invalid format string: the `+` sign flag must appear after `:` in a format string
--> $DIR/format-string-wrong-order.rs:23:15
|
LL | format!("{+:}");
| ^ expected `:` before `+` sign flag in format string
|
= note: `+` comes after `:`, try `{:+}` instead of `{+}`

error: invalid format string: the `+` sign flag must appear after `:` in a format string
--> $DIR/format-string-wrong-order.rs:25:18
|
LL | format!("{bar+:}");
| ^ expected `:` before `+` sign flag in format string
|
= note: `+` comes after `:`, try `{:+}` instead of `{+}`

error: aborting due to 12 previous errors

6 changes: 6 additions & 0 deletions tests/ui/parser/field-name-in-tuple-struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Provide diagnostics when the user writes field names in tuple struct.(issue#144595)

struct Foo(a:u8,b:u8);
//~^ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
//~| HELP if you meant to write a path, use a double colon:
//~| HELP if you meant to create a regular struct, use curly braces:
18 changes: 18 additions & 0 deletions tests/ui/parser/field-name-in-tuple-struct.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
--> $DIR/field-name-in-tuple-struct.rs:3:13
|
LL | struct Foo(a:u8,b:u8);
| ^ expected one of 7 possible tokens
|
help: if you meant to write a path, use a double colon:
|
LL | struct Foo(a::u8,b:u8);
| +
help: if you meant to create a regular struct, use curly braces:
|
LL - struct Foo(a:u8,b:u8);
LL + struct Foo{a:u8,b:u8}
|

error: aborting due to 1 previous error

5 changes: 5 additions & 0 deletions tests/ui/pattern/deref-patterns/needs-gate.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ LL | match "str".to_owned() {
| ---------------- this expression has type `String`
LL | "str" => {}
| ^^^^^ expected `String`, found `&str`
|
help: consider converting the `String` to a `&str` using `.as_str()`
|
LL | match "str".to_owned().as_str() {
| +++++++++

error[E0308]: mismatched types
--> $DIR/needs-gate.rs:52:12
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/pattern/string-match-as-str-suggestion.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//@ run-rustfix

fn main() {
let s = "yes".to_owned();

let _ = match s.as_str() {
"yes" => Some(true),
//~^ ERROR mismatched types
"no" => Some(false),
//~^ ERROR mismatched types
_ => None,
};

let s2 = String::from("hello");
if let "hello" = s2.as_str() {
//~^ ERROR mismatched types
}
}
Loading
Loading