Auto merge of #63043 - Centril:rollup-f4baee4, r=Centril

Rollup of 6 pull requests

Successful merges:

 - #62423 (Fix cycle error with existential types)
 - #62979 (Cleanup save-analysis JsonDumper)
 - #62982 (Don't access a static just for its size and alignment)
 - #63013 (add `repr(transparent)` to `IoSliceMut` where missing)
 - #63014 (Stop bare trait lint applying to macro call sites)
 - #63036 (Add lib section to rustc_lexer's Cargo.toml)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-07-27 15:41:45 +00:00
commit a5e7bb3e2b
26 changed files with 387 additions and 218 deletions

View file

@ -5753,13 +5753,21 @@ impl<'a> LoweringContext<'a> {
}
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
self.sess.buffer_lint_with_diagnostic(
builtin::BARE_TRAIT_OBJECTS,
id,
span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
let is_macro_callsite = self.sess.source_map()
.span_to_snippet(span)
.map(|snippet| snippet.starts_with("#["))
.unwrap_or(true);
if !is_macro_callsite {
self.sess.buffer_lint_with_diagnostic(
builtin::BARE_TRAIT_OBJECTS,
id,
span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
}
}
fn wrap_in_try_constructor(

View file

@ -7,3 +7,9 @@ edition = "2018"
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
unicode-xid = { version = "0.1.0", optional = true }
# Note: do not remove this blank `[lib]` section.
# This will be used when publishing this crate as `rustc-ap-rustc_lexer`.
[lib]
doctest = false
name = "rustc_lexer"

View file

@ -1281,15 +1281,43 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let opaque_defn_ty = tcx.type_of(opaque_def_id);
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
let concrete_is_opaque = infcx
.resolve_vars_if_possible(&opaque_decl.concrete_ty).is_impl_trait();
debug!(
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \
concrete_is_opaque={}",
opaque_decl.concrete_ty,
infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
opaque_defn_ty
opaque_defn_ty,
concrete_is_opaque
);
obligations.add(infcx
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
// concrete_is_opaque is `true` when we're using an existential
// type without 'revealing' it. For example, code like this:
//
// existential type Foo: Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the existential type - this will always fail, since
// the defining type of an existential type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into
if !concrete_is_opaque {
obligations.add(infcx
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
}
}
debug!("eq_opaque_type_and_type: equated");

View file

@ -535,41 +535,48 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
id: AllocId,
liveness: AllocCheck,
) -> InterpResult<'static, (Size, Align)> {
// Regular allocations.
if let Ok(alloc) = self.get(id) {
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
}
// Function pointers.
if let Ok(_) = self.get_fn_alloc(id) {
return if let AllocCheck::Dereferencable = liveness {
// The caller requested no function pointers.
err!(DerefFunctionPointer)
} else {
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
};
}
// Foreign statics.
// Can't do this in the match argument, we may get cycle errors since the lock would
// be held throughout the match.
let alloc = self.tcx.alloc_map.lock().get(id);
match alloc {
Some(GlobalAlloc::Static(did)) => {
assert!(self.tcx.is_foreign_item(did));
// Use size and align of the type
let ty = self.tcx.type_of(did);
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
return Ok((layout.size, layout.align.abi));
// Don't use `self.get` here as that will
// a) cause cycles in case `id` refers to a static
// b) duplicate a static's allocation in miri
match self.alloc_map.get_or(id, || Err(())) {
Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
Err(()) => {
// Not a local allocation, check the global `tcx.alloc_map`.
// Can't do this in the match argument, we may get cycle errors since the lock would
// be held throughout the match.
let alloc = self.tcx.alloc_map.lock().get(id);
match alloc {
Some(GlobalAlloc::Static(did)) => {
// Use size and align of the type.
let ty = self.tcx.type_of(did);
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
Ok((layout.size, layout.align.abi))
},
Some(GlobalAlloc::Memory(alloc)) =>
// Need to duplicate the logic here, because the global allocations have
// different associated types than the interpreter-local ones.
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
Some(GlobalAlloc::Function(_)) => {
if let AllocCheck::Dereferencable = liveness {
// The caller requested no function pointers.
err!(DerefFunctionPointer)
} else {
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
}
},
// The rest must be dead.
None => if let AllocCheck::MaybeDead = liveness {
// Deallocated pointers are allowed, we should be able to find
// them in the map.
Ok(*self.dead_alloc_map.get(&id)
.expect("deallocated pointers should all be recorded in \
`dead_alloc_map`"))
} else {
err!(DanglingPointerDeref)
},
}
}
_ => {}
}
// The rest must be dead.
if let AllocCheck::MaybeDead = liveness {
// Deallocated pointers are allowed, we should be able to find
// them in the map.
Ok(*self.dead_alloc_map.get(&id)
.expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
} else {
err!(DanglingPointerDeref)
}
}

View file

@ -10,7 +10,7 @@
//!
//! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
//! from spans (e.g., the span for `bar` from the above example path).
//! DumpVisitor walks the AST and processes it, and JsonDumper is used for
//! DumpVisitor walks the AST and processes it, and Dumper is used for
//! recording the output.
use rustc::hir::def::{Res, DefKind as HirDefKind};
@ -38,7 +38,7 @@ use syntax_pos::*;
use crate::{escape, generated_code, id_from_def_id, id_from_node_id, lower_attributes,
PathCollector, SaveContext};
use crate::json_dumper::{Access, DumpOutput, JsonDumper};
use crate::dumper::{Access, Dumper};
use crate::span_utils::SpanUtils;
use crate::sig;
@ -75,10 +75,10 @@ macro_rules! access_from_vis {
};
}
pub struct DumpVisitor<'l, 'tcx, 'll, O: DumpOutput> {
pub struct DumpVisitor<'l, 'tcx, 'll> {
save_ctxt: SaveContext<'l, 'tcx>,
tcx: TyCtxt<'tcx>,
dumper: &'ll mut JsonDumper<O>,
dumper: &'ll mut Dumper,
span: SpanUtils<'l>,
@ -92,11 +92,11 @@ pub struct DumpVisitor<'l, 'tcx, 'll, O: DumpOutput> {
// macro_calls: FxHashSet<Span>,
}
impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> {
pub fn new(
save_ctxt: SaveContext<'l, 'tcx>,
dumper: &'ll mut JsonDumper<O>,
) -> DumpVisitor<'l, 'tcx, 'll, O> {
dumper: &'ll mut Dumper,
) -> DumpVisitor<'l, 'tcx, 'll> {
let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
DumpVisitor {
tcx: save_ctxt.tcx,
@ -111,7 +111,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
where
F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>),
{
let parent_scope = self.cur_scope;
self.cur_scope = scope_id;
@ -121,7 +121,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
where
F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>),
{
let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
if self.tcx.has_typeck_tables(item_def_id) {
@ -1311,7 +1311,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
}
}
impl<'l, 'tcx, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> {
fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
// Since we handle explicit modules ourselves in visit_item, this should
// only get called for the root module of a crate.

View file

@ -1,80 +1,33 @@
use std::io::Write;
use rls_data::config::Config;
use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import,
MacroRef, Ref, RefKind, Relation};
use rls_span::{Column, Row};
use log::error;
#[derive(Debug)]
pub struct Access {
pub reachable: bool,
pub public: bool,
}
pub struct JsonDumper<O: DumpOutput> {
pub struct Dumper {
result: Analysis,
config: Config,
output: O,
}
pub trait DumpOutput {
fn dump(&mut self, result: &Analysis);
}
pub struct WriteOutput<'b, W: Write> {
output: &'b mut W,
}
impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> {
fn dump(&mut self, result: &Analysis) {
if let Err(e) = serde_json::to_writer(self.output.by_ref(), result) {
error!("Can't serialize save-analysis: {:?}", e);
}
}
}
pub struct CallbackOutput<'b> {
callback: &'b mut dyn FnMut(&Analysis),
}
impl<'b> DumpOutput for CallbackOutput<'b> {
fn dump(&mut self, result: &Analysis) {
(self.callback)(result)
}
}
impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> {
pub fn new(writer: &'b mut W, config: Config) -> JsonDumper<WriteOutput<'b, W>> {
JsonDumper {
output: WriteOutput { output: writer },
impl Dumper {
pub fn new(config: Config) -> Dumper {
Dumper {
config: config.clone(),
result: Analysis::new(config),
}
}
}
impl<'b> JsonDumper<CallbackOutput<'b>> {
pub fn with_callback(
callback: &'b mut dyn FnMut(&Analysis),
config: Config,
) -> JsonDumper<CallbackOutput<'b>> {
JsonDumper {
output: CallbackOutput { callback },
config: config.clone(),
result: Analysis::new(config),
}
pub fn to_output(self, f: impl FnOnce(&Analysis)) {
f(&self.result)
}
}
impl<O: DumpOutput> Drop for JsonDumper<O> {
fn drop(&mut self) {
self.output.dump(&self.result);
}
}
impl<'b, O: DumpOutput + 'b> JsonDumper<O> {
impl Dumper {
pub fn crate_prelude(&mut self, data: CratePreludeData) {
self.result.prelude = Some(data)
}

View file

@ -7,7 +7,7 @@
#![recursion_limit="256"]
mod json_dumper;
mod dumper;
mod dump_visitor;
#[macro_use]
mod span_utils;
@ -39,7 +39,7 @@ use syntax::visit::{self, Visitor};
use syntax::print::pprust::{arg_to_string, ty_to_string};
use syntax_pos::*;
use json_dumper::JsonDumper;
use dumper::Dumper;
use dump_visitor::DumpVisitor;
use span_utils::SpanUtils;
@ -1075,17 +1075,19 @@ impl<'a> SaveHandler for DumpHandler<'a> {
input: &'l Input,
) {
let sess = &save_ctxt.tcx.sess;
let file_name = {
let (mut output, file_name) = self.output_file(&save_ctxt);
let mut dumper = JsonDumper::new(&mut output, save_ctxt.config.clone());
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
let (output, file_name) = self.output_file(&save_ctxt);
let mut dumper = Dumper::new(save_ctxt.config.clone());
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
visitor.dump_crate_info(cratename, krate);
visitor.dump_compilation_options(input, cratename);
visit::walk_crate(&mut visitor, krate);
visitor.dump_crate_info(cratename, krate);
visitor.dump_compilation_options(input, cratename);
visit::walk_crate(&mut visitor, krate);
file_name
};
dumper.to_output(|analysis| {
if let Err(e) = serde_json::to_writer(output, analysis) {
error!("Can't serialize save-analysis: {:?}", e);
}
});
if sess.opts.debugging_opts.emit_artifact_notifications {
sess.parse_sess.span_diagnostic
@ -1107,17 +1109,19 @@ impl<'b> SaveHandler for CallbackHandler<'b> {
cratename: &str,
input: &'l Input,
) {
// We're using the JsonDumper here because it has the format of the
// We're using the Dumper here because it has the format of the
// save-analysis results that we will pass to the callback. IOW, we are
// using the JsonDumper to collect the save-analysis results, but not
// using the Dumper to collect the save-analysis results, but not
// actually to dump them to a file. This is all a bit convoluted and
// there is certainly a simpler design here trying to get out (FIXME).
let mut dumper = JsonDumper::with_callback(self.callback, save_ctxt.config.clone());
let mut dumper = Dumper::new(save_ctxt.config.clone());
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
visitor.dump_crate_info(cratename, krate);
visitor.dump_compilation_options(input, cratename);
visit::walk_crate(&mut visitor, krate);
dumper.to_output(|a| (self.callback)(a))
}
}

View file

@ -453,36 +453,43 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
def_id, opaque_defn, instantiated_ty, span);
let mut skip_add = false;
if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
if def_id == defin_ty_def_id {
// Concrete type resolved to the existential type itself.
// Force a cycle error.
// FIXME(oli-obk): we could just not insert it into `concrete_existential_types`
// which simply would make this use not a defining use.
self.tcx().at(span).type_of(defin_ty_def_id);
debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
opaque_defn, defin_ty_def_id);
skip_add = true;
}
}
if !opaque_defn.substs.has_local_value() {
let new = ty::ResolvedOpaqueTy {
concrete_type: definition_ty,
substs: opaque_defn.substs,
};
// We only want to add an entry into `concrete_existential_types`
// if we actually found a defining usage of this existential type.
// Otherwise, we do nothing - we'll either find a defining usage
// in some other location, or we'll end up emitting an error due
// to the lack of defining usage
if !skip_add {
let new = ty::ResolvedOpaqueTy {
concrete_type: definition_ty,
substs: opaque_defn.substs,
};
let old = self.tables
.concrete_existential_types
.insert(def_id, new);
if let Some(old) = old {
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
span_bug!(
span,
"visit_opaque_types tried to write \
different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
def_id,
definition_ty,
opaque_defn,
old,
);
let old = self.tables
.concrete_existential_types
.insert(def_id, new);
if let Some(old) = old {
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
span_bug!(
span,
"visit_opaque_types tried to write different types for the same \
existential type: {:?}, {:?}, {:?}, {:?}",
def_id,
definition_ty,
opaque_defn,
old,
);
}
}
}
} else {

View file

@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
}
}
#[repr(transparent)]
pub struct IoSliceMut<'a> {
vec: iovec,
_p: PhantomData<&'a mut [u8]>,

View file

@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
}
}
#[repr(transparent)]
pub struct IoSliceMut<'a> {
vec: __wasi_iovec_t,
_p: PhantomData<&'a mut [u8]>,

View file

@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
}
}
#[repr(transparent)]
pub struct IoSliceMut<'a> {
vec: c::WSABUF,
_p: PhantomData<&'a mut [u8]>,

View file

@ -0,0 +1,11 @@
// check-pass
struct Foo {
foo: Option<&'static Foo>
}
static FOO: Foo = Foo {
foo: Some(&FOO),
};
fn main() {}

View file

@ -1,7 +1,7 @@
#![feature(existential_type)]
existential type Foo: Fn() -> Foo;
//~^ ERROR: cycle detected when processing `Foo`
//~^ ERROR: could not find defining uses
fn crash(x: Foo) -> Foo {
x

View file

@ -1,30 +1,8 @@
error[E0391]: cycle detected when processing `Foo`
error: could not find defining uses
--> $DIR/existential-types-with-cycle-error.rs:3:1
|
LL | existential type Foo: Fn() -> Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires processing `crash`...
--> $DIR/existential-types-with-cycle-error.rs:6:25
|
LL | fn crash(x: Foo) -> Foo {
| _________________________^
LL | | x
LL | | }
| |_^
= note: ...which again requires processing `Foo`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/existential-types-with-cycle-error.rs:1:1
|
LL | / #![feature(existential_type)]
LL | |
LL | | existential type Foo: Fn() -> Foo;
LL | |
... |
LL | |
LL | | }
| |_^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0391`.

View file

@ -5,7 +5,7 @@ pub trait Bar<T> {
}
existential type Foo: Bar<Foo, Item = Foo>;
//~^ ERROR: cycle detected when processing `Foo`
//~^ ERROR: could not find defining uses
fn crash(x: Foo) -> Foo {
x

View file

@ -1,30 +1,8 @@
error[E0391]: cycle detected when processing `Foo`
error: could not find defining uses
--> $DIR/existential-types-with-cycle-error2.rs:7:1
|
LL | existential type Foo: Bar<Foo, Item = Foo>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires processing `crash`...
--> $DIR/existential-types-with-cycle-error2.rs:10:25
|
LL | fn crash(x: Foo) -> Foo {
| _________________________^
LL | | x
LL | | }
| |_^
= note: ...which again requires processing `Foo`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/existential-types-with-cycle-error2.rs:1:1
|
LL | / #![feature(existential_type)]
LL | |
LL | | pub trait Bar<T> {
LL | | type Item;
... |
LL | |
LL | | }
| |_^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0391`.

View file

@ -0,0 +1,20 @@
// check-pass
#![feature(existential_type)]
// Currently, the `existential_type` feature implicitly
// depends on `impl_trait_in_bindings` in order to work properly.
// Specifically, this line requires `impl_trait_in_bindings` to be enabled:
// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/src/librustc_typeck/check/mod.rs#L856
#![feature(impl_trait_in_bindings)]
//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
// Ensures that `const` items can constrain an `existential type`.
use std::fmt::Debug;
pub existential type Foo: Debug;
const _FOO: Foo = 5;
fn main() {
}

View file

@ -0,0 +1,6 @@
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
--> $DIR/existential_type_const.rs:8:12
|
LL | #![feature(impl_trait_in_bindings)]
| ^^^^^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,27 @@
// check-pass
#![feature(existential_type)]
// Regression test for issue #61863
pub trait MyTrait {}
#[derive(Debug)]
pub struct MyStruct {
v: u64
}
impl MyTrait for MyStruct {}
pub fn bla() -> TE {
return MyStruct {v:1}
}
pub fn bla2() -> TE {
bla()
}
existential type TE: MyTrait;
fn main() {}

View file

@ -0,0 +1,33 @@
// check-pass
#![feature(existential_type)]
#![allow(dead_code)]
pub trait MyTrait {}
impl MyTrait for bool {}
struct Blah {
my_foo: Foo,
my_u8: u8
}
impl Blah {
fn new() -> Blah {
Blah {
my_foo: make_foo(),
my_u8: 12
}
}
fn into_inner(self) -> (Foo, u8) {
(self.my_foo, self.my_u8)
}
}
fn make_foo() -> Foo {
true
}
existential type Foo: MyTrait;
fn main() {}

View file

@ -1,9 +1,9 @@
// Issue 52985: Cause cycle error if user code provides no use case that allows an existential type
// to be inferred to a concrete type. This results in an infinite cycle during type normalization.
// Issue 52985: user code provides no use case that allows an existential type
// We now emit a 'could not find defining uses' error
#![feature(existential_type)]
existential type Foo: Copy; //~ cycle detected
existential type Foo: Copy; //~ could not find defining uses
// make compiler happy about using 'Foo'
fn bar(x: Foo) -> Foo { x }

View file

@ -1,27 +1,8 @@
error[E0391]: cycle detected when processing `Foo`
error: could not find defining uses
--> $DIR/no_inferrable_concrete_type.rs:6:1
|
LL | existential type Foo: Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires processing `bar`...
--> $DIR/no_inferrable_concrete_type.rs:9:23
|
LL | fn bar(x: Foo) -> Foo { x }
| ^^^^^
= note: ...which again requires processing `Foo`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/no_inferrable_concrete_type.rs:4:1
|
LL | / #![feature(existential_type)]
LL | |
LL | | existential type Foo: Copy;
LL | |
... |
LL | | let _: Foo = std::mem::transmute(0u8);
LL | | }
| |_^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0391`.

View file

@ -0,0 +1,40 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::{Group, TokenStream, TokenTree};
// This macro exists as part of a reproduction of #61963 but without using quote/syn/proc_macro2.
#[proc_macro_derive(DomObject)]
pub fn expand_token_stream(input: TokenStream) -> TokenStream {
// Construct a dummy span - `#0 bytes(0..0)` - which is present in the input because
// of the specially crafted generated tokens in the `attribute-crate` proc-macro.
let dummy_span = input.clone().into_iter().nth(0).unwrap().span();
// Define what the macro would output if constructed properly from the source using syn/quote.
let output: TokenStream = "impl Bar for ((), Qux<Qux<Baz> >) { }
impl Bar for ((), Box<Bar>) { }".parse().unwrap();
let mut tokens: Vec<_> = output.into_iter().collect();
// Adjust token spans to match the original crate (which would use `quote`). Some of the
// generated tokens point to the dummy span.
for token in tokens.iter_mut() {
if let TokenTree::Group(group) = token {
let mut tokens: Vec<_> = group.stream().into_iter().collect();
for token in tokens.iter_mut().skip(2) {
token.set_span(dummy_span);
}
let mut stream = TokenStream::new();
stream.extend(tokens);
*group = Group::new(group.delimiter(), stream);
}
}
let mut output = TokenStream::new();
output.extend(tokens);
output
}

