Auto merge of #129202 - matthiaskrgr:rollup-wev7uur, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #128989 (Emit an error for invalid use of the linkage attribute) - #129167 (mir/pretty: use `Option` instead of `Either<Once, Empty>`) - #129168 (Return correct HirId when finding body owner in diagnostics) - #129191 (rustdoc-json: Clean up serialization and printing.) - #129192 (Remove useless attributes in merged doctest generated code) - #129196 (Remove a useless ref/id/ref round-trip from `pattern_from_hir`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0f26ee4fd9
15 changed files with 357 additions and 101 deletions
|
@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
||||||
let mut iter = self.parent_iter(id).peekable();
|
let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
|
||||||
let mut ignore_tail = false;
|
|
||||||
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
|
|
||||||
// When dealing with `return` statements, we don't care about climbing only tail
|
|
||||||
// expressions.
|
|
||||||
ignore_tail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut prev_hir_id = None;
|
// Return `None` if the `id` expression is not the returned value of the enclosing body
|
||||||
while let Some((hir_id, node)) = iter.next() {
|
let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
|
||||||
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
|
while let Some(cur_id) = iter.next() {
|
||||||
match next_node {
|
if enclosing_body_owner == cur_id {
|
||||||
Node::Block(Block { expr: None, .. }) => return None,
|
break;
|
||||||
// The current node is not the tail expression of its parent.
|
}
|
||||||
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
|
|
||||||
|
// A return statement is always the value returned from the enclosing body regardless of
|
||||||
|
// what the parent expressions are.
|
||||||
|
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current expression's value doesnt get used as the parent expressions value then return `None`
|
||||||
|
if let Some(&parent_id) = iter.peek() {
|
||||||
|
match self.tcx.hir_node(parent_id) {
|
||||||
|
// The current node is not the tail expression of the block expression parent expr.
|
||||||
|
Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
|
||||||
Node::Block(Block { expr: Some(e), .. })
|
Node::Block(Block { expr: Some(e), .. })
|
||||||
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The current expression's value does not pass up through these parent expressions
|
||||||
|
Node::Block(Block { expr: None, .. })
|
||||||
|
| Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
|
||||||
|
| Node::LetStmt(..) => return None,
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match node {
|
|
||||||
Node::Item(_)
|
|
||||||
| Node::ForeignItem(_)
|
|
||||||
| Node::TraitItem(_)
|
|
||||||
| Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
|
|
||||||
| Node::ImplItem(_)
|
|
||||||
// The input node `id` must be enclosed in the method's body as opposed
|
|
||||||
// to some other place such as its return type (fixes #114918).
|
|
||||||
// We verify that indirectly by checking that the previous node is the
|
|
||||||
// current node's body
|
|
||||||
if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
|
|
||||||
return Some(hir_id)
|
|
||||||
}
|
|
||||||
// Ignore `return`s on the first iteration
|
|
||||||
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
|
|
||||||
| Node::LetStmt(_) => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_hir_id = Some(hir_id);
|
|
||||||
}
|
}
|
||||||
None
|
|
||||||
|
Some(enclosing_body_owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
|
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
|
||||||
|
|
|
@ -1418,21 +1418,19 @@ pub fn write_allocations<'tcx>(
|
||||||
alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
|
alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
|
fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option<AllocId> {
|
||||||
match val {
|
match val {
|
||||||
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
|
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()),
|
||||||
Either::Left(std::iter::once(ptr.provenance.alloc_id()))
|
ConstValue::Scalar(interpret::Scalar::Int { .. }) => None,
|
||||||
}
|
ConstValue::ZeroSized => None,
|
||||||
ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
|
|
||||||
ConstValue::ZeroSized => Either::Right(std::iter::empty()),
|
|
||||||
ConstValue::Slice { .. } => {
|
ConstValue::Slice { .. } => {
|
||||||
// `u8`/`str` slices, shouldn't contain pointers that we want to print.
|
// `u8`/`str` slices, shouldn't contain pointers that we want to print.
|
||||||
Either::Right(std::iter::empty())
|
None
|
||||||
}
|
}
|
||||||
ConstValue::Indirect { alloc_id, .. } => {
|
ConstValue::Indirect { alloc_id, .. } => {
|
||||||
// FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
|
// FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
|
||||||
// Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
|
// Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
|
||||||
Either::Left(std::iter::once(alloc_id))
|
Some(alloc_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1443,7 +1441,9 @@ pub fn write_allocations<'tcx>(
|
||||||
match c.const_ {
|
match c.const_ {
|
||||||
Const::Ty(_, _) | Const::Unevaluated(..) => {}
|
Const::Ty(_, _) | Const::Unevaluated(..) => {}
|
||||||
Const::Val(val, _) => {
|
Const::Val(val, _) => {
|
||||||
self.0.extend(alloc_ids_from_const_val(val));
|
if let Some(id) = alloc_id_from_const_val(val) {
|
||||||
|
self.0.insert(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{HirId, Node};
|
use rustc_hir::HirId;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
|
@ -110,11 +110,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
|
fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
|
||||||
let p = match self.tcx.hir_node(p.hir_id) {
|
|
||||||
Node::Pat(p) => p,
|
|
||||||
node => bug!("pattern became {:?}", node),
|
|
||||||
};
|
|
||||||
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
|
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -430,6 +430,10 @@ passes_link_section =
|
||||||
.warn = {-passes_previously_accepted}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = not a function or static
|
.label = not a function or static
|
||||||
|
|
||||||
|
passes_linkage =
|
||||||
|
attribute should be applied to a function or static
|
||||||
|
.label = not a function definition or static
|
||||||
|
|
||||||
passes_macro_export =
|
passes_macro_export =
|
||||||
`#[macro_export]` only has an effect on macro definitions
|
`#[macro_export]` only has an effect on macro definitions
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
[sym::coroutine, ..] => {
|
[sym::coroutine, ..] => {
|
||||||
self.check_coroutine(attr, target);
|
self.check_coroutine(attr, target);
|
||||||
}
|
}
|
||||||
|
[sym::linkage, ..] => self.check_linkage(attr, span, target),
|
||||||
[
|
[
|
||||||
// ok
|
// ok
|
||||||
sym::allow
|
sym::allow
|
||||||
|
@ -256,7 +257,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
| sym::cfi_encoding // FIXME(cfi_encoding)
|
| sym::cfi_encoding // FIXME(cfi_encoding)
|
||||||
| sym::may_dangle // FIXME(dropck_eyepatch)
|
| sym::may_dangle // FIXME(dropck_eyepatch)
|
||||||
| sym::pointee // FIXME(derive_smart_pointer)
|
| sym::pointee // FIXME(derive_smart_pointer)
|
||||||
| sym::linkage // FIXME(linkage)
|
|
||||||
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
|
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
|
||||||
| sym::used // handled elsewhere to restrict to static items
|
| sym::used // handled elsewhere to restrict to static items
|
||||||
| sym::repr // handled elsewhere to restrict to type decls items
|
| sym::repr // handled elsewhere to restrict to type decls items
|
||||||
|
@ -2347,6 +2347,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
|
||||||
|
match target {
|
||||||
|
Target::Fn
|
||||||
|
| Target::Method(..)
|
||||||
|
| Target::Static
|
||||||
|
| Target::ForeignStatic
|
||||||
|
| Target::ForeignFn => {}
|
||||||
|
_ => {
|
||||||
|
self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||||
|
|
|
@ -643,6 +643,15 @@ pub struct CoroutineOnNonClosure {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(passes_linkage)]
|
||||||
|
pub struct Linkage {
|
||||||
|
#[primary_span]
|
||||||
|
pub attr_span: Span,
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes_empty_confusables)]
|
#[diag(passes_empty_confusables)]
|
||||||
pub(crate) struct EmptyConfusables {
|
pub(crate) struct EmptyConfusables {
|
||||||
|
|
|
@ -75,7 +75,6 @@ impl DocTestRunner {
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(coverage_attribute)]
|
|
||||||
"
|
"
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
|
@ -135,7 +134,6 @@ mod __doctest_mod {{
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#[rustc_main]
|
#[rustc_main]
|
||||||
#[coverage(off)]
|
|
||||||
fn main() -> std::process::ExitCode {{
|
fn main() -> std::process::ExitCode {{
|
||||||
const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}];
|
const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}];
|
||||||
let bin_marker = std::ffi::OsStr::new(__doctest_mod::BIN_OPTION);
|
let bin_marker = std::ffi::OsStr::new(__doctest_mod::BIN_OPTION);
|
||||||
|
@ -235,11 +233,9 @@ fn main() {returns_result} {{
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
"
|
"
|
||||||
#[rustc_test_marker = {test_name:?}]
|
|
||||||
pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
|
pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
|
||||||
{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic},
|
{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic},
|
||||||
test::StaticTestFn(
|
test::StaticTestFn(
|
||||||
#[coverage(off)]
|
|
||||||
|| {{{runner}}},
|
|| {{{runner}}},
|
||||||
));
|
));
|
||||||
}}",
|
}}",
|
||||||
|
|
|
@ -39,8 +39,10 @@ pub(crate) struct JsonRenderer<'tcx> {
|
||||||
/// A mapping of IDs that contains all local items for this crate which gets output as a top
|
/// A mapping of IDs that contains all local items for this crate which gets output as a top
|
||||||
/// level field of the JSON blob.
|
/// level field of the JSON blob.
|
||||||
index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
|
index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
|
||||||
/// The directory where the blob will be written to.
|
/// The directory where the JSON blob should be written to.
|
||||||
out_path: Option<PathBuf>,
|
///
|
||||||
|
/// If this is `None`, the blob will be printed to `stdout` instead.
|
||||||
|
out_dir: Option<PathBuf>,
|
||||||
cache: Rc<Cache>,
|
cache: Rc<Cache>,
|
||||||
imported_items: DefIdSet,
|
imported_items: DefIdSet,
|
||||||
}
|
}
|
||||||
|
@ -101,18 +103,20 @@ impl<'tcx> JsonRenderer<'tcx> {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<T: Write>(
|
fn serialize_and_write<T: Write>(
|
||||||
&self,
|
&self,
|
||||||
output: types::Crate,
|
output_crate: types::Crate,
|
||||||
mut writer: BufWriter<T>,
|
mut writer: BufWriter<T>,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.tcx
|
self.sess().time("rustdoc_json_serialize_and_write", || {
|
||||||
.sess
|
try_err!(
|
||||||
.time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut writer, &output))
|
serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
|
||||||
.unwrap();
|
path
|
||||||
try_err!(writer.flush(), path);
|
);
|
||||||
Ok(())
|
try_err!(writer.flush(), path);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +141,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||||
JsonRenderer {
|
JsonRenderer {
|
||||||
tcx,
|
tcx,
|
||||||
index: Rc::new(RefCell::new(FxHashMap::default())),
|
index: Rc::new(RefCell::new(FxHashMap::default())),
|
||||||
out_path: if options.output_to_stdout { None } else { Some(options.output) },
|
out_dir: if options.output_to_stdout { None } else { Some(options.output) },
|
||||||
cache: Rc::new(cache),
|
cache: Rc::new(cache),
|
||||||
imported_items,
|
imported_items,
|
||||||
},
|
},
|
||||||
|
@ -237,7 +241,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||||
let index = (*self.index).clone().into_inner();
|
let index = (*self.index).clone().into_inner();
|
||||||
|
|
||||||
debug!("Constructing Output");
|
debug!("Constructing Output");
|
||||||
let output = types::Crate {
|
let output_crate = types::Crate {
|
||||||
root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
|
root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
|
||||||
crate_version: self.cache.crate_version.clone(),
|
crate_version: self.cache.crate_version.clone(),
|
||||||
includes_private: self.cache.document_private,
|
includes_private: self.cache.document_private,
|
||||||
|
@ -278,20 +282,20 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||||
.collect(),
|
.collect(),
|
||||||
format_version: types::FORMAT_VERSION,
|
format_version: types::FORMAT_VERSION,
|
||||||
};
|
};
|
||||||
if let Some(ref out_path) = self.out_path {
|
if let Some(ref out_dir) = self.out_dir {
|
||||||
let out_dir = out_path.clone();
|
|
||||||
try_err!(create_dir_all(&out_dir), out_dir);
|
try_err!(create_dir_all(&out_dir), out_dir);
|
||||||
|
|
||||||
let mut p = out_dir;
|
let mut p = out_dir.clone();
|
||||||
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
|
p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
|
||||||
p.set_extension("json");
|
p.set_extension("json");
|
||||||
self.write(
|
|
||||||
output,
|
self.serialize_and_write(
|
||||||
|
output_crate,
|
||||||
BufWriter::new(try_err!(File::create(&p), p)),
|
BufWriter::new(try_err!(File::create(&p), p)),
|
||||||
&p.display().to_string(),
|
&p.display().to_string(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.write(output, BufWriter::new(stdout()), "<stdout>")
|
self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "<stdout>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//@ known-bug: rust-lang/rust#128810
|
|
||||||
|
|
||||||
#![feature(fn_delegation)]
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
|
||||||
|
|
||||||
impl<'a> InvariantRef<'a, ()> {
|
|
||||||
pub const NEW: Self = InvariantRef::new(&());
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Trait {
|
|
||||||
fn foo(&self) -> u8 { 0 }
|
|
||||||
fn bar(&self) -> u8 { 1 }
|
|
||||||
fn meh(&self) -> u8 { 2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Z(u8);
|
|
||||||
|
|
||||||
impl Trait for Z {
|
|
||||||
reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() { }
|
|
42
tests/ui/attributes/linkage.rs
Normal file
42
tests/ui/attributes/linkage.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#![feature(linkage)]
|
||||||
|
#![feature(stmt_expr_attributes)]
|
||||||
|
#![deny(unused_attributes)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
|
||||||
|
type InvalidTy = ();
|
||||||
|
|
||||||
|
#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
|
||||||
|
mod invalid_module {}
|
||||||
|
|
||||||
|
#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
|
||||||
|
struct F;
|
||||||
|
|
||||||
|
#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
|
||||||
|
impl F {
|
||||||
|
#[linkage = "weak"]
|
||||||
|
fn valid(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[linkage = "weak"]
|
||||||
|
fn f() {
|
||||||
|
#[linkage = "weak"]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
//~^^^^ ERROR attribute should be applied to a function or static
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[linkage = "weak"]
|
||||||
|
static A: *const ();
|
||||||
|
|
||||||
|
#[linkage = "weak"]
|
||||||
|
fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = #[linkage = "weak"]
|
||||||
|
(|| 1);
|
||||||
|
//~^^ ERROR attribute should be applied to a function or static
|
||||||
|
}
|
55
tests/ui/attributes/linkage.stderr
Normal file
55
tests/ui/attributes/linkage.stderr
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:6:1
|
||||||
|
|
|
||||||
|
LL | #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | type InvalidTy = ();
|
||||||
|
| -------------------- not a function definition or static
|
||||||
|
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:9:1
|
||||||
|
|
|
||||||
|
LL | #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | mod invalid_module {}
|
||||||
|
| --------------------- not a function definition or static
|
||||||
|
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:12:1
|
||||||
|
|
|
||||||
|
LL | #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | struct F;
|
||||||
|
| --------- not a function definition or static
|
||||||
|
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:15:1
|
||||||
|
|
|
||||||
|
LL | #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | / impl F {
|
||||||
|
LL | | #[linkage = "weak"]
|
||||||
|
LL | | fn valid(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_- not a function definition or static
|
||||||
|
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:23:5
|
||||||
|
|
|
||||||
|
LL | #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | / {
|
||||||
|
LL | | 1
|
||||||
|
LL | | };
|
||||||
|
| |_____- not a function definition or static
|
||||||
|
|
||||||
|
error: attribute should be applied to a function or static
|
||||||
|
--> $DIR/linkage.rs:39:13
|
||||||
|
|
|
||||||
|
LL | let _ = #[linkage = "weak"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | (|| 1);
|
||||||
|
| ------ not a function definition or static
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#![feature(fn_delegation)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||||
|
|
||||||
|
impl<'a> InvariantRef<'a, ()> {
|
||||||
|
pub const NEW: Self = InvariantRef::new(&());
|
||||||
|
//~^ ERROR: no function or associated item named `new` found
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn foo(&self) -> u8 { 0 }
|
||||||
|
fn bar(&self) -> u8 { 1 }
|
||||||
|
fn meh(&self) -> u8 { 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Z(u8);
|
||||||
|
|
||||||
|
impl Trait for Z {
|
||||||
|
reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
//~^ ERROR: use of undeclared lifetime name `'a`
|
||||||
|
//~| ERROR: use of undeclared lifetime name `'a`
|
||||||
|
//~| ERROR: use of undeclared lifetime name `'a`
|
||||||
|
//~| ERROR: the trait bound `u8: Trait` is not satisfied
|
||||||
|
//~| ERROR: the trait bound `u8: Trait` is not satisfied
|
||||||
|
//~| ERROR: the trait bound `u8: Trait` is not satisfied
|
||||||
|
//~| ERROR: mismatched types
|
||||||
|
//~| ERROR: mismatched types
|
||||||
|
//~| ERROR: mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,113 @@
|
||||||
|
error[E0261]: use of undeclared lifetime name `'a`
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ undeclared lifetime
|
||||||
|
|
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| +++
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | impl<'a> Trait for Z {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0261]: use of undeclared lifetime name `'a`
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ undeclared lifetime
|
||||||
|
|
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| +++
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | impl<'a> Trait for Z {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0261]: use of undeclared lifetime name `'a`
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ undeclared lifetime
|
||||||
|
|
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| +++
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | impl<'a> Trait for Z {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
|
||||||
|
|
|
||||||
|
LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||||
|
| -------------------------------------- function or associated item `new` not found for this struct
|
||||||
|
...
|
||||||
|
LL | pub const NEW: Self = InvariantRef::new(&());
|
||||||
|
| ^^^ function or associated item not found in `InvariantRef<'_, _>`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
||||||
|
|
|
||||||
|
= note: expected type `u8`
|
||||||
|
found struct `InvariantRef<'_, ()>`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `u8: Trait` is not satisfied
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ the trait `Trait` is not implemented for `u8`
|
||||||
|
|
|
||||||
|
= help: the trait `Trait` is implemented for `Z`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
||||||
|
|
|
||||||
|
= note: expected type `u8`
|
||||||
|
found struct `InvariantRef<'_, ()>`
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `u8: Trait` is not satisfied
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ the trait `Trait` is not implemented for `u8`
|
||||||
|
|
|
||||||
|
= help: the trait `Trait` is implemented for `Z`
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
||||||
|
|
|
||||||
|
= note: expected type `u8`
|
||||||
|
found struct `InvariantRef<'_, ()>`
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `u8: Trait` is not satisfied
|
||||||
|
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
||||||
|
|
|
||||||
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||||
|
| ^^ the trait `Trait` is not implemented for `u8`
|
||||||
|
|
|
||||||
|
= help: the trait `Trait` is implemented for `Z`
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0261, E0277, E0308, E0599.
|
||||||
|
For more information about an error, try `rustc --explain E0261`.
|
16
tests/ui/typeck/const-in-fn-call-generics.rs
Normal file
16
tests/ui/typeck/const-in-fn-call-generics.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
fn generic<const N: u32>() {}
|
||||||
|
|
||||||
|
trait Collate<const A: u32> {
|
||||||
|
type Pass;
|
||||||
|
fn collate(self) -> Self::Pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const B: u32> Collate<B> for i32 {
|
||||||
|
type Pass = ();
|
||||||
|
fn collate(self) -> Self::Pass {
|
||||||
|
generic::<{ true }>()
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
9
tests/ui/typeck/const-in-fn-call-generics.stderr
Normal file
9
tests/ui/typeck/const-in-fn-call-generics.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/const-in-fn-call-generics.rs:11:21
|
||||||
|
|
|
||||||
|
LL | generic::<{ true }>()
|
||||||
|
| ^^^^ expected `u32`, found `bool`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue