Auto merge of #145366 - GuillaumeGomez:rollup-v0a6v3u, r=GuillaumeGomez

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#144761 (aarch64: Make `outline-atomics` a known target feature)
 - rust-lang/rust#144949 (More `Printer` cleanups)
 - rust-lang/rust#144955 (search graph: lazily update parent goals)
 - rust-lang/rust#144962 (Add aarch64_be-unknown-none-softfloat target)
 - rust-lang/rust#145153 (Handle macros with multiple kinds, and improve errors)
 - rust-lang/rust#145241 ([AVR] Changed data_layout)
 - rust-lang/rust#145341 (Install libgccjit into the compiler's sysroot when cg_gcc is enabled)
 - rust-lang/rust#145349 (Correctly handle when there are no unstable items in the documented crate)
 - rust-lang/rust#145356 (Add another example for escaped `#` character in doctest in rustdoc book)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-08-13 19:23:12 +00:00
commit 3672a55b7c
61 changed files with 946 additions and 508 deletions

View file

@ -3889,6 +3889,7 @@ dependencies = [
name = "rustc_hir"
version = "0.0.0"
dependencies = [
"bitflags",
"odht",
"rustc_abi",
"rustc_arena",

View file

@ -436,14 +436,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let body = Box::new(self.lower_delim_args(body));
let def_id = self.local_def_id(id);
let def_kind = self.tcx.def_kind(def_id);
let DefKind::Macro(macro_kind) = def_kind else {
let DefKind::Macro(macro_kinds) = def_kind else {
unreachable!(
"expected DefKind::Macro for macro item, found {}",
def_kind.descr(def_id.to_def_id())
);
};
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
hir::ItemKind::Macro(ident, macro_def, macro_kind)
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
}
ItemKind::Delegation(box delegation) => {
let delegation_results = self.lower_delegation(delegation, id, false);

View file

@ -213,6 +213,12 @@ pub(crate) unsafe fn create_module<'ll>(
target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128")
}
}
if llvm_version < (22, 0, 0) {
if sess.target.arch == "avr" {
// LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010
target_data_layout = target_data_layout.replace("n8:16", "n8")
}
}
// Ensure the data-layout values hardcoded remain the defaults.
{

View file

@ -7,12 +7,12 @@ use rustc_middle::bug;
use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
struct AbsolutePathPrinter<'tcx> {
struct TypeNamePrinter<'tcx> {
tcx: TyCtxt<'tcx>,
path: String,
}
impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@ -75,26 +75,26 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
self.pretty_print_dyn_existential(predicates)
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.path.push_str(self.tcx.crate_name(cnum).as_str());
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.pretty_path_qualified(self_ty, trait_ref)
self.pretty_print_path_with_qualified(self_ty, trait_ref)
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.pretty_path_append_impl(
self.pretty_print_path_with_impl(
|cx| {
print_prefix(cx)?;
@ -107,7 +107,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
)
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -119,7 +119,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
Ok(())
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
args: &[GenericArg<'tcx>],
@ -135,7 +135,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
}
}
impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
false
}
@ -159,7 +159,7 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
}
}
impl Write for AbsolutePathPrinter<'_> {
impl Write for TypeNamePrinter<'_> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.path.push_str(s);
Ok(())
@ -167,7 +167,7 @@ impl Write for AbsolutePathPrinter<'_> {
}
pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let mut p = AbsolutePathPrinter { tcx, path: String::new() };
let mut p = TypeNamePrinter { tcx, path: String::new() };
p.print_type(ty).unwrap();
p.path
}

View file

@ -17,6 +17,7 @@ use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
use rustc_hir::def::MacroKinds;
use rustc_hir::{Stability, find_attr};
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
use rustc_parse::MACRO_ARGUMENTS;
@ -718,6 +719,9 @@ impl MacResult for DummyResult {
/// A syntax extension kind.
#[derive(Clone)]
pub enum SyntaxExtensionKind {
/// A `macro_rules!` macro that can work as any `MacroKind`
MacroRules(Arc<crate::MacroRulesMacroExpander>),
/// A token-based function-like macro.
Bang(
/// An expander with signature TokenStream -> TokenStream.
@ -772,9 +776,39 @@ pub enum SyntaxExtensionKind {
),
/// A glob delegation.
///
/// This is for delegated function implementations, and has nothing to do with glob imports.
GlobDelegation(Arc<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
}
impl SyntaxExtensionKind {
/// Returns `Some(expander)` for a macro usable as a `LegacyBang`; otherwise returns `None`
///
/// This includes a `MacroRules` with function-like rules.
pub fn as_legacy_bang(&self) -> Option<&(dyn TTMacroExpander + sync::DynSync + sync::DynSend)> {
match self {
SyntaxExtensionKind::LegacyBang(exp) => Some(exp.as_ref()),
SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::BANG) => {
Some(exp.as_ref())
}
_ => None,
}
}
/// Returns `Some(expander)` for a macro usable as an `Attr`; otherwise returns `None`
///
/// This includes a `MacroRules` with `attr` rules.
pub fn as_attr(&self) -> Option<&(dyn AttrProcMacro + sync::DynSync + sync::DynSend)> {
match self {
SyntaxExtensionKind::Attr(exp) => Some(exp.as_ref()),
SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::ATTR) => {
Some(exp.as_ref())
}
_ => None,
}
}
}
/// A struct representing a macro definition in "lowered" form ready for expansion.
pub struct SyntaxExtension {
/// A syntax extension kind.
@ -804,18 +838,19 @@ pub struct SyntaxExtension {
}
impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn macro_kind(&self) -> MacroKind {
/// Returns which kinds of macro call this syntax extension.
pub fn macro_kinds(&self) -> MacroKinds {
match self.kind {
SyntaxExtensionKind::Bang(..)
| SyntaxExtensionKind::LegacyBang(..)
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
| SyntaxExtensionKind::GlobDelegation(..) => MacroKinds::BANG,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
| SyntaxExtensionKind::NonMacroAttr => MacroKinds::ATTR,
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
MacroKind::Derive
MacroKinds::DERIVE
}
SyntaxExtensionKind::MacroRules(ref m) => m.kinds(),
}
}
@ -1024,11 +1059,12 @@ impl SyntaxExtension {
parent: LocalExpnId,
call_site: Span,
descr: Symbol,
kind: MacroKind,
macro_def_id: Option<DefId>,
parent_module: Option<DefId>,
) -> ExpnData {
ExpnData::new(
ExpnKind::Macro(self.macro_kind(), descr),
ExpnKind::Macro(kind, descr),
parent.to_expn_id(),
call_site,
self.span,

View file

@ -736,8 +736,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, span } => match ext {
SyntaxExtensionKind::Bang(expander) => {
InvocationKind::Bang { mac, span } => {
if let SyntaxExtensionKind::Bang(expander) = ext {
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
Ok(tok_result) => {
let fragment =
@ -755,8 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
}
}
SyntaxExtensionKind::LegacyBang(expander) => {
} else if let Some(expander) = ext.as_legacy_bang() {
let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
ExpandResult::Ready(tok_result) => tok_result,
ExpandResult::Retry(_) => {
@ -776,11 +775,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
fragment_kind.dummy(span, guar)
}
} else {
unreachable!();
}
_ => unreachable!(),
},
InvocationKind::Attr { attr, pos, mut item, derives } => match ext {
SyntaxExtensionKind::Attr(expander) => {
}
InvocationKind::Attr { attr, pos, mut item, derives } => {
if let Some(expander) = ext.as_attr() {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
let tokens = match &item {
@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
}
}
SyntaxExtensionKind::LegacyAttr(expander) => {
} else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
Ok(meta) => {
let item_clone = macro_stats.then(|| item.clone());
@ -878,15 +877,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
fragment_kind.expect_from_annotatables(iter::once(item))
}
}
}
SyntaxExtensionKind::NonMacroAttr => {
} else if let SyntaxExtensionKind::NonMacroAttr = ext {
// `-Zmacro-stats` ignores these because they don't do any real expansion.
self.cx.expanded_inert_attrs.mark(&attr);
item.visit_attrs(|attrs| attrs.insert(pos, attr));
fragment_kind.expect_from_annotatables(iter::once(item))
} else {
unreachable!();
}
_ => unreachable!(),
},
}
InvocationKind::Derive { path, item, is_const } => match ext {
SyntaxExtensionKind::Derive(expander)
| SyntaxExtensionKind::LegacyDerive(expander) => {

View file

@ -58,18 +58,6 @@ pub(super) fn failed_to_match_macro(
let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
else {
// FIXME: we should report this at macro resolution time, as we do for
// `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a
// Def.
if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) {
let msg = format!("macro has no rules for function-like invocation `{name}!`");
let mut err = psess.dcx().struct_span_err(sp, msg);
if !def_head_span.is_dummy() {
let msg = "this macro has no rules for function-like invocation";
err.span_label(def_head_span, msg);
}
return (sp, err.emit());
}
return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
};

View file

@ -357,10 +357,10 @@ enum NestedMacroState {
/// The token `macro_rules` was processed.
MacroRules,
/// The tokens `macro_rules!` were processed.
MacroRulesNot,
MacroRulesBang,
/// The tokens `macro_rules!` followed by a name were processed. The name may be either directly
/// an identifier or a meta-variable (that hopefully would be instantiated by an identifier).
MacroRulesNotName,
MacroRulesBangName,
/// The keyword `macro` was processed.
Macro,
/// The keyword `macro` followed by a name was processed.
@ -408,24 +408,24 @@ fn check_nested_occurrences(
NestedMacroState::MacroRules,
&TokenTree::Token(Token { kind: TokenKind::Bang, .. }),
) => {
state = NestedMacroState::MacroRulesNot;
state = NestedMacroState::MacroRulesBang;
}
(
NestedMacroState::MacroRulesNot,
NestedMacroState::MacroRulesBang,
&TokenTree::Token(Token { kind: TokenKind::Ident(..), .. }),
) => {
state = NestedMacroState::MacroRulesNotName;
state = NestedMacroState::MacroRulesBangName;
}
(NestedMacroState::MacroRulesNot, &TokenTree::MetaVar(..)) => {
state = NestedMacroState::MacroRulesNotName;
(NestedMacroState::MacroRulesBang, &TokenTree::MetaVar(..)) => {
state = NestedMacroState::MacroRulesBangName;
// We check that the meta-variable is correctly used.
check_occurrences(psess, node_id, tt, macros, binders, ops, guar);
}
(NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del))
(NestedMacroState::MacroRulesBangName, TokenTree::Delimited(.., del))
| (NestedMacroState::MacroName, TokenTree::Delimited(.., del))
if del.delim == Delimiter::Brace =>
{
let macro_rules = state == NestedMacroState::MacroRulesNotName;
let macro_rules = state == NestedMacroState::MacroRulesBangName;
state = NestedMacroState::Empty;
let rest =
check_nested_macro(psess, node_id, macro_rules, &del.tts, &nested_macros, guar);

View file

@ -15,6 +15,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::MacroKinds;
use rustc_hir::find_attr;
use rustc_lint_defs::BuiltinLintDiag;
use rustc_lint_defs::builtin::{
@ -144,6 +145,7 @@ pub struct MacroRulesMacroExpander {
name: Ident,
span: Span,
transparency: Transparency,
kinds: MacroKinds,
rules: Vec<MacroRule>,
}
@ -158,6 +160,10 @@ impl MacroRulesMacroExpander {
};
if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) }
}
pub fn kinds(&self) -> MacroKinds {
self.kinds
}
}
impl TTMacroExpander for MacroRulesMacroExpander {
@ -540,13 +546,13 @@ pub fn compile_declarative_macro(
span: Span,
node_id: NodeId,
edition: Edition,
) -> (SyntaxExtension, Option<Arc<SyntaxExtension>>, usize) {
) -> (SyntaxExtension, usize) {
let mk_syn_ext = |kind| {
let is_local = is_defined_in_current_crate(node_id);
SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
};
let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander));
let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0);
let dummy_syn_ext =
|guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0);
let macro_rules = macro_def.macro_rules;
let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@ -559,12 +565,12 @@ pub fn compile_declarative_macro(
let mut guar = None;
let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
let mut has_attr_rules = false;
let mut kinds = MacroKinds::empty();
let mut rules = Vec::new();
while p.token != token::Eof {
let args = if p.eat_keyword_noexpect(sym::attr) {
has_attr_rules = true;
kinds |= MacroKinds::ATTR;
if !features.macro_attr() {
feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable")
.emit();
@ -581,6 +587,7 @@ pub fn compile_declarative_macro(
}
Some(args)
} else {
kinds |= MacroKinds::BANG;
None
};
let lhs_tt = p.parse_token_tree();
@ -627,6 +634,7 @@ pub fn compile_declarative_macro(
let guar = sess.dcx().span_err(span, "macros must contain at least one rule");
return dummy_syn_ext(guar);
}
assert!(!kinds.is_empty());
let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
.unwrap_or(Transparency::fallback(macro_rules));
@ -640,12 +648,8 @@ pub fn compile_declarative_macro(
// Return the number of rules for unused rule linting, if this is a local macro.
let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 };
let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
let opt_attr_ext = has_attr_rules.then(|| {
let exp = Arc::clone(&exp);
Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp)))
});
(mk_bang_ext(exp), opt_attr_ext, nrules)
let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules };
(mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules)
}
fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<ErrorGuaranteed> {

View file

@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.9.1"
odht = { version = "0.3.1", features = ["nightly"] }
rustc_abi = { path = "../rustc_abi" }
rustc_arena = { path = "../rustc_arena" }

View file

@ -31,6 +31,53 @@ pub enum CtorKind {
Const,
}
/// A set of macro kinds, for macros that can have more than one kind
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
#[derive(HashStable_Generic)]
pub struct MacroKinds(u8);
bitflags::bitflags! {
impl MacroKinds: u8 {
const BANG = 1 << 0;
const ATTR = 1 << 1;
const DERIVE = 1 << 2;
}
}
impl From<MacroKind> for MacroKinds {
fn from(kind: MacroKind) -> Self {
match kind {
MacroKind::Bang => Self::BANG,
MacroKind::Attr => Self::ATTR,
MacroKind::Derive => Self::DERIVE,
}
}
}
impl MacroKinds {
/// Convert the MacroKinds to a static string.
///
/// This hardcodes all the possibilities, in order to return a static string.
pub fn descr(self) -> &'static str {
match self {
// FIXME: change this to "function-like macro" and fix all tests
Self::BANG => "macro",
Self::ATTR => "attribute macro",
Self::DERIVE => "derive macro",
_ if self == (Self::ATTR | Self::BANG) => "attribute/function macro",
_ if self == (Self::DERIVE | Self::BANG) => "derive/function macro",
_ if self == (Self::ATTR | Self::DERIVE) => "attribute/derive macro",
_ if self.is_all() => "attribute/derive/function macro",
_ if self.is_empty() => "useless macro",
_ => unreachable!(),
}
}
/// Return an indefinite article (a/an) for use with `descr()`
pub fn article(self) -> &'static str {
if self.contains(Self::ATTR) { "an" } else { "a" }
}
}
/// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`.
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
pub enum NonMacroAttrKind {
@ -101,7 +148,7 @@ pub enum DefKind {
AssocConst,
// Macro namespace
Macro(MacroKind),
Macro(MacroKinds),
// Not namespaced (or they are, but we don't treat them so)
ExternCrate,
@ -177,7 +224,7 @@ impl DefKind {
DefKind::AssocConst => "associated constant",
DefKind::TyParam => "type parameter",
DefKind::ConstParam => "const parameter",
DefKind::Macro(macro_kind) => macro_kind.descr(),
DefKind::Macro(kinds) => kinds.descr(),
DefKind::LifetimeParam => "lifetime parameter",
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
@ -208,7 +255,7 @@ impl DefKind {
| DefKind::Use
| DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
DefKind::Macro(kinds) => kinds.article(),
_ => "a",
}
}
@ -845,10 +892,10 @@ impl<Id> Res<Id> {
)
}
pub fn macro_kind(self) -> Option<MacroKind> {
pub fn macro_kinds(self) -> Option<MacroKinds> {
match self {
Res::Def(DefKind::Macro(kind), _) => Some(kind),
Res::NonMacroAttr(..) => Some(MacroKind::Attr),
Res::Def(DefKind::Macro(kinds), _) => Some(kinds),
Res::NonMacroAttr(..) => Some(MacroKinds::ATTR),
_ => None,
}
}

View file

@ -20,7 +20,6 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use rustc_target::asm::InlineAsmRegOrRegClass;
@ -30,7 +29,7 @@ use tracing::debug;
use crate::LangItem;
use crate::attrs::AttributeKind;
use crate::def::{CtorKind, DefKind, PerNS, Res};
use crate::def::{CtorKind, DefKind, MacroKinds, PerNS, Res};
use crate::def_id::{DefId, LocalDefIdMap};
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::{FnKind, VisitorExt};
@ -4157,7 +4156,7 @@ impl<'hir> Item<'hir> {
expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId),
ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body);
expect_macro, (Ident, &ast::MacroDef, MacroKind),
expect_macro, (Ident, &ast::MacroDef, MacroKinds),
ItemKind::Macro(ident, def, mk), (*ident, def, *mk);
expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m);
@ -4336,7 +4335,7 @@ pub enum ItemKind<'hir> {
has_body: bool,
},
/// A MBE macro definition (`macro_rules!` or `macro`).
Macro(Ident, &'hir ast::MacroDef, MacroKind),
Macro(Ident, &'hir ast::MacroDef, MacroKinds),
/// A module.
Mod(Ident, &'hir Mod<'hir>),
/// An external module, e.g. `extern { .. }`.

View file

@ -745,12 +745,12 @@ impl<'tcx> LateContext<'tcx> {
/// }
/// ```
pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
struct AbsolutePathPrinter<'tcx> {
struct LintPathPrinter<'tcx> {
tcx: TyCtxt<'tcx>,
path: Vec<Symbol>,
}
impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@ -774,12 +774,12 @@ impl<'tcx> LateContext<'tcx> {
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.path = vec![self.tcx.crate_name(cnum)];
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
@ -800,7 +800,7 @@ impl<'tcx> LateContext<'tcx> {
})
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
@ -825,7 +825,7 @@ impl<'tcx> LateContext<'tcx> {
Ok(())
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -844,7 +844,7 @@ impl<'tcx> LateContext<'tcx> {
Ok(())
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_args: &[GenericArg<'tcx>],
@ -853,7 +853,7 @@ impl<'tcx> LateContext<'tcx> {
}
}
let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
let mut p = LintPathPrinter { tcx: self.tcx, path: vec![] };
p.print_def_path(def_id, &[]).unwrap();
p.path
}

View file

@ -5,7 +5,7 @@ use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::{ExpnKind, MacroKind, Span, kw, sym};
use rustc_span::{ExpnKind, Span, kw, sym};
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
},
)
}
ItemKind::Macro(_, _macro, MacroKind::Bang)
ItemKind::Macro(_, _macro, _kinds)
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
{
cx.emit_span_lint(

View file

@ -1981,7 +1981,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
def_key.disambiguated_data.data = DefPathData::MacroNs(name);
let def_id = id.to_def_id();
self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind.into()));
self.tables.proc_macro.set_some(def_id.index, macro_kind);
self.encode_attrs(id);
record!(self.tables.def_keys[def_id] <- def_key);

View file

@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, ReprOptions, VariantIdx};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::svh::Svh;
use rustc_hir::attrs::StrippedCfgItem;
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, MacroKinds};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items::LangItem;

View file

@ -81,7 +81,7 @@ impl FixedSizeEncoding for u64 {
}
macro_rules! fixed_size_enum {
($ty:ty { $(($($pat:tt)*))* }) => {
($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
impl FixedSizeEncoding for Option<$ty> {
type ByteArray = [u8;1];
@ -103,12 +103,24 @@ macro_rules! fixed_size_enum {
b[0] = match self {
None => unreachable!(),
$(Some($($pat)*) => 1 + ${index()},)*
$(Some($($($upat)*)|+) => unreachable!(),)?
}
}
}
}
}
// Workaround; need const traits to construct bitflags in a const
macro_rules! const_macro_kinds {
($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+))
}
const MACRO_KINDS_ATTR_BANG: MacroKinds = const_macro_kinds!(ATTR, BANG);
const MACRO_KINDS_DERIVE_BANG: MacroKinds = const_macro_kinds!(DERIVE, BANG);
const MACRO_KINDS_DERIVE_ATTR: MacroKinds = const_macro_kinds!(DERIVE, ATTR);
const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = const_macro_kinds!(DERIVE, ATTR, BANG);
// Ensure that we get a compilation error if MacroKinds gets extended without updating metadata.
const _: () = assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all());
fixed_size_enum! {
DefKind {
( Mod )
@ -151,10 +163,16 @@ fixed_size_enum! {
( Ctor(CtorOf::Struct, CtorKind::Const) )
( Ctor(CtorOf::Variant, CtorKind::Fn) )
( Ctor(CtorOf::Variant, CtorKind::Const) )
( Macro(MacroKind::Bang) )
( Macro(MacroKind::Attr) )
( Macro(MacroKind::Derive) )
( Macro(MacroKinds::BANG) )
( Macro(MacroKinds::ATTR) )
( Macro(MacroKinds::DERIVE) )
( Macro(MACRO_KINDS_ATTR_BANG) )
( Macro(MACRO_KINDS_DERIVE_ATTR) )
( Macro(MACRO_KINDS_DERIVE_BANG) )
( Macro(MACRO_KINDS_DERIVE_ATTR_BANG) )
( SyntheticCoroutineBody )
} unreachable {
( Macro(_) )
}
}

View file

@ -1932,7 +1932,7 @@ fn pretty_print_const_value_tcx<'tcx>(
let args = tcx.lift(args).unwrap();
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
p.print_alloc_ids = true;
p.print_value_path(variant_def.def_id, args)?;
p.pretty_print_value_path(variant_def.def_id, args)?;
fmt.write_str(&p.into_buffer())?;
match variant_def.ctor_kind() {
@ -1974,7 +1974,7 @@ fn pretty_print_const_value_tcx<'tcx>(
(ConstValue::ZeroSized, ty::FnDef(d, s)) => {
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
p.print_alloc_ids = true;
p.print_value_path(*d, s)?;
p.pretty_print_value_path(*d, s)?;
fmt.write_str(&p.into_buffer())?;
return Ok(());
}

View file

@ -19,18 +19,16 @@ pub trait Print<'tcx, P> {
fn print(&self, p: &mut P) -> Result<(), PrintError>;
}
/// Interface for outputting user-facing "type-system entities"
/// (paths, types, lifetimes, constants, etc.) as a side-effect
/// (e.g. formatting, like `PrettyPrinter` implementors do) or by
/// constructing some alternative representation (e.g. an AST),
/// which the associated types allow passing through the methods.
///
/// For pretty-printing/formatting in particular, see `PrettyPrinter`.
//
// FIXME(eddyb) find a better name; this is more general than "printing".
/// A trait that "prints" user-facing type system entities: paths, types, lifetimes, constants,
/// etc. "Printing" here means building up a representation of the entity's path, usually as a
/// `String` (e.g. "std::io::Read") or a `Vec<Symbol>` (e.g. `[sym::std, sym::io, sym::Read]`). The
/// representation is built up by appending one or more pieces. The specific details included in
/// the built-up representation depend on the purpose of the printer. The more advanced printers
/// also rely on the `PrettyPrinter` sub-trait.
pub trait Printer<'tcx>: Sized {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
/// Appends a representation of an entity with a normal path, e.g. "std::io::Read".
fn print_def_path(
&mut self,
def_id: DefId,
@ -39,6 +37,7 @@ pub trait Printer<'tcx>: Sized {
self.default_print_def_path(def_id, args)
}
/// Like `print_def_path`, but for `DefPathData::Impl`.
fn print_impl_path(
&mut self,
impl_def_id: DefId,
@ -64,47 +63,66 @@ pub trait Printer<'tcx>: Sized {
self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
}
/// Appends a representation of a region.
fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
/// Appends a representation of a type.
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>;
/// Appends a representation of a list of `PolyExistentialPredicate`s.
fn print_dyn_existential(
&mut self,
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Result<(), PrintError>;
/// Appends a representation of a const.
fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>;
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
/// Appends a representation of a crate name, e.g. `std`, or even ``.
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
fn path_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError>;
fn path_append_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError>;
fn path_append(
/// Appends a representation of a (full or partial) simple path, in two parts. `print_prefix`,
/// when called, appends the representation of the leading segments. The rest of the method
/// appends the representation of the final segment, the details of which are in
/// `disambiguated_data`.
///
/// E.g. `std::io` + `Read` -> `std::io::Read`.
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
) -> Result<(), PrintError>;
fn path_generic_args(
/// Similar to `print_path_with_simple`, but the final segment is an `impl` segment.
///
/// E.g. `slice` + `<impl [T]>` -> `slice::<impl [T]>`, which may then be further appended to,
/// giving a longer path representation such as `slice::<impl [T]>::to_vec_in::ConvertVec`.
fn print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError>;
/// Appends a representation of a path ending in generic args, in two parts. `print_prefix`,
/// when called, appends the leading segments. The rest of the method appends the
/// representation of the generic args. (Some printers choose to skip appending the generic
/// args.)
///
/// E.g. `ImplementsTraitForUsize` + `<usize>` -> `ImplementsTraitForUsize<usize>`.
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
args: &[GenericArg<'tcx>],
) -> Result<(), PrintError>;
fn should_truncate(&mut self) -> bool {
false
}
/// Appends a representation of a qualified path segment, e.g. `<OsString as From<&T>>`.
/// If `trait_ref` is `None`, it may fall back to simpler forms, e.g. `<Vec<T>>` or just `Foo`.
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError>;
// Defaults (should not be overridden):
@ -120,7 +138,7 @@ pub trait Printer<'tcx>: Sized {
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
self.path_crate(def_id.krate)
self.print_crate_name(def_id.krate)
}
DefPathData::Impl => self.print_impl_path(def_id, args),
@ -144,7 +162,7 @@ pub trait Printer<'tcx>: Sized {
)) = self.tcx().coroutine_kind(def_id)
&& args.len() > parent_args.len()
{
return self.path_generic_args(
return self.print_path_with_generic_args(
|p| p.print_def_path(def_id, parent_args),
&args[..parent_args.len() + 1][..1],
);
@ -166,7 +184,7 @@ pub trait Printer<'tcx>: Sized {
_ => {
if !generics.is_own_empty() && args.len() >= generics.count() {
let args = generics.own_args_no_defaults(self.tcx(), args);
return self.path_generic_args(
return self.print_path_with_generic_args(
|p| p.print_def_path(def_id, parent_args),
args,
);
@ -182,7 +200,7 @@ pub trait Printer<'tcx>: Sized {
&& self.tcx().generics_of(parent_def_id).parent_count == 0;
}
self.path_append(
self.print_path_with_simple(
|p: &mut Self| {
if trait_qualify_parent {
let trait_ref = ty::TraitRef::new(
@ -190,7 +208,7 @@ pub trait Printer<'tcx>: Sized {
parent_def_id,
parent_args.iter().copied(),
);
p.path_qualified(trait_ref.self_ty(), Some(trait_ref))
p.print_path_with_qualified(trait_ref.self_ty(), Some(trait_ref))
} else {
p.print_def_path(parent_def_id, parent_args)
}
@ -233,11 +251,15 @@ pub trait Printer<'tcx>: Sized {
// If the impl is not co-located with either self-type or
// trait-type, then fallback to a format that identifies
// the module more clearly.
self.path_append_impl(|p| p.print_def_path(parent_def_id, &[]), self_ty, impl_trait_ref)
self.print_path_with_impl(
|p| p.print_def_path(parent_def_id, &[]),
self_ty,
impl_trait_ref,
)
} else {
// Otherwise, try to give a good form that would be valid language
// syntax. Preferably using associated item notation.
self.path_qualified(self_ty, impl_trait_ref)
self.print_path_with_qualified(self_ty, impl_trait_ref)
}
}
}

View file

@ -245,7 +245,7 @@ impl<'tcx> RegionHighlightMode<'tcx> {
/// Trait for printers that pretty-print using `fmt::Write` to the printer.
pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
/// Like `print_def_path` but for value paths.
fn print_value_path(
fn pretty_print_value_path(
&mut self,
def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
@ -253,7 +253,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
self.print_def_path(def_id, args)
}
fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
fn pretty_print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
where
T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
{
@ -333,6 +333,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
) -> Result<(), PrintError>;
fn should_truncate(&mut self) -> bool {
false
}
/// Returns `true` if the region should be printed in
/// optional positions, e.g., `&'a T` or `dyn Tr + 'b`.
/// This is typically the case for all non-`'_` regions.
@ -470,7 +474,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
// path to the crate followed by the path to the item within the crate.
if let Some(cnum) = def_id.as_crate_root() {
if cnum == LOCAL_CRATE {
self.path_crate(cnum)?;
self.print_crate_name(cnum)?;
return Ok(true);
}
@ -494,7 +498,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
// or avoid ending up with `ExternCrateSource::Extern`,
// for the injected `std`/`core`.
if span.is_dummy() {
self.path_crate(cnum)?;
self.print_crate_name(cnum)?;
return Ok(true);
}
@ -508,13 +512,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
return Ok(true);
}
(ExternCrateSource::Path, LOCAL_CRATE) => {
self.path_crate(cnum)?;
self.print_crate_name(cnum)?;
return Ok(true);
}
_ => {}
},
None => {
self.path_crate(cnum)?;
self.print_crate_name(cnum)?;
return Ok(true);
}
}
@ -624,7 +628,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
return Ok(false);
}
callers.push(visible_parent);
// HACK(eddyb) this bypasses `path_append`'s prefix printing to avoid
// HACK(eddyb) this bypasses `print_path_with_simple`'s prefix printing to avoid
// knowing ahead of time whether the entire path will succeed or not.
// To support printers that do not implement `PrettyPrinter`, a `Vec` or
// linked list on the stack would need to be built, before any printing.
@ -633,11 +637,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
true => {}
}
callers.pop();
self.path_append(|_| Ok(()), &DisambiguatedDefPathData { data, disambiguator: 0 })?;
self.print_path_with_simple(
|_| Ok(()),
&DisambiguatedDefPathData { data, disambiguator: 0 },
)?;
Ok(true)
}
fn pretty_path_qualified(
fn pretty_print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
@ -672,7 +679,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
})
}
fn pretty_path_append_impl(
fn pretty_print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
@ -739,7 +746,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
}
sig.print(self)?;
write!(self, " {{")?;
self.print_value_path(def_id, args)?;
self.pretty_print_value_path(def_id, args)?;
write!(self, "}}")?;
}
}
@ -1308,10 +1315,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
alias_ty: ty::AliasTerm<'tcx>,
) -> Result<(), PrintError> {
let def_key = self.tcx().def_key(alias_ty.def_id);
self.path_generic_args(
self.print_path_with_generic_args(
|p| {
p.path_append(
|p| p.path_qualified(alias_ty.self_ty(), None),
p.print_path_with_simple(
|p| p.print_path_with_qualified(alias_ty.self_ty(), None),
&def_key.disambiguated_data,
)
},
@ -1386,7 +1393,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
if let ty::Tuple(tys) = principal.args.type_at(0).kind() {
let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) {
p.pretty_fn_sig(
p.pretty_print_fn_sig(
tys,
false,
proj.skip_binder().term.as_type().expect("Return type was a const"),
@ -1396,7 +1403,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
}
}
// HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`,
// HACK(eddyb) this duplicates `FmtPrinter`'s `print_path_with_generic_args`,
// in order to place the projections inside the `<...>`.
if !resugared {
let principal_with_self =
@ -1488,7 +1495,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
Ok(())
}
fn pretty_fn_sig(
fn pretty_print_fn_sig(
&mut self,
inputs: &[Ty<'tcx>],
c_variadic: bool,
@ -1525,7 +1532,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
match self.tcx().def_kind(def) {
DefKind::Const | DefKind::AssocConst => {
self.print_value_path(def, args)?;
self.pretty_print_value_path(def, args)?;
}
DefKind::AnonConst => {
if def.is_local()
@ -1534,13 +1541,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
{
write!(self, "{snip}")?;
} else {
// Do not call `print_value_path` as if a parent of this anon const is
// an impl it will attempt to print out the impl trait ref i.e. `<T as
// Trait>::{constant#0}`. This would cause printing to enter an
// infinite recursion if the anon const is in the self type i.e.
// `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we would
// try to print
// `<[T; /* print constant#0 again */] as // Default>::{constant#0}`.
// Do not call `pretty_print_value_path` as if a parent of this anon
// const is an impl it will attempt to print out the impl trait ref
// i.e. `<T as Trait>::{constant#0}`. This would cause printing to
// enter an infinite recursion if the anon const is in the self type
// i.e. `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we
// would try to print `<[T; /* print constant#0 again */] as //
// Default>::{constant#0}`.
write!(
self,
"{}::{}",
@ -1742,7 +1749,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
self.tcx().try_get_global_alloc(prov.alloc_id())
{
self.typed_value(
|this| this.print_value_path(instance.def_id(), instance.args),
|this| this.pretty_print_value_path(instance.def_id(), instance.args),
|this| this.print_type(ty),
" as ",
)?;
@ -1936,7 +1943,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
let variant_idx =
contents.variant.expect("destructed const of adt without variant idx");
let variant_def = &def.variant(variant_idx);
self.print_value_path(variant_def.def_id, args)?;
self.pretty_print_value_path(variant_def.def_id, args)?;
match variant_def.ctor_kind() {
Some(CtorKind::Const) => {}
Some(CtorKind::Fn) => {
@ -1972,7 +1979,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
}
(_, ty::FnDef(def_id, args)) => {
// Never allowed today, but we still encounter them in invalid const args.
self.print_value_path(def_id, args)?;
self.pretty_print_value_path(def_id, args)?;
return Ok(());
}
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
@ -1993,7 +2000,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
Ok(())
}
fn pretty_closure_as_impl(
fn pretty_print_closure_as_impl(
&mut self,
closure: ty::ClosureArgs<TyCtxt<'tcx>>,
) -> Result<(), PrintError> {
@ -2131,8 +2138,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
}
}
// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
// (but also some things just print a `DefId` generally so maybe we need this?)
fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::OpaqueTy => {
@ -2157,6 +2162,7 @@ impl<'t> TyCtxt<'t> {
self.def_path_str_with_args(def_id, &[])
}
/// For this one we determine the appropriate namespace for the `def_id`.
pub fn def_path_str_with_args(
self,
def_id: impl IntoQueryParam<DefId>,
@ -2169,16 +2175,17 @@ impl<'t> TyCtxt<'t> {
FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap()
}
/// For this one we always use value namespace.
pub fn value_path_str_with_args(
self,
def_id: impl IntoQueryParam<DefId>,
args: &'t [GenericArg<'t>],
) -> String {
let def_id = def_id.into_query_param();
let ns = guess_def_namespace(self, def_id);
let ns = Namespace::ValueNS;
debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns);
FmtPrinter::print_string(self, ns, |p| p.print_value_path(def_id, args)).unwrap()
FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap()
}
}
@ -2230,7 +2237,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
self.print_def_path(parent_def_id, &[])?;
// HACK(eddyb) copy of `path_append` to avoid
// HACK(eddyb) copy of `print_path_with_simple` to avoid
// constructing a `DisambiguatedDefPathData`.
if !self.empty_path {
write!(self, "::")?;
@ -2295,10 +2302,6 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
}
}
fn should_truncate(&mut self) -> bool {
!self.type_length_limit.value_within_limit(self.printed_type_count)
}
fn print_dyn_existential(
&mut self,
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@ -2310,7 +2313,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
self.pretty_print_const(ct, false)
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.empty_path = true;
if cnum == LOCAL_CRATE {
if self.tcx.sess.at_least_rust_2018() {
@ -2327,23 +2330,23 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.pretty_path_qualified(self_ty, trait_ref)?;
self.pretty_print_path_with_qualified(self_ty, trait_ref)?;
self.empty_path = false;
Ok(())
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.pretty_path_append_impl(
self.pretty_print_path_with_impl(
|p| {
print_prefix(p)?;
if !p.empty_path {
@ -2359,7 +2362,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
Ok(())
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -2390,7 +2393,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
Ok(())
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
args: &[GenericArg<'tcx>],
@ -2421,7 +2424,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
}
fn print_value_path(
fn pretty_print_value_path(
&mut self,
def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
@ -2433,7 +2436,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
Ok(())
}
fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
fn pretty_print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
where
T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
{
@ -2487,6 +2490,10 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
Ok(())
}
fn should_truncate(&mut self) -> bool {
!self.type_length_limit.value_within_limit(self.printed_type_count)
}
fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
let highlight = self.region_highlight_mode;
if highlight.region_highlighted(region).is_some() {
@ -2892,7 +2899,7 @@ where
T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>,
{
fn print(&self, p: &mut P) -> Result<(), PrintError> {
p.print_in_binder(self)
p.pretty_print_in_binder(self)
}
}
@ -3090,7 +3097,7 @@ define_print! {
}
write!(p, "fn")?;
p.pretty_fn_sig(self.inputs(), self.c_variadic, self.output())?;
p.pretty_print_fn_sig(self.inputs(), self.c_variadic, self.output())?;
}
ty::TraitRef<'tcx> {
@ -3225,7 +3232,7 @@ define_print! {
// The args don't contain the self ty (as it has been erased) but the corresp.
// generics do as the trait always has a self ty param. We need to offset.
let args = &self.args[p.tcx().generics_of(self.def_id).parent_count - 1..];
p.path_generic_args(|p| write!(p, "{name}"), args)?;
p.print_path_with_generic_args(|p| write!(p, "{name}"), args)?;
write!(p, " = ")?;
self.term.print(p)?;
}
@ -3314,7 +3321,7 @@ define_print_and_forward_display! {
}
PrintClosureAsImpl<'tcx> {
p.pretty_closure_as_impl(self.closure)?;
p.pretty_print_closure_as_impl(self.closure)?;
}
ty::ParamTy {

View file

@ -242,6 +242,9 @@ resolve_lowercase_self =
attempt to use a non-constant value in a constant
.suggestion = try using `Self`
resolve_macro_cannot_use_as_fn_like =
`{$ident}` exists, but has no rules for function-like invocation
resolve_macro_cannot_use_as_attr =
`{$ident}` exists, but has no `attr` rules

View file

@ -1232,7 +1232,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
ItemKind::Fn(box ast::Fn { ident: fn_ident, .. }) => {
match self.proc_macro_stub(item, *fn_ident) {
Some((macro_kind, ident, span)) => {
let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id());
let macro_kinds = macro_kind.into();
let res = Res::Def(DefKind::Macro(macro_kinds), def_id.to_def_id());
let macro_data = MacroData::new(self.r.dummy_ext(macro_kind));
self.r.new_local_macro(def_id, macro_data);
self.r.proc_macro_stubs.insert(def_id);

View file

@ -149,9 +149,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
let macro_data =
self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition);
let macro_kind = macro_data.ext.macro_kind();
let macro_kinds = macro_data.ext.macro_kinds();
opt_macro_data = Some(macro_data);
DefKind::Macro(macro_kind)
DefKind::Macro(macro_kinds)
}
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(use_tree) => {

View file

@ -13,7 +13,7 @@ use rustc_errors::{
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem};
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr};
use rustc_middle::bug;
@ -1491,11 +1491,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let Some(binding) = resolution.borrow().best_binding() else {
continue;
};
let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
binding.res()
else {
let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else {
continue;
};
if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) {
continue;
}
// By doing this all *imported* macros get added to the `macro_map` even if they
// are *unused*, which makes the later suggestions find them and work.
let _ = this.get_macro_by_def_id(def_id);
@ -1504,7 +1505,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
},
);
let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
let is_expected =
&|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
let suggestion = self.early_lookup_typo_candidate(
ScopeSet::Macro(macro_kind),
parent_scope,
@ -1553,11 +1555,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if let Some((def_id, unused_ident)) = unused_macro {
let scope = self.local_macro_def_scopes[&def_id];
let parent_nearest = parent_scope.module.nearest_parent_mod();
if Some(parent_nearest) == scope.opt_def_id() {
let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds();
if !unused_macro_kinds.contains(macro_kind.into()) {
match macro_kind {
MacroKind::Bang => {
err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident });
}
MacroKind::Attr => {
err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
@ -1566,14 +1568,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
}
}
return;
}
}
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
err.subdiagnostic(AddedMacroUse);
return;
if Some(parent_nearest) == scope.opt_def_id() {
err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
return;
}
}
if ident.name == kw::Default
@ -1601,13 +1602,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
};
let desc = match binding.res() {
Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
Res::Def(DefKind::Macro(MacroKinds::BANG), _) => {
"a function-like macro".to_string()
}
Res::Def(DefKind::Macro(MacroKinds::ATTR), _) | Res::NonMacroAttr(..) => {
format!("an attribute: `#[{ident}]`")
}
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
Res::Def(DefKind::Macro(MacroKinds::DERIVE), _) => {
format!("a derive macro: `#[derive({ident})]`")
}
Res::Def(DefKind::Macro(kinds), _) => {
format!("{} {}", kinds.article(), kinds.descr())
}
Res::ToolMod => {
// Don't confuse the user with tool modules.
continue;
@ -1644,6 +1650,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
err.subdiagnostic(note);
return;
}
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
err.subdiagnostic(AddedMacroUse);
return;
}
}
/// Given an attribute macro that failed to be resolved, look for `derive` macros that could
@ -2748,9 +2759,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let binding_key = BindingKey::new(ident, MacroNS);
let binding = self.resolution(crate_module, binding_key)?.binding()?;
let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
let Res::Def(DefKind::Macro(kinds), _) = binding.res() else {
return None;
};
if !kinds.contains(MacroKinds::BANG) {
return None;
}
let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
let import_snippet = match import.kind {
ImportKind::Single { source, target, .. } if source != target => {

View file

@ -672,6 +672,12 @@ pub(crate) struct MacroSuggMovePosition {
#[derive(Subdiagnostic)]
pub(crate) enum MacroRulesNot {
#[label(resolve_macro_cannot_use_as_fn_like)]
Func {
#[primary_span]
span: Span,
ident: Ident,
},
#[label(resolve_macro_cannot_use_as_attr)]
Attr {
#[primary_span]

View file

@ -2,7 +2,7 @@ use Determinacy::*;
use Namespace::*;
use rustc_ast::{self as ast, NodeId};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS};
use rustc_middle::bug;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
@ -259,7 +259,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
{
let ext = &self.get_macro_by_def_id(def_id).ext;
if ext.builtin_name.is_none()
&& ext.macro_kind() == MacroKind::Derive
&& ext.macro_kinds() == MacroKinds::DERIVE
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
{
return Some((parent, derive_fallback_lint_id));
@ -632,17 +632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
match result {
Ok((binding, flags)) => {
let binding_macro_kind = binding.macro_kind();
// If we're looking for an attribute, that might be supported by a
// `macro_rules!` macro.
// FIXME: Replace this with tracking multiple macro kinds for one Def.
if !(sub_namespace_match(binding_macro_kind, macro_kind)
|| (binding_macro_kind == Some(MacroKind::Bang)
&& macro_kind == Some(MacroKind::Attr)
&& this
.get_macro(binding.res())
.is_some_and(|macro_data| macro_data.attr_ext.is_some())))
{
if !sub_namespace_match(binding.macro_kinds(), macro_kind) {
return None;
}

View file

@ -19,14 +19,13 @@ use rustc_errors::{
};
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_hir::{MissingLifetimeKind, PrimTy};
use rustc_middle::ty;
use rustc_session::{Session, lint};
use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use thin_vec::ThinVec;
use tracing::debug;
@ -1850,12 +1849,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
match (res, source) {
(
Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
Res::Def(DefKind::Macro(kinds), def_id),
PathSource::Expr(Some(Expr {
kind: ExprKind::Index(..) | ExprKind::Call(..), ..
}))
| PathSource::Struct(_),
) => {
) if kinds.contains(MacroKinds::BANG) => {
// Don't suggest macro if it's unstable.
let suggestable = def_id.is_local()
|| self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
@ -1880,7 +1879,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
err.note("if you want the `try` keyword, you need Rust 2018 or later");
}
}
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
(Res::Def(DefKind::Macro(kinds), _), _) if kinds.contains(MacroKinds::BANG) => {
err.span_label(span, fallback_label.to_string());
}
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {

View file

@ -53,7 +53,8 @@ use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::attrs::StrippedCfgItem;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{
self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS,
self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes,
PerNS,
};
use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
use rustc_hir::definitions::DisambiguatorState;
@ -969,8 +970,8 @@ impl<'ra> NameBindingData<'ra> {
matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _))
}
fn macro_kind(&self) -> Option<MacroKind> {
self.res().macro_kind()
fn macro_kinds(&self) -> Option<MacroKinds> {
self.res().macro_kinds()
}
// Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
@ -1030,14 +1031,13 @@ struct DeriveData {
struct MacroData {
ext: Arc<SyntaxExtension>,
attr_ext: Option<Arc<SyntaxExtension>>,
nrules: usize,
macro_rules: bool,
}
impl MacroData {
fn new(ext: Arc<SyntaxExtension>) -> MacroData {
MacroData { ext, attr_ext: None, nrules: 0, macro_rules: false }
MacroData { ext, nrules: 0, macro_rules: false }
}
}

View file

@ -1,7 +1,6 @@
//! A bunch of methods and structures more or less related to resolving macros and
//! interface provided by `Resolver` to macro expander.
use std::any::Any;
use std::cell::Cell;
use std::mem;
use std::sync::Arc;
@ -13,13 +12,13 @@ use rustc_expand::base::{
Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
SyntaxExtensionKind,
};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{
AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
};
use rustc_expand::{MacroRulesMacroExpander, compile_declarative_macro};
use rustc_hir::StabilityLevel;
use rustc_hir::attrs::{CfgEntry, StrippedCfgItem};
use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_middle::middle::stability;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
@ -86,22 +85,19 @@ pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell<MacroRulesScope<'ra>>;
/// one for attribute-like macros (attributes, derives).
/// We ignore resolutions from one sub-namespace when searching names in scope for another.
pub(crate) fn sub_namespace_match(
candidate: Option<MacroKind>,
candidate: Option<MacroKinds>,
requirement: Option<MacroKind>,
) -> bool {
#[derive(PartialEq)]
enum SubNS {
Bang,
AttrLike,
}
let sub_ns = |kind| match kind {
MacroKind::Bang => SubNS::Bang,
MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike,
};
let candidate = candidate.map(sub_ns);
let requirement = requirement.map(sub_ns);
// "No specific sub-namespace" means "matches anything" for both requirements and candidates.
candidate.is_none() || requirement.is_none() || candidate == requirement
let (Some(candidate), Some(requirement)) = (candidate, requirement) else {
return true;
};
match requirement {
MacroKind::Bang => candidate.contains(MacroKinds::BANG),
MacroKind::Attr | MacroKind::Derive => {
candidate.intersects(MacroKinds::ATTR | MacroKinds::DERIVE)
}
}
}
// We don't want to format a path using pretty-printing,
@ -323,6 +319,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
parent_scope.expansion,
span,
fast_print_path(path),
kind,
def_id,
def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()),
),
@ -356,11 +353,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
}
let def_id = self.local_def_id(node_id);
let m = &self.local_macro_map[&def_id];
let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else {
continue;
};
let ext: &dyn Any = ext.as_ref();
let Some(m) = ext.downcast_ref::<MacroRulesMacroExpander>() else {
let SyntaxExtensionKind::MacroRules(ref m) = m.ext.kind else {
continue;
};
for arm_i in unused_arms.iter() {
@ -633,7 +626,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
self.check_stability_and_deprecation(&ext, path, node_id);
let unexpected_res = if ext.macro_kind() != kind {
let unexpected_res = if !ext.macro_kinds().contains(kind.into()) {
Some((kind.article(), kind.descr_expected()))
} else if matches!(res, Res::Def(..)) {
match supports_macro_expansion {
@ -665,7 +658,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// Suggest moving the macro out of the derive() if the macro isn't Derive
if !path.span.from_expansion()
&& kind == MacroKind::Derive
&& ext.macro_kind() != MacroKind::Derive
&& !ext.macro_kinds().contains(MacroKinds::DERIVE)
&& ext.macro_kinds().contains(MacroKinds::ATTR)
{
err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span });
err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str });
@ -842,10 +836,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
_ => None,
},
None => self.get_macro(res).map(|macro_data| match kind {
Some(MacroKind::Attr) if let Some(ref ext) = macro_data.attr_ext => Arc::clone(ext),
_ => Arc::clone(&macro_data.ext),
}),
None => self.get_macro(res).map(|macro_data| Arc::clone(&macro_data.ext)),
};
Ok((ext, res))
}
@ -1114,7 +1105,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& let Some(binding) = binding
// This is a `macro_rules` itself, not some import.
&& let NameBindingKind::Res(res) = binding.kind
&& let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res
&& let Res::Def(DefKind::Macro(kinds), def_id) = res
&& kinds.contains(MacroKinds::BANG)
// And the `macro_rules` is defined inside the attribute's module,
// so it cannot be in scope unless imported.
&& self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id())
@ -1161,8 +1153,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// Reserve some names that are not quite covered by the general check
// performed on `Resolver::builtin_attrs`.
if ident.name == sym::cfg || ident.name == sym::cfg_attr {
let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
let macro_kinds = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kinds());
if macro_kinds.is_some() && sub_namespace_match(macro_kinds, Some(MacroKind::Attr)) {
self.dcx()
.emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident });
}
@ -1181,7 +1173,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
node_id: NodeId,
edition: Edition,
) -> MacroData {
let (mut ext, mut attr_ext, mut nrules) = compile_declarative_macro(
let (mut ext, mut nrules) = compile_declarative_macro(
self.tcx.sess,
self.tcx.features(),
macro_def,
@ -1198,14 +1190,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
ext.kind = builtin_ext_kind.clone();
attr_ext = None;
nrules = 0;
} else {
self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
}
}
MacroData { ext: Arc::new(ext), attr_ext, nrules, macro_rules: macro_def.macro_rules }
MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules }
}
fn path_accessible(

View file

@ -58,7 +58,7 @@ pub(super) fn mangle<'tcx>(
let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
let mut p = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false };
let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false };
p.print_def_path(
def_id,
if let ty::InstanceKind::DropGlue(_, _)
@ -213,13 +213,13 @@ impl SymbolPath {
}
}
struct SymbolPrinter<'tcx> {
struct LegacySymbolMangler<'tcx> {
tcx: TyCtxt<'tcx>,
path: SymbolPath,
// When `true`, `finalize_pending_component` isn't used.
// This is needed when recursing into `path_qualified`,
// or `path_generic_args`, as any nested paths are
// This is needed when recursing into `print_path_with_qualified`,
// or `print_path_with_generic_args`, as any nested paths are
// logically within one component.
keep_within_component: bool,
}
@ -228,7 +228,7 @@ struct SymbolPrinter<'tcx> {
// `PrettyPrinter` aka pretty printing of e.g. types in paths,
// symbol names should have their own printing machinery.
impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@ -305,16 +305,17 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
Ok(())
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.write_str(self.tcx.crate_name(cnum).as_str())?;
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
// Similar to `pretty_path_qualified`, but for the other
// Similar to `pretty_print_path_with_qualified`, but for the other
// types that are printed as paths (see `print_type` above).
match self_ty.kind() {
ty::FnDef(..)
@ -327,17 +328,17 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
self.print_type(self_ty)
}
_ => self.pretty_path_qualified(self_ty, trait_ref),
_ => self.pretty_print_path_with_qualified(self_ty, trait_ref),
}
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.pretty_path_append_impl(
self.pretty_print_path_with_impl(
|cx| {
print_prefix(cx)?;
@ -354,7 +355,8 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
trait_ref,
)
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -377,7 +379,8 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
Ok(())
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
args: &[GenericArg<'tcx>],
@ -455,7 +458,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
}
}
impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
false
}
@ -491,7 +494,7 @@ impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
}
}
impl fmt::Write for SymbolPrinter<'_> {
impl fmt::Write for LegacySymbolMangler<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!

View file

@ -33,7 +33,7 @@ pub(super) fn mangle<'tcx>(
let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args);
let prefix = "_R";
let mut p: SymbolMangler<'_> = SymbolMangler {
let mut p: V0SymbolMangler<'_> = V0SymbolMangler {
tcx,
start_offset: prefix.len(),
is_exportable,
@ -88,7 +88,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin
}
let prefix = "_R";
let mut p: SymbolMangler<'_> = SymbolMangler {
let mut p: V0SymbolMangler<'_> = V0SymbolMangler {
tcx,
start_offset: prefix.len(),
is_exportable: false,
@ -131,7 +131,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
trait_ref: ty::ExistentialTraitRef<'tcx>,
) -> String {
// FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`.
let mut p = SymbolMangler {
let mut p = V0SymbolMangler {
tcx,
start_offset: 0,
is_exportable: false,
@ -159,7 +159,7 @@ struct BinderLevel {
lifetime_depths: Range<u32>,
}
struct SymbolMangler<'tcx> {
struct V0SymbolMangler<'tcx> {
tcx: TyCtxt<'tcx>,
binders: Vec<BinderLevel>,
out: String,
@ -173,7 +173,7 @@ struct SymbolMangler<'tcx> {
consts: FxHashMap<ty::Const<'tcx>, usize>,
}
impl<'tcx> SymbolMangler<'tcx> {
impl<'tcx> V0SymbolMangler<'tcx> {
fn push(&mut self, s: &str) {
self.out.push_str(s);
}
@ -272,7 +272,7 @@ impl<'tcx> SymbolMangler<'tcx> {
}
}
impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@ -365,7 +365,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
// Encode impl generic params if the generic parameters contain non-region parameters
// and this isn't an inherent impl.
if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) {
self.path_generic_args(
self.print_path_with_generic_args(
|this| {
this.path_append_ns(
|p| p.print_def_path(parent_def_id, &[]),
@ -786,7 +786,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
None => {
self.push("S");
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
// HACK(eddyb) this mimics `path_append`,
// HACK(eddyb) this mimics `print_path_with_simple`,
// instead of simply using `field_def.ident`,
// just to be able to handle disambiguators.
let disambiguated_field =
@ -819,7 +819,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
Ok(())
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.push("C");
if !self.is_exportable {
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
@ -830,7 +830,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
@ -843,7 +843,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
self.print_def_path(trait_ref.def_id, trait_ref.args)
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
_: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_: Ty<'tcx>,
@ -853,7 +853,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
unreachable!()
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -873,7 +873,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
DefPathData::SyntheticCoroutineBody => 's',
DefPathData::NestedStatic => 'n',
// These should never show up as `path_append` arguments.
// These should never show up as `print_path_with_simple` arguments.
DefPathData::CrateRoot
| DefPathData::Use
| DefPathData::GlobalAsm
@ -896,7 +896,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
)
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
args: &[GenericArg<'tcx>],

View file

@ -2147,6 +2147,7 @@ supported_targets! {
("aarch64-unknown-none", aarch64_unknown_none),
("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
("aarch64_be-unknown-none-softfloat", aarch64_be_unknown_none_softfloat),
("aarch64-unknown-nuttx", aarch64_unknown_nuttx),
("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),

View file

@ -0,0 +1,43 @@
// Generic big-endian AArch64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.
use rustc_abi::Endian;
use crate::spec::{
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
TargetMetadata, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: "softfloat".into(),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v8a,+strict-align,-neon,-fp-armv8".into(),
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
endian: Endian::Big,
..Default::default()
};
Target {
llvm_target: "aarch64_be-unknown-none".into(),
metadata: TargetMetadata {
description: Some("Bare ARM64 (big-endian), softfloat".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 64,
data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: "aarch64".into(),
options: opts,
}
}

View file

@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
host_tools: None,
std: None,
},
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8".into(),
llvm_target: "avr-unknown-unknown".into(),
pointer_width: 16,
options: TargetOptions {

View file

@ -248,6 +248,10 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("mte", Stable, &[]),
// FEAT_AdvSimd & FEAT_FP
("neon", Stable, &[]),
// Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be
// available, so the intrinsic can do runtime LSE feature detection rather than unconditionally
// using slower non-LSE operations. Unstable since it doesn't need to user-togglable.
("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]),
// FEAT_PAUTH (address authentication)
("paca", Stable, &[]),
// FEAT_PAUTH (generic authentication)

View file

@ -224,12 +224,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
use ty::GenericArg;
use ty::print::Printer;
struct AbsolutePathPrinter<'tcx> {
struct ConflictingPathPrinter<'tcx> {
tcx: TyCtxt<'tcx>,
segments: Vec<Symbol>,
}
impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
impl<'tcx> Printer<'tcx> for ConflictingPathPrinter<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
@ -253,12 +253,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
self.segments = vec![self.tcx.crate_name(cnum)];
Ok(())
}
fn path_qualified(
fn print_path_with_qualified(
&mut self,
_self_ty: Ty<'tcx>,
_trait_ref: Option<ty::TraitRef<'tcx>>,
@ -266,7 +266,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
Err(fmt::Error)
}
fn path_append_impl(
fn print_path_with_impl(
&mut self,
_print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_self_ty: Ty<'tcx>,
@ -275,7 +275,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
Err(fmt::Error)
}
fn path_append(
fn print_path_with_simple(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
@ -285,7 +285,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
Ok(())
}
fn path_generic_args(
fn print_path_with_generic_args(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_args: &[GenericArg<'tcx>],
@ -300,28 +300,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
if did1.krate != did2.krate {
let abs_path = |def_id| {
let mut p = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] };
let mut p = ConflictingPathPrinter { tcx: self.tcx, segments: vec![] };
p.print_def_path(def_id, &[]).map(|_| p.segments)
};
// We compare strings because DefPath can be different
// for imported and non-imported crates
// We compare strings because DefPath can be different for imported and
// non-imported crates.
let expected_str = self.tcx.def_path_str(did1);
let found_str = self.tcx.def_path_str(did2);
let Ok(expected_abs) = abs_path(did1) else { return false };
let Ok(found_abs) = abs_path(did2) else { return false };
let same_path = || -> Result<_, PrintError> {
Ok(expected_str == found_str || expected_abs == found_abs)
};
// We want to use as unique a type path as possible. If both types are "locally
// known" by the same name, we use the "absolute path" which uses the original
// crate name instead.
let (expected, found) = if expected_str == found_str {
(join_path_syms(&expected_abs), join_path_syms(&found_abs))
} else {
(expected_str.clone(), found_str.clone())
};
if same_path().unwrap_or(false) {
let same_path = expected_str == found_str || expected_abs == found_abs;
if same_path {
// We want to use as unique a type path as possible. If both types are "locally
// known" by the same name, we use the "absolute path" which uses the original
// crate name instead.
let (expected, found) = if expected_str == found_str {
(join_path_syms(&expected_abs), join_path_syms(&found_abs))
} else {
(expected_str.clone(), found_str.clone())
};
// We've displayed "expected `a::b`, found `a::b`". We add context to
// differentiate the different cases where that might happen.
let expected_crate_name = self.tcx.crate_name(did1.krate);

View file

@ -946,7 +946,7 @@ fn foo(&self) -> Self::T { String::new() }
pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |p| {
p.path_generic_args(|_| Ok(()), args)
p.print_path_with_generic_args(|_| Ok(()), args)
})
.expect("could not write to `String`.")
}

View file

@ -12,10 +12,11 @@
//! The global cache has to be completely unobservable, while the per-cycle cache may impact
//! behavior as long as the resulting behavior is still correct.
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, btree_map};
use std::fmt::Debug;
use std::hash::Hash;
use std::iter;
use std::marker::PhantomData;
use derive_where::derive_where;
@ -230,13 +231,19 @@ impl AvailableDepth {
}
}
#[derive(Clone, Copy, Debug)]
struct CycleHead {
paths_to_head: PathsToNested,
usage_kind: UsageKind,
}
/// All cycle heads a given goal depends on, ordered by their stack depth.
///
/// We also track all paths from this goal to that head. This is necessary
/// when rebasing provisional cache results.
#[derive(Clone, Debug, Default)]
struct CycleHeads {
heads: BTreeMap<StackDepth, PathsToNested>,
heads: BTreeMap<StackDepth, CycleHead>,
}
impl CycleHeads {
@ -256,32 +263,32 @@ impl CycleHeads {
self.heads.first_key_value().map(|(k, _)| *k)
}
fn remove_highest_cycle_head(&mut self) -> PathsToNested {
fn remove_highest_cycle_head(&mut self) -> CycleHead {
let last = self.heads.pop_last();
last.unwrap().1
}
fn insert(&mut self, head: StackDepth, path_from_entry: impl Into<PathsToNested> + Copy) {
*self.heads.entry(head).or_insert(path_from_entry.into()) |= path_from_entry.into();
}
fn iter(&self) -> impl Iterator<Item = (StackDepth, PathsToNested)> + '_ {
self.heads.iter().map(|(k, v)| (*k, *v))
}
/// Update the cycle heads of a goal at depth `this` given the cycle heads
/// of a nested goal. This merges the heads after filtering the parent goal
/// itself.
fn extend_from_child(&mut self, this: StackDepth, step_kind: PathKind, child: &CycleHeads) {
for (&head, &path_from_entry) in child.heads.iter() {
match head.cmp(&this) {
Ordering::Less => {}
Ordering::Equal => continue,
Ordering::Greater => unreachable!(),
fn insert(
&mut self,
head_index: StackDepth,
path_from_entry: impl Into<PathsToNested> + Copy,
usage_kind: UsageKind,
) {
match self.heads.entry(head_index) {
btree_map::Entry::Vacant(entry) => {
entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usage_kind });
}
btree_map::Entry::Occupied(entry) => {
let head = entry.into_mut();
head.paths_to_head |= path_from_entry.into();
head.usage_kind = head.usage_kind.merge(usage_kind);
}
self.insert(head, path_from_entry.extend_with(step_kind));
}
}
fn iter(&self) -> impl Iterator<Item = (StackDepth, CycleHead)> + '_ {
self.heads.iter().map(|(k, v)| (*k, *v))
}
}
bitflags::bitflags! {
@ -487,9 +494,6 @@ impl<X: Cx> EvaluationResult<X> {
pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
root_depth: AvailableDepth,
/// The stack of goals currently being computed.
///
/// An element is *deeper* in the stack if its index is *lower*.
stack: Stack<X>,
/// The provisional cache contains entries for already computed goals which
/// still depend on goals higher-up in the stack. We don't move them to the
@ -511,6 +515,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
/// cache entry.
enum UpdateParentGoalCtxt<'a, X: Cx> {
Ordinary(&'a NestedGoals<X>),
CycleOnStack(X::Input),
ProvisionalCacheHit,
}
@ -532,21 +537,42 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
stack: &mut Stack<X>,
step_kind_from_parent: PathKind,
required_depth_for_nested: usize,
heads: &CycleHeads,
heads: impl Iterator<Item = (StackDepth, CycleHead)>,
encountered_overflow: bool,
context: UpdateParentGoalCtxt<'_, X>,
) {
if let Some(parent_index) = stack.last_index() {
let parent = &mut stack[parent_index];
if let Some((parent_index, parent)) = stack.last_mut_with_index() {
parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1);
parent.encountered_overflow |= encountered_overflow;
parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads);
for (head_index, head) in heads {
match head_index.cmp(&parent_index) {
Ordering::Less => parent.heads.insert(
head_index,
head.paths_to_head.extend_with(step_kind_from_parent),
head.usage_kind,
),
Ordering::Equal => {
let usage_kind = parent
.has_been_used
.map_or(head.usage_kind, |prev| prev.merge(head.usage_kind));
parent.has_been_used = Some(usage_kind);
}
Ordering::Greater => unreachable!(),
}
}
let parent_depends_on_cycle = match context {
UpdateParentGoalCtxt::Ordinary(nested_goals) => {
parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals);
!nested_goals.is_empty()
}
UpdateParentGoalCtxt::CycleOnStack(head) => {
// We lookup provisional cache entries before detecting cycles.
// We therefore can't use a global cache entry if it contains a cycle
// whose head is in the provisional cache.
parent.nested_goals.insert(head, step_kind_from_parent.into());
true
}
UpdateParentGoalCtxt::ProvisionalCacheHit => true,
};
// Once we've got goals which encountered overflow or a cycle,
@ -674,7 +700,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
&mut self.stack,
step_kind_from_parent,
evaluation_result.required_depth,
&evaluation_result.heads,
evaluation_result.heads.iter(),
evaluation_result.encountered_overflow,
UpdateParentGoalCtxt::Ordinary(&evaluation_result.nested_goals),
);
@ -772,7 +798,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
stack_entry: &StackEntry<X>,
mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result,
) {
let popped_head = self.stack.next_index();
let popped_head_index = self.stack.next_index();
#[allow(rustc::potential_query_instability)]
self.provisional_cache.retain(|&input, entries| {
entries.retain_mut(|entry| {
@ -782,7 +808,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
path_from_head,
result,
} = entry;
let ep = if heads.highest_cycle_head() == popped_head {
let popped_head = if heads.highest_cycle_head() == popped_head_index {
heads.remove_highest_cycle_head()
} else {
return true;
@ -795,9 +821,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
//
// After rebasing the cycles `hph` will go through `e`. We need to make
// sure that forall possible paths `hep`, `heph` is equal to `hph.`
for (h, ph) in stack_entry.heads.iter() {
let hp =
Self::cycle_path_kind(&self.stack, stack_entry.step_kind_from_parent, h);
let ep = popped_head.paths_to_head;
for (head_index, head) in stack_entry.heads.iter() {
let ph = head.paths_to_head;
let hp = Self::cycle_path_kind(
&self.stack,
stack_entry.step_kind_from_parent,
head_index,
);
// We first validate that all cycles while computing `p` would stay
// the same if we were to recompute it as a nested goal of `e`.
@ -817,7 +848,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// the heads of `e` to make sure that rebasing `e` again also considers
// them.
let eph = ep.extend_with_paths(ph);
heads.insert(h, eph);
heads.insert(head_index, eph, head.usage_kind);
}
let Some(head) = heads.opt_highest_cycle_head() else {
@ -877,11 +908,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
&mut self.stack,
step_kind_from_parent,
0,
heads,
heads.iter(),
encountered_overflow,
UpdateParentGoalCtxt::ProvisionalCacheHit,
);
debug_assert!(self.stack[head].has_been_used.is_some());
debug!(?head, ?path_from_head, "provisional cache hit");
return Some(result);
}
@ -993,12 +1023,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// We don't move cycle participants to the global cache, so the
// cycle heads are always empty.
let heads = Default::default();
let heads = iter::empty();
Self::update_parent_goal(
&mut self.stack,
step_kind_from_parent,
required_depth,
&heads,
heads,
encountered_overflow,
UpdateParentGoalCtxt::Ordinary(nested_goals),
);
@ -1014,34 +1044,31 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
input: X::Input,
step_kind_from_parent: PathKind,
) -> Option<X::Result> {
let head = self.stack.find(input)?;
let head_index = self.stack.find(input)?;
// We have a nested goal which directly relies on a goal deeper in the stack.
//
// We start by tagging all cycle participants, as that's necessary for caching.
//
// Finally we can return either the provisional response or the initial response
// in case we're in the first fixpoint iteration for this goal.
let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head);
debug!(?path_kind, "encountered cycle with depth {head:?}");
let usage_kind = UsageKind::Single(path_kind);
self.stack[head].has_been_used =
Some(self.stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind)));
// Subtle: when encountering a cyclic goal, we still first checked for overflow,
// so we have to update the reached depth.
let last_index = self.stack.last_index().unwrap();
let last = &mut self.stack[last_index];
last.required_depth = last.required_depth.max(1);
last.nested_goals.insert(input, step_kind_from_parent.into());
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
if last_index != head {
last.heads.insert(head, step_kind_from_parent);
}
let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index);
debug!(?path_kind, "encountered cycle with depth {head_index:?}");
let head = CycleHead {
paths_to_head: step_kind_from_parent.into(),
usage_kind: UsageKind::Single(path_kind),
};
Self::update_parent_goal(
&mut self.stack,
step_kind_from_parent,
0,
iter::once((head_index, head)),
false,
UpdateParentGoalCtxt::CycleOnStack(input),
);
// Return the provisional result or, if we're in the first iteration,
// start with no constraints.
if let Some(result) = self.stack[head].provisional_result {
if let Some(result) = self.stack[head_index].provisional_result {
Some(result)
} else {
Some(D::initial_provisional_result(cx, path_kind, input))

View file

@ -1,4 +1,4 @@
use std::ops::{Index, IndexMut};
use std::ops::Index;
use derive_where::derive_where;
use rustc_index::IndexVec;
@ -48,6 +48,12 @@ pub(super) struct StackEntry<X: Cx> {
pub nested_goals: NestedGoals<X>,
}
/// The stack of goals currently being computed.
///
/// An element is *deeper* in the stack if its index is *lower*.
///
/// Only the last entry of the stack is mutable. All other entries get
/// lazily updated in `update_parent_goal`.
#[derive_where(Default; X: Cx)]
pub(super) struct Stack<X: Cx> {
entries: IndexVec<StackDepth, StackEntry<X>>,
@ -62,10 +68,6 @@ impl<X: Cx> Stack<X> {
self.entries.len()
}
pub(super) fn last_index(&self) -> Option<StackDepth> {
self.entries.last_index()
}
pub(super) fn last(&self) -> Option<&StackEntry<X>> {
self.entries.raw.last()
}
@ -74,6 +76,10 @@ impl<X: Cx> Stack<X> {
self.entries.raw.last_mut()
}
pub(super) fn last_mut_with_index(&mut self) -> Option<(StackDepth, &mut StackEntry<X>)> {
self.entries.last_index().map(|idx| (idx, &mut self.entries[idx]))
}
pub(super) fn next_index(&self) -> StackDepth {
self.entries.next_index()
}
@ -108,9 +114,3 @@ impl<X: Cx> Index<StackDepth> for Stack<X> {
&self.entries[index]
}
}
impl<X: Cx> IndexMut<StackDepth> for Stack<X> {
fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output {
&mut self.entries[index]
}
}

View file

@ -18,7 +18,7 @@ use serde_derive::Deserialize;
#[cfg(feature = "tracing")]
use tracing::{instrument, span};
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
use crate::core::build_steps::{dist, llvm};
use crate::core::builder;
@ -1543,13 +1543,22 @@ impl Step for RustcLink {
}
}
/// Output of the `compile::GccCodegenBackend` step.
/// It includes the path to the libgccjit library on which this backend depends.
#[derive(Clone)]
pub struct GccCodegenBackendOutput {
stamp: BuildStamp,
gcc: GccOutput,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GccCodegenBackend {
compilers: RustcPrivateCompilers,
}
impl Step for GccCodegenBackend {
type Output = BuildStamp;
type Output = GccCodegenBackendOutput;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -1584,6 +1593,8 @@ impl Step for GccCodegenBackend {
&CodegenBackendKind::Gcc,
);
let gcc = builder.ensure(Gcc { target });
if builder.config.keep_stage.contains(&build_compiler.stage) {
trace!("`keep-stage` requested");
builder.info(
@ -1592,7 +1603,7 @@ impl Step for GccCodegenBackend {
);
// Codegen backends are linked separately from this step today, so we don't do
// anything here.
return stamp;
return GccCodegenBackendOutput { stamp, gcc };
}
let mut cargo = builder::Cargo::new(
@ -1606,13 +1617,16 @@ impl Step for GccCodegenBackend {
cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo, target);
let gcc = builder.ensure(Gcc { target });
add_cg_gcc_cargo_flags(&mut cargo, &gcc);
let _guard =
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
write_codegen_backend_stamp(stamp, files, builder.config.dry_run())
GccCodegenBackendOutput {
stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
gcc,
}
}
fn metadata(&self) -> Option<StepMetadata> {
@ -2191,53 +2205,6 @@ impl Step for Assemble {
);
build_compiler.stage = actual_stage;
let mut codegen_backend_stamps = vec![];
{
#[cfg(feature = "tracing")]
let _codegen_backend_span =
span!(tracing::Level::DEBUG, "building requested codegen backends").entered();
for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
// FIXME: this is a horrible hack used to make `x check` work when other codegen
// backends are enabled.
// `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
// Then it checks codegen backends, which correctly use these rmetas.
// Then it needs to check std, but for that it needs to build stage 1 rustc.
// This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
// because we then have both check and build rmetas in the same sysroot.
// That would be fine on its own. However, when another codegen backend is enabled,
// then building stage 1 rustc implies also building stage 1 codegen backend (even if
// it isn't used for anything). And since that tries to use the poisoned
// rmetas, it fails to build.
// We don't actually need to build rustc-private codegen backends for checking std,
// so instead we skip that.
// Note: this would be also an issue for other rustc-private tools, but that is "solved"
// by check::Std being last in the list of checked things (see
// `Builder::get_step_descriptions`).
if builder.kind == Kind::Check && builder.top_stage == 1 {
continue;
}
let prepare_compilers = || {
RustcPrivateCompilers::from_build_and_target_compiler(
build_compiler,
target_compiler,
)
};
let stamp = match backend {
CodegenBackendKind::Cranelift => {
builder.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() })
}
CodegenBackendKind::Gcc => {
builder.ensure(GccCodegenBackend { compilers: prepare_compilers() })
}
CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
};
codegen_backend_stamps.push(stamp);
}
}
let stage = target_compiler.stage;
let host = target_compiler.host;
let (host_info, dir_name) = if build_compiler.host == host {
@ -2296,9 +2263,56 @@ impl Step for Assemble {
}
}
debug!("copying codegen backends to sysroot");
for stamp in codegen_backend_stamps {
copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
{
#[cfg(feature = "tracing")]
let _codegen_backend_span =
span!(tracing::Level::DEBUG, "building requested codegen backends").entered();
for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
// FIXME: this is a horrible hack used to make `x check` work when other codegen
// backends are enabled.
// `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
// Then it checks codegen backends, which correctly use these rmetas.
// Then it needs to check std, but for that it needs to build stage 1 rustc.
// This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
// because we then have both check and build rmetas in the same sysroot.
// That would be fine on its own. However, when another codegen backend is enabled,
// then building stage 1 rustc implies also building stage 1 codegen backend (even if
// it isn't used for anything). And since that tries to use the poisoned
// rmetas, it fails to build.
// We don't actually need to build rustc-private codegen backends for checking std,
// so instead we skip that.
// Note: this would be also an issue for other rustc-private tools, but that is "solved"
// by check::Std being last in the list of checked things (see
// `Builder::get_step_descriptions`).
if builder.kind == Kind::Check && builder.top_stage == 1 {
continue;
}
let prepare_compilers = || {
RustcPrivateCompilers::from_build_and_target_compiler(
build_compiler,
target_compiler,
)
};
match backend {
CodegenBackendKind::Cranelift => {
let stamp = builder
.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() });
copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
}
CodegenBackendKind::Gcc => {
let output =
builder.ensure(GccCodegenBackend { compilers: prepare_compilers() });
copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
// Also copy libgccjit to the library sysroot, so that it is available for
// the codegen backend.
output.gcc.install_to(builder, &rustc_libdir);
}
CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
}
}
}
if builder.config.lld_enabled {

View file

@ -478,7 +478,19 @@ impl Step for Rustc {
if libdir_relative.to_str() != Some("bin") {
let libdir = builder.rustc_libdir(compiler);
for entry in builder.read_dir(&libdir) {
if is_dylib(&entry.path()) {
// A safeguard that we will not ship libgccjit.so from the libdir, in case the
// GCC codegen backend is enabled by default.
// Long-term we should probably split the config options for:
// - Include cg_gcc in the rustc sysroot by default
// - Run dist of a specific codegen backend in `x dist` by default
if is_dylib(&entry.path())
&& !entry
.path()
.file_name()
.and_then(|n| n.to_str())
.map(|n| n.contains("libgccjit"))
.unwrap_or(false)
{
// Don't use custom libdir here because ^lib/ will be resolved again
// with installer
builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary);

View file

@ -12,6 +12,7 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use crate::FileType;
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
@ -28,6 +29,21 @@ pub struct GccOutput {
pub libgccjit: PathBuf,
}
impl GccOutput {
/// Install the required libgccjit library file(s) to the specified `path`.
pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
// At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
// However, at runtime, it will by default look for libgccjit.so.0.
// So when we install the built libgccjit.so file to the target `directory`, we add it there
// with the `.0` suffix.
let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
target_filename.push_str(".0");
let dst = directory.join(target_filename);
builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary);
}
}
impl Step for Gcc {
type Output = GccOutput;
@ -61,7 +77,6 @@ impl Step for Gcc {
}
build_gcc(&metadata, builder, target);
create_lib_alias(builder, &libgccjit_path);
t!(metadata.stamp.write());
@ -69,15 +84,6 @@ impl Step for Gcc {
}
}
/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not
/// already exist
fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) {
let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0");
if !lib_alias.exists() {
t!(builder.symlink_file(libgccjit, lib_alias));
}
}
pub struct Meta {
stamp: BuildStamp,
out_dir: PathBuf,
@ -124,7 +130,6 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
}
let libgccjit = root.join("lib").join("libgccjit.so");
create_lib_alias(builder, &libgccjit);
Some(libgccjit)
}
PathFreshness::HasLocalModifications { .. } => {

View file

@ -35,6 +35,7 @@ pub struct Finder {
const STAGE0_MISSING_TARGETS: &[&str] = &[
"armv7a-vex-v5",
// just a dummy comment so the list doesn't get onelined
"aarch64_be-unknown-none-softfloat",
];
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM

View file

@ -47,6 +47,7 @@
- [\*-apple-visionos](platform-support/apple-visionos.md)
- [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
- [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
- [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
- [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
- [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
- [arm-none-eabi](platform-support/arm-none-eabi.md)

View file

@ -273,6 +273,7 @@ target | std | host | notes
`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
`aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
[`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
[`aarch64_be-unknown-none-softfloat`](platform-support/aarch64_be-unknown-none-softfloat.md) | * | | Bare big-endian ARM64, softfloat
[`amdgcn-amd-amdhsa`](platform-support/amdgcn-amd-amdhsa.md) | * | | `-Ctarget-cpu=gfx...` to specify [the AMD GPU] to compile for
[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Arm Apple WatchOS 64-bit with 32-bit pointers
[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin

View file

@ -0,0 +1,74 @@
# aarch64_be-unknown-none-softfloat
**Tier: 3**
Target for freestanding/bare-metal big-endian ARM64 binaries in ELF format:
firmware, kernels, etc.
## Target maintainers
[@Gelbpunkt](https://github.com/Gelbpunkt)
## Requirements
This target is cross-compiled. There is no support for `std`. There is no
default allocator, but it's possible to use `alloc` by supplying an allocator.
The target does not assume existence of a FPU and does not make use of any
non-GPR register. This allows the generated code to run in environments, such
as kernels, which may need to avoid the use of such registers or which may have
special considerations about the use of such registers (e.g. saving and
restoring them to avoid breaking userspace code using the same registers). You
can change code generation to use additional CPU features via the
`-C target-feature=` codegen options to rustc, or via the `#[target_feature]`
mechanism within Rust code.
By default, code generated with the soft-float target should run on any
big-endian ARM64 hardware, enabling additional target features may raise this
baseline.
`extern "C"` uses the [architecture's standard calling convention][aapcs64].
[aapcs64]: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
The targets generate binaries in the ELF format. Any alternate formats or
special considerations for binary layout will require linker options or linker
scripts.
## Building the target
You can build Rust with support for the target by adding it to the `target`
list in `bootstrap.toml`:
```toml
[build]
target = ["aarch64_be-unknown-none-softfloat"]
```
## Building Rust programs
Rust does not yet ship pre-compiled artifacts for this target. To compile for
this target, you will first need to build Rust with the target enabled (see
"Building the target" above).
## Cross-compilation
For cross builds, you will need an appropriate ARM64 C/C++ toolchain for
linking, or if you want to compile C code along with Rust (such as for Rust
crates with C dependencies).
Rust *may* be able to use an `aarch64_be-unknown-linux-{gnu,musl}-` toolchain
with appropriate standalone flags to build for this target (depending on the
assumptions of that toolchain, see below), or you may wish to use a separate
`aarch64_be-unknown-none-softfloat` toolchain.
On some ARM64 hosts that use ELF binaries, you *may* be able to use the host C
toolchain, if it does not introduce assumptions about the host environment that
don't match the expectations of a standalone environment. Otherwise, you may
need a separate toolchain for standalone/freestanding development, just as when
cross-compiling from a non-ARM64 platform.
## Testing
As the target supports a variety of different environments and does not support
`std`, it does not support running the Rust test suite.

View file

@ -191,6 +191,20 @@ We can document it by escaping the initial `#`:
/// ## bar # baz";
```
Here is an example with a macro rule which matches on tokens starting with `#`:
`````rust,no_run
/// ```
/// macro_rules! ignore { (##tag) => {}; }
/// ignore! {
/// ###tag
/// }
/// ```
# fn f() {}
`````
As you can see, the rule is expecting two `#`, so when calling it, we need to add an extra `#`
because the first one is used as escape.
## Using `?` in doc tests

View file

@ -6,7 +6,7 @@ use std::sync::Arc;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::Mutability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def::{DefKind, MacroKinds, Res};
use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId};
use rustc_metadata::creader::{CStore, LoadedMacro};
use rustc_middle::ty::fast_reject::SimplifiedType;
@ -137,13 +137,16 @@ pub(crate) fn try_inline(
clean::ConstantItem(Box::new(ct))
})
}
Res::Def(DefKind::Macro(kind), did) => {
let mac = build_macro(cx, did, name, kind);
Res::Def(DefKind::Macro(kinds), did) => {
let mac = build_macro(cx, did, name, kinds);
let type_kind = match kind {
MacroKind::Bang => ItemType::Macro,
MacroKind::Attr => ItemType::ProcAttribute,
MacroKind::Derive => ItemType::ProcDerive,
// FIXME: handle attributes and derives that aren't proc macros, and macros with
// multiple kinds
let type_kind = match kinds {
MacroKinds::BANG => ItemType::Macro,
MacroKinds::ATTR => ItemType::ProcAttribute,
MacroKinds::DERIVE => ItemType::ProcDerive,
_ => todo!("Handle macros with multiple kinds"),
};
record_extern_fqn(cx, did, type_kind);
mac
@ -749,22 +752,36 @@ fn build_macro(
cx: &mut DocContext<'_>,
def_id: DefId,
name: Symbol,
macro_kind: MacroKind,
macro_kinds: MacroKinds,
) -> clean::ItemKind {
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
LoadedMacro::MacroDef { def, .. } => match macro_kind {
MacroKind::Bang => clean::MacroItem(clean::Macro {
// FIXME: handle attributes and derives that aren't proc macros, and macros with multiple
// kinds
LoadedMacro::MacroDef { def, .. } => match macro_kinds {
MacroKinds::BANG => clean::MacroItem(clean::Macro {
source: utils::display_macro_source(cx, name, &def),
macro_rules: def.macro_rules,
}),
MacroKind::Derive | MacroKind::Attr => {
clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
}
MacroKinds::DERIVE => clean::ProcMacroItem(clean::ProcMacro {
kind: MacroKind::Derive,
helpers: Vec::new(),
}),
MacroKinds::ATTR => clean::ProcMacroItem(clean::ProcMacro {
kind: MacroKind::Attr,
helpers: Vec::new(),
}),
_ => todo!("Handle macros with multiple kinds"),
},
LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
kind: ext.macro_kind(),
helpers: ext.helper_attrs,
}),
LoadedMacro::ProcMacro(ext) => {
// Proc macros can only have a single kind
let kind = match ext.macro_kinds() {
MacroKinds::BANG => MacroKind::Bang,
MacroKinds::ATTR => MacroKind::Attr,
MacroKinds::DERIVE => MacroKind::Derive,
_ => unreachable!(),
};
clean::ProcMacroItem(clean::ProcMacro { kind, helpers: ext.helper_attrs })
}
}
}

View file

@ -40,7 +40,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, In
use rustc_errors::codes::*;
use rustc_errors::{FatalError, struct_span_code_err};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
use rustc_hir::{LangItem, PredicateOrigin, find_attr};
use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
@ -2845,11 +2845,19 @@ fn clean_maybe_renamed_item<'tcx>(
generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro {
// FIXME: handle attributes and derives that aren't proc macros, and macros with
// multiple kinds
ItemKind::Macro(_, macro_def, MacroKinds::BANG) => MacroItem(Macro {
source: display_macro_source(cx, name, macro_def),
macro_rules: macro_def.macro_rules,
}),
ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
ItemKind::Macro(_, _, MacroKinds::ATTR) => {
clean_proc_macro(item, &mut name, MacroKind::Attr, cx)
}
ItemKind::Macro(_, _, MacroKinds::DERIVE) => {
clean_proc_macro(item, &mut name, MacroKind::Derive, cx)
}
ItemKind::Macro(_, _, _) => todo!("Handle macros with multiple kinds"),
// proc macros can have a name set by attributes
ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)

View file

@ -2,7 +2,7 @@
use std::fmt;
use rustc_hir::def::{CtorOf, DefKind};
use rustc_hir::def::{CtorOf, DefKind, MacroKinds};
use rustc_span::hygiene::MacroKind;
use serde::{Serialize, Serializer};
@ -134,9 +134,10 @@ impl ItemType {
DefKind::Trait => Self::Trait,
DefKind::TyAlias => Self::TypeAlias,
DefKind::TraitAlias => Self::TraitAlias,
DefKind::Macro(MacroKind::Bang) => ItemType::Macro,
DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute,
DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive,
DefKind::Macro(MacroKinds::BANG) => ItemType::Macro,
DefKind::Macro(MacroKinds::ATTR) => ItemType::ProcAttribute,
DefKind::Macro(MacroKinds::DERIVE) => ItemType::ProcDerive,
DefKind::Macro(_) => todo!("Handle macros with multiple kinds"),
DefKind::ForeignTy => Self::ForeignType,
DefKind::Variant => Self::Variant,
DefKind::Field => Self::StructField,

View file

@ -2060,7 +2060,9 @@ class DocSearch {
// Deprecated and unstable items and items with no description
this.searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c));
this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u));
if (crateCorpus.u !== undefined && crateCorpus.u !== null) {
this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u));
}
let descIndex = 0;
/**

View file

@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_errors::{Applicability, Diag, DiagMessage};
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{DefKind, Namespace, PerNS};
use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
use rustc_hir::{Mutability, Safety};
use rustc_middle::ty::{Ty, TyCtxt};
@ -25,7 +25,6 @@ use rustc_resolve::rustdoc::{
use rustc_session::config::CrateType;
use rustc_session::lint::Lint;
use rustc_span::BytePos;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Ident, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use tracing::{debug, info, instrument, trace};
@ -115,9 +114,11 @@ impl Res {
let prefix = match kind {
DefKind::Fn | DefKind::AssocFn => return Suggestion::Function,
DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro,
// FIXME: handle macros with multiple kinds, and attribute/derive macros that aren't
// proc macros
DefKind::Macro(MacroKinds::BANG) => return Suggestion::Macro,
DefKind::Macro(MacroKind::Derive) => "derive",
DefKind::Macro(MacroKinds::DERIVE) => "derive",
DefKind::Struct => "struct",
DefKind::Enum => "enum",
DefKind::Trait => "trait",
@ -881,9 +882,12 @@ fn trait_impls_for<'a>(
fn is_derive_trait_collision<T>(ns: &PerNS<Result<Vec<(Res, T)>, ResolutionFailure<'_>>>) -> bool {
if let (Ok(type_ns), Ok(macro_ns)) = (&ns.type_ns, &ns.macro_ns) {
type_ns.iter().any(|(res, _)| matches!(res, Res::Def(DefKind::Trait, _)))
&& macro_ns
.iter()
.any(|(res, _)| matches!(res, Res::Def(DefKind::Macro(MacroKind::Derive), _)))
&& macro_ns.iter().any(|(res, _)| {
matches!(
res,
Res::Def(DefKind::Macro(kinds), _) if kinds.contains(MacroKinds::DERIVE)
)
})
} else {
false
}
@ -1674,11 +1678,11 @@ impl Disambiguator {
let suffixes = [
// If you update this list, please also update the relevant rustdoc book section!
("!()", DefKind::Macro(MacroKind::Bang)),
("!{}", DefKind::Macro(MacroKind::Bang)),
("![]", DefKind::Macro(MacroKind::Bang)),
("!()", DefKind::Macro(MacroKinds::BANG)),
("!{}", DefKind::Macro(MacroKinds::BANG)),
("![]", DefKind::Macro(MacroKinds::BANG)),
("()", DefKind::Fn),
("!", DefKind::Macro(MacroKind::Bang)),
("!", DefKind::Macro(MacroKinds::BANG)),
];
if let Some(idx) = link.find('@') {
@ -1697,7 +1701,7 @@ impl Disambiguator {
safety: Safety::Safe,
}),
"function" | "fn" | "method" => Kind(DefKind::Fn),
"derive" => Kind(DefKind::Macro(MacroKind::Derive)),
"derive" => Kind(DefKind::Macro(MacroKinds::DERIVE)),
"field" => Kind(DefKind::Field),
"variant" => Kind(DefKind::Variant),
"type" => NS(Namespace::TypeNS),

View file

@ -5,7 +5,7 @@ use std::mem;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def::{DefKind, MacroKinds, Res};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
use rustc_hir::intravisit::{Visitor, walk_body, walk_item};
use rustc_hir::{CRATE_HIR_ID, Node};
@ -13,7 +13,6 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Symbol, kw, sym};
use tracing::debug;
@ -325,7 +324,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let is_bang_macro = matches!(
item,
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, MacroKind::Bang), .. })
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, kinds), .. }) if kinds.contains(MacroKinds::BANG)
);
if !self.view_item_stack.insert(res_did) && !is_bang_macro {
@ -406,7 +405,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
// attribute can still be visible.
|| match item.kind {
hir::ItemKind::Impl(..) => true,
hir::ItemKind::Macro(_, _, MacroKind::Bang) => {
hir::ItemKind::Macro(_, _, _) => {
self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
}
_ => false,

View file

@ -8,7 +8,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::MacroKind;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@ -503,8 +502,8 @@ impl LateLintPass<'_> for ItemNameRepetitions {
);
}
let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang));
if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule {
let is_macro = matches!(item.kind, ItemKind::Macro(_, _, _));
if both_are_public && item_camel.len() > mod_camel.len() && !is_macro {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();

View file

@ -7,7 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::hygiene::MacroKind;
declare_clippy_lint! {
/// ### What it does
@ -89,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
// We ignore macro exports. And `ListStem` uses, which aren't interesting.
fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
if let ItemKind::Use(path, kind) = item.kind {
let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(MacroKind::Bang), _)))
let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _)))
|| kind == UseKind::ListStem;
if ignore {
return true;

View file

@ -8,6 +8,10 @@
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::*;
// Verify config on outline-atomics works (it is always enabled on aarch64-linux).
#[cfg(not(target_feature = "outline-atomics"))]
compile_error!("outline-atomics is not enabled");
pub fn compare_exchange(a: &AtomicI32) {
// On AArch64 LLVM should outline atomic operations.
// CHECK: __aarch64_cas4_relax

View file

@ -10,6 +10,9 @@
//@ revisions: aarch64_be_unknown_netbsd
//@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd
//@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64
//@ revisions: aarch64_be_unknown_none_softfloat
//@ [aarch64_be_unknown_none_softfloat] compile-flags: --target aarch64_be-unknown-none-softfloat
//@ [aarch64_be_unknown_none_softfloat] needs-llvm-components: aarch64
//@ revisions: aarch64_kmc_solid_asp3
//@ [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3
//@ [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64

View file

@ -183,6 +183,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`nnp-assist`
`nontrapping-fptoint`
`nvic`
`outline-atomics`
`paca`
`pacg`
`pan`

View file

@ -7,9 +7,46 @@ macro_rules! local_attr {
//~^^ ERROR: local_attr
}
//~v NOTE: `fn_only` exists, but has no `attr` rules
macro_rules! fn_only {
{} => {}
}
//~v NOTE: `attr_only` exists, but has no rules for function-like invocation
macro_rules! attr_only {
attr() {} => {}
}
fn main() {
//~v NOTE: in this expansion of #[local_attr]
#[local_attr]
struct S;
local_attr!(arg); //~ ERROR: macro has no rules for function-like invocation
//~vv ERROR: cannot find macro `local_attr` in this scope
//~| NOTE: `local_attr` is in scope, but it is an attribute
local_attr!(arg);
//~v ERROR: cannot find attribute `fn_only` in this scope
#[fn_only]
struct S;
attr_only!(); //~ ERROR: cannot find macro `attr_only` in this scope
}
//~vv ERROR: cannot find attribute `forward_referenced_attr` in this scope
//~| NOTE: consider moving the definition of `forward_referenced_attr` before this call
#[forward_referenced_attr]
struct S;
//~v NOTE: a macro with the same name exists, but it appears later
macro_rules! forward_referenced_attr {
attr() {} => {}
}
//~vv ERROR: cannot find attribute `cyclic_attr` in this scope
//~| NOTE: consider moving the definition of `cyclic_attr` before this call
#[cyclic_attr]
//~v NOTE: a macro with the same name exists, but it appears later
macro_rules! cyclic_attr {
attr() {} => {}
}

View file

@ -9,14 +9,55 @@ LL | #[local_attr]
|
= note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
error: macro has no rules for function-like invocation `local_attr!`
--> $DIR/macro-rules-attr-error.rs:14:5
error: cannot find macro `local_attr` in this scope
--> $DIR/macro-rules-attr-error.rs:27:5
|
LL | macro_rules! local_attr {
| ----------------------- this macro has no rules for function-like invocation
...
LL | local_attr!(arg);
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^^^
|
= note: `local_attr` is in scope, but it is an attribute: `#[local_attr]`
error: aborting due to 2 previous errors
error: cannot find attribute `fn_only` in this scope
--> $DIR/macro-rules-attr-error.rs:30:7
|
LL | macro_rules! fn_only {
| ------- `fn_only` exists, but has no `attr` rules
...
LL | #[fn_only]
| ^^^^^^^
error: cannot find macro `attr_only` in this scope
--> $DIR/macro-rules-attr-error.rs:33:5
|
LL | macro_rules! attr_only {
| --------- `attr_only` exists, but has no rules for function-like invocation
...
LL | attr_only!();
| ^^^^^^^^^
error: cannot find attribute `forward_referenced_attr` in this scope
--> $DIR/macro-rules-attr-error.rs:38:3
|
LL | #[forward_referenced_attr]
| ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `forward_referenced_attr` before this call
|
note: a macro with the same name exists, but it appears later
--> $DIR/macro-rules-attr-error.rs:42:14
|
LL | macro_rules! forward_referenced_attr {
| ^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find attribute `cyclic_attr` in this scope
--> $DIR/macro-rules-attr-error.rs:48:3
|
LL | #[cyclic_attr]
| ^^^^^^^^^^^ consider moving the definition of `cyclic_attr` before this call
|
note: a macro with the same name exists, but it appears later
--> $DIR/macro-rules-attr-error.rs:50:14
|
LL | macro_rules! cyclic_attr {
| ^^^^^^^^^^^
error: aborting due to 6 previous errors

View file

@ -95,14 +95,6 @@ error: expected derive macro, found macro `crate::my_macro`
|
LL | #[derive(crate::my_macro)]
| ^^^^^^^^^^^^^^^ not a derive macro
|
help: remove from the surrounding `derive()`
--> $DIR/macro-namespace-reserved-2.rs:50:10
|
LL | #[derive(crate::my_macro)]
| ^^^^^^^^^^^^^^^
= help: add as non-Derive macro
`#[crate::my_macro]`
error: cannot find macro `my_macro_attr` in this scope
--> $DIR/macro-namespace-reserved-2.rs:28:5