Skip to content

Commit

Permalink
Auto merge of #134640 - matthiaskrgr:rollup-xlstm3o, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #134364 (Use E0665 for missing `#[default]` on enum and update doc)
 - #134601 (Support pretty-printing `dyn*` trait objects)
 - #134603 (Explain why a type is not eligible for `impl PointerLike`.)
 - #134618 (coroutine_clone: add comments)
 - #134630 (Use `&raw` for `ptr` primitive docs)
 - #134637 (Flatten effects directory now that it doesn't really test anything specific)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Dec 22, 2024
2 parents c113247 + 66dbfd4 commit a2bcfae
Show file tree
Hide file tree
Showing 54 changed files with 366 additions and 197 deletions.
6 changes: 4 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1204,8 +1204,10 @@ impl<'a> State<'a> {
}
ast::TyKind::Path(Some(qself), path) => self.print_qpath(path, qself, false),
ast::TyKind::TraitObject(bounds, syntax) => {
if *syntax == ast::TraitObjectSyntax::Dyn {
self.word_nbsp("dyn");
match syntax {
ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
ast::TraitObjectSyntax::None => {}
}
self.print_type_bounds(bounds);
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ builtin_macros_naked_functions_testing_attribute =
.label = function marked with testing attribute here
.naked_attribute = `#[naked]` is incompatible with testing attributes
builtin_macros_no_default_variant = no default declared
.help = make a unit variant default by placing `#[default]` above it
.suggestion = make `{$ident}` default
builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
.label = this enum needs a unit variant marked with `#[default]`
.suggestion = make this unit variant default by placing `#[default]` on it
builtin_macros_non_abi = at least one abi must be provided as an argument to `clobber_abi`
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ pub(crate) fn expand_deriving_default(
StaticStruct(_, fields) => {
default_struct_substructure(cx, trait_span, substr, fields)
}
StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def),
StaticEnum(enum_def, _) => {
default_enum_substructure(cx, trait_span, enum_def, item.span())
}
_ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
}
})),
Expand Down Expand Up @@ -96,9 +98,10 @@ fn default_enum_substructure(
cx: &ExtCtxt<'_>,
trait_span: Span,
enum_def: &EnumDef,
item_span: Span,
) -> BlockOrExpr {
let expr = match try {
let default_variant = extract_default_variant(cx, enum_def, trait_span)?;
let default_variant = extract_default_variant(cx, enum_def, trait_span, item_span)?;
validate_default_attribute(cx, default_variant)?;
default_variant
} {
Expand Down Expand Up @@ -146,6 +149,7 @@ fn extract_default_variant<'a>(
cx: &ExtCtxt<'_>,
enum_def: &'a EnumDef,
trait_span: Span,
item_span: Span,
) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> {
let default_variants: SmallVec<[_; 1]> = enum_def
.variants
Expand All @@ -163,9 +167,10 @@ fn extract_default_variant<'a>(
.filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));

let suggs = possible_defaults
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
.map(|v| errors::NoDefaultVariantSugg { span: v.span.shrink_to_lo() })
.collect();
let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
let guar =
cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, item_span, suggs });

return Err(guar);
}
Expand Down
13 changes: 4 additions & 9 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,26 +369,21 @@ pub(crate) struct DerivePathArgsValue {
}

#[derive(Diagnostic)]
#[diag(builtin_macros_no_default_variant)]
#[help]
#[diag(builtin_macros_no_default_variant, code = E0665)]
pub(crate) struct NoDefaultVariant {
#[primary_span]
pub(crate) span: Span,
#[label]
pub(crate) item_span: Span,
#[subdiagnostic]
pub(crate) suggs: Vec<NoDefaultVariantSugg>,
}

#[derive(Subdiagnostic)]
#[suggestion(
builtin_macros_suggestion,
code = "#[default] {ident}",
applicability = "maybe-incorrect",
style = "tool-only"
)]
#[suggestion(builtin_macros_suggestion, code = "#[default] ", applicability = "maybe-incorrect")]
pub(crate) struct NoDefaultVariantSugg {
#[primary_span]
pub(crate) span: Span,
pub(crate) ident: Ident,
}

#[derive(Diagnostic)]
Expand Down
25 changes: 18 additions & 7 deletions compiler/rustc_error_codes/src/error_codes/E0665.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#### Note: this error code is no longer emitted by the compiler.

The `Default` trait was derived on an enum.
The `Default` trait was derived on an enum without specifying the default
variant.

Erroneous code example:

```compile_fail
```compile_fail,E0665
#[derive(Default)]
enum Food {
Sweet,
Expand All @@ -16,18 +15,30 @@ The `Default` cannot be derived on an enum for the simple reason that the
compiler doesn't know which value to pick by default whereas it can for a
struct as long as all its fields implement the `Default` trait as well.

If you still want to implement `Default` on your enum, you'll have to do it "by
hand":
For the case where the desired default variant has no payload, you can
annotate it with `#[default]` to derive it:

```
#[derive(Default)]
enum Food {
#[default]
Sweet,
Salty,
}
```

In the case where the default variant does have a payload, you will have to
implement `Default` on your enum manually:

```
enum Food {
Sweet(i32),
Salty,
}
impl Default for Food {
fn default() -> Food {
Food::Sweet
Food::Sweet(1)
}
}
```
100 changes: 69 additions & 31 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,37 +673,6 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
let impl_span = tcx.def_span(checker.impl_def_id);
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();

// If an ADT is repr(transparent)...
if let ty::Adt(def, args) = *self_ty.kind()
&& def.repr().transparent()
{
// FIXME(compiler-errors): This should and could be deduplicated into a query.
// Find the nontrivial field.
let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
let nontrivial_field = def.all_fields().find(|field_def| {
let field_ty = tcx.type_of(field_def.did).instantiate_identity();
!tcx.layout_of(adt_typing_env.as_query_input(field_ty))
.is_ok_and(|layout| layout.layout.is_1zst())
});

if let Some(nontrivial_field) = nontrivial_field {
// Check that the nontrivial field implements `PointerLike`.
let nontrivial_field = nontrivial_field.ty(tcx, args);
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field,
tcx.lang_items().pointer_like().unwrap(),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
return Ok(());
}
}
}

let is_permitted_primitive = match *self_ty.kind() {
ty::Adt(def, _) => def.is_box(),
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
Expand All @@ -717,12 +686,81 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
return Ok(());
}

let why_disqualified = match *self_ty.kind() {
// If an ADT is repr(transparent)
ty::Adt(self_ty_def, args) => {
if self_ty_def.repr().transparent() {
// FIXME(compiler-errors): This should and could be deduplicated into a query.
// Find the nontrivial field.
let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
let field_ty = tcx.type_of(field_def.did).instantiate_identity();
!tcx.layout_of(adt_typing_env.as_query_input(field_ty))
.is_ok_and(|layout| layout.layout.is_1zst())
});

if let Some(nontrivial_field) = nontrivial_field {
// Check that the nontrivial field implements `PointerLike`.
let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field_ty,
tcx.lang_items().pointer_like().unwrap(),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
return Ok(());
} else {
format!(
"the field `{field_name}` of {descr} `{self_ty}` \
does not implement `PointerLike`",
field_name = nontrivial_field.name,
descr = self_ty_def.descr()
)
}
} else {
format!(
"the {descr} `{self_ty}` is `repr(transparent)`, \
but does not have a non-trivial field (it is zero-sized)",
descr = self_ty_def.descr()
)
}
} else if self_ty_def.is_box() {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this box is not a thin pointer.

String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
} else {
format!(
"the {descr} `{self_ty}` is not `repr(transparent)`",
descr = self_ty_def.descr()
)
}
}
ty::Ref(..) => {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this reference is not a thin pointer.
String::from("references to dynamically-sized types are too large to be `PointerLike`")
}
ty::Dynamic(..) | ty::Foreign(..) => {
String::from("types of dynamic or unknown size may not implement `PointerLike`")
}
_ => {
// This is a white lie; it is true everywhere outside the standard library.
format!("only user-defined sized types are eligible for `impl PointerLike`")
}
};

Err(tcx
.dcx()
.struct_span_err(
impl_span,
"implementation must be applied to type that has the same ABI as a pointer, \
or is `repr(transparent)` and whose field is `PointerLike`",
)
.with_note(why_disqualified)
.emit())
}
6 changes: 4 additions & 2 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,10 @@ impl<'a> State<'a> {
}
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
if syntax == ast::TraitObjectSyntax::Dyn {
self.word_space("dyn");
match syntax {
ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
ast::TraitObjectSyntax::None => {}
}
let mut first = true;
for bound in bounds {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,11 @@ pub enum TerminatorKind<'tcx> {
/// continues at the `resume` basic block, with the second argument written to the `resume_arg`
/// place. If the coroutine is dropped before then, the `drop` basic block is invoked.
///
/// Note that coroutines can be (unstably) cloned under certain conditions, which means that
/// this terminator can **return multiple times**! MIR optimizations that reorder code into
/// different basic blocks needs to be aware of that.
/// See <https://github.com/rust-lang/rust/issues/95360>.
///
/// Not permitted in bodies that are not coroutine bodies, or after coroutine lowering.
///
/// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
Expand Down
10 changes: 5 additions & 5 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,11 +563,11 @@ impl () {}
/// Note that here the call to [`drop`] is for clarity - it indicates
/// that we are done with the given value and it should be destroyed.
///
/// ## 3. Create it using `ptr::addr_of!`
/// ## 3. Create it using `&raw`
///
/// Instead of coercing a reference to a raw pointer, you can use the macros
/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
/// These macros allow you to create raw pointers to fields to which you cannot
/// Instead of coercing a reference to a raw pointer, you can use the raw borrow
/// operators `&raw const` (for `*const T`) and `&raw mut` (for `*mut T`).
/// These operators allow you to create raw pointers to fields to which you cannot
/// create a reference (without causing undefined behavior), such as an
/// unaligned field. This might be necessary if packed structs or uninitialized
/// memory is involved.
Expand All @@ -580,7 +580,7 @@ impl () {}
/// unaligned: u32,
/// }
/// let s = S::default();
/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
/// let p = &raw const s.unaligned; // not allowed with coercion
/// ```
///
/// ## 4. Get it from C.
Expand Down
4 changes: 0 additions & 4 deletions tests/ui-fulldeps/pprust-parenthesis-insertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,6 @@ static EXPRS: &[&str] = &[
"(0.).to_string()",
"0. .. 1.",
*/
/*
// FIXME: pretty-printer loses the dyn*. `i as Trait`
"i as dyn* Trait",
*/
];

// Flatten the content of parenthesis nodes into their parent node. For example
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/coroutine/clone-impl-static.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//@compile-flags: --diagnostic-width=300
// gate-test-coroutine_clone
// Verifies that static coroutines cannot be cloned/copied.
// This is important: the cloned coroutine would reference state of the original
// coroutine, leading to semantic nonsense.

#![feature(coroutines, coroutine_clone, stmt_expr_attributes)]

Expand Down
16 changes: 8 additions & 8 deletions tests/ui/coroutine/clone-impl-static.stderr
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:9:5: 9:19}: Copy` is not satisfied
--> $DIR/clone-impl-static.rs:12:16
error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Copy` is not satisfied
--> $DIR/clone-impl-static.rs:14:16
|
LL | check_copy(&gen);
| ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:9:5: 9:19}`
| ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check_copy`
--> $DIR/clone-impl-static.rs:18:18
--> $DIR/clone-impl-static.rs:20:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`

error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:9:5: 9:19}: Clone` is not satisfied
--> $DIR/clone-impl-static.rs:14:17
error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Clone` is not satisfied
--> $DIR/clone-impl-static.rs:16:17
|
LL | check_clone(&gen);
| ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:9:5: 9:19}`
| ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check_clone`
--> $DIR/clone-impl-static.rs:19:19
--> $DIR/clone-impl-static.rs:21:19
|
LL | fn check_clone<T: Clone>(_x: &T) {}
| ^^^^^ required by this bound in `check_clone`
Expand Down
Loading

0 comments on commit a2bcfae

Please sign in to comment.