View file

@ -0,0 +1,41 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::{Group, Spacing, Punct, TokenTree, TokenStream};
// This macro exists as part of a reproduction of #61963 but without using quote/syn/proc_macro2.
#[proc_macro_attribute]
pub fn dom_struct(_: TokenStream, input: TokenStream) -> TokenStream {
// Construct the expected output tokens - the input but with a `#[derive(DomObject)]` applied.
let attributes: TokenStream =
"#[derive(DomObject)]".to_string().parse().unwrap();
let output: TokenStream = attributes.into_iter()
.chain(input.into_iter()).collect();
let mut tokens: Vec<_> = output.into_iter().collect();
// Adjust the spacing of `>` tokens to match what `quote` would produce.
for token in tokens.iter_mut() {
if let TokenTree::Group(group) = token {
let mut tokens: Vec<_> = group.stream().into_iter().collect();
for token in tokens.iter_mut() {
if let TokenTree::Punct(p) = token {
if p.as_char() == '>' {
*p = Punct::new('>', Spacing::Alone);
}
}
}
let mut stream = TokenStream::new();
stream.extend(tokens);
*group = Group::new(group.delimiter(), stream);
}
}
let mut output = TokenStream::new();
output.extend(tokens);
output
}

View file

@ -0,0 +1,24 @@
// aux-build:issue-61963.rs
// aux-build:issue-61963-1.rs
#![deny(bare_trait_objects)]
#[macro_use]
extern crate issue_61963;
#[macro_use]
extern crate issue_61963_1;
// This test checks that the bare trait object lint does not trigger on macro attributes that
// generate code which would trigger the lint.
pub struct Baz;
pub trait Bar { }
pub struct Qux<T>(T);
#[dom_struct]
pub struct Foo {
qux: Qux<Qux<Baz>>,
bar: Box<Bar>,
//~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
}
fn main() {}

View file

@ -0,0 +1,14 @@
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-61963.rs:20:14
|
LL | bar: Box<Bar>,
| ^^^ help: use `dyn`: `dyn Bar`
|
note: lint level defined here
--> $DIR/issue-61963.rs:3:9
|
LL | #![deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error