Auto merge of #139023 - jhpratt:rollup-4ou6ei4, r=jhpratt
Rollup of 7 pull requests
Successful merges:
- #138844 (expand: Leave traces when expanding `cfg` attributes)
- #138926 (Remove `kw::Empty` uses from `rustc_middle`.)
- #138989 (Clean up a few things in rustc_hir_analysis::check::region)
- #138999 (Report compiletest pass mode if forced)
- #139014 (Improve suggest construct with literal syntax instead of calling)
- #139015 (Remove unneeded LLVM CI test assertions)
- #139016 (Add job duration changes to post-merge analysis report)
r? `@ghost`
`@rustbot` modify labels: rollup
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2539700..51dd0f8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -69,6 +69,8 @@
env:
CI_JOB_NAME: ${{ matrix.name }}
CI_JOB_DOC_URL: ${{ matrix.doc_url }}
+ GITHUB_WORKFLOW_RUN_ID: ${{ github.run_id }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
# commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a1487ca..da739b0 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -334,8 +334,7 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) {
.filter(|attr| {
let arr = [
sym::allow,
- sym::cfg,
- sym::cfg_attr,
+ sym::cfg_trace,
sym::cfg_attr_trace,
sym::deny,
sym::expect,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index cdb1817..3dbfc19 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -593,7 +593,7 @@ fn print_either_attributes(
}
fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) -> bool {
- if attr.has_name(sym::cfg_attr_trace) {
+ if attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) {
// It's not a valid identifier, so avoid printing it
// to keep the printed code reasonably parse-able.
return false;
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index ada49ee..bcc2703 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -156,6 +156,19 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
.collect()
}
+pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute {
+ match &mut attr.kind {
+ AttrKind::Normal(normal) => {
+ let NormalAttr { item, tokens } = &mut **normal;
+ item.path.segments[0].ident.name = trace_name;
+ // This makes the trace attributes unobservable to token-based proc macros.
+ *tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default()));
+ }
+ AttrKind::DocComment(..) => unreachable!(),
+ }
+ attr
+}
+
#[macro_export]
macro_rules! configure {
($this:ident, $node:ident) => {
@@ -280,16 +293,7 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V
// A trace attribute left in AST in place of the original `cfg_attr` attribute.
// It can later be used by lints or other diagnostics.
- let mut trace_attr = cfg_attr.clone();
- match &mut trace_attr.kind {
- AttrKind::Normal(normal) => {
- let NormalAttr { item, tokens } = &mut **normal;
- item.path.segments[0].ident.name = sym::cfg_attr_trace;
- // This makes the trace attributes unobservable to token-based proc macros.
- *tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default()));
- }
- AttrKind::DocComment(..) => unreachable!(),
- }
+ let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace);
let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index d0bd8a8..22da117 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -33,7 +33,7 @@
use smallvec::SmallVec;
use crate::base::*;
-use crate::config::StripUnconfigured;
+use crate::config::{StripUnconfigured, attr_into_trace};
use crate::errors::{
EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,
RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
@@ -2003,7 +2003,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let attr_name = attr.ident().unwrap().name;
// `#[cfg]` and `#[cfg_attr]` are special - they are
// eagerly evaluated.
- if attr_name != sym::cfg && attr_name != sym::cfg_attr_trace {
+ if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace {
self.cx.sess.psess.buffer_lint(
UNUSED_ATTRIBUTES,
attr.span,
@@ -2027,11 +2027,10 @@ fn expand_cfg_true(
) -> (bool, Option<ast::MetaItem>) {
let (res, meta_item) = self.cfg().cfg_true(&attr);
if res {
- // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
- // and some tools like rustdoc and clippy rely on that. Find a way to remove them
- // while keeping the tools working.
- self.cx.expanded_inert_attrs.mark(&attr);
- node.visit_attrs(|attrs| attrs.insert(pos, attr));
+ // A trace attribute left in AST in place of the original `cfg` attribute.
+ // It can later be used by lints or other diagnostics.
+ let trace_attr = attr_into_trace(attr, sym::cfg_trace);
+ node.visit_attrs(|attrs| attrs.insert(pos, trace_attr));
}
(res, meta_item)
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index fd93645..6fe65c8 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -760,10 +760,14 @@ pub struct BuiltinAttribute {
template!(Word, List: r#""...""#), DuplicatesOk,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
- // Trace that is left when a `cfg_attr` attribute is expanded.
- // The attribute is not gated, to avoid stability errors, but it cannot be used in stable or
- // unstable code directly because `sym::cfg_attr_trace` is not a valid identifier, it can only
- // be generated by the compiler.
+ // Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
+ // The attributes are not gated, to avoid stability errors, but they cannot be used in stable
+ // or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they
+ // can only be generated by the compiler.
+ ungated!(
+ cfg_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
+ EncodeCrossCrate::No
+ ),
ungated!(
cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
EncodeCrossCrate::No
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 255f5fe..ba8124b 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -25,12 +25,18 @@
struct Context {
/// The scope that contains any new variables declared, plus its depth in
/// the scope tree.
- var_parent: Option<(Scope, ScopeDepth)>,
+ var_parent: Option<Scope>,
/// Region parent of expressions, etc., plus its depth in the scope tree.
parent: Option<(Scope, ScopeDepth)>,
}
+impl Context {
+ fn set_var_parent(&mut self) {
+ self.var_parent = self.parent.map(|(p, _)| p);
+ }
+}
+
struct ScopeResolutionVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -78,7 +84,7 @@ fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::It
//
// extern fn isalnum(c: c_int) -> c_int
}
- Some((parent_scope, _)) => visitor.scope_tree.record_var_scope(var_id, parent_scope),
+ Some(parent_scope) => visitor.scope_tree.record_var_scope(var_id, parent_scope),
}
}
@@ -113,7 +119,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi
// itself has returned.
visitor.enter_node_scope_with_dtor(blk.hir_id.local_id);
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
{
// This block should be kept approximately in sync with
@@ -132,7 +138,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi
local_id: blk.hir_id.local_id,
data: ScopeData::Remainder(FirstStatementIndex::new(i)),
});
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
visitor.visit_stmt(statement);
// We need to back out temporarily to the last enclosing scope
// for the `else` block, so that even the temporaries receiving
@@ -157,7 +163,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi
local_id: blk.hir_id.local_id,
data: ScopeData::Remainder(FirstStatementIndex::new(i)),
});
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
visitor.visit_stmt(statement)
}
hir::StmtKind::Item(..) => {
@@ -207,7 +213,7 @@ fn has_let_expr(expr: &Expr<'_>) -> bool {
visitor.terminating_scopes.insert(arm.hir_id.local_id);
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
if let Some(expr) = arm.guard
&& !has_let_expr(expr)
@@ -221,8 +227,6 @@ fn has_let_expr(expr: &Expr<'_>) -> bool {
}
fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
- visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node });
-
// If this is a binding then record the lifetime of that binding.
if let PatKind::Binding(..) = pat.kind {
record_var_lifetime(visitor, pat.hir_id.local_id);
@@ -486,7 +490,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi
ScopeData::IfThen
};
visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data });
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
visitor.visit_expr(cond);
visitor.visit_expr(then);
visitor.cx = expr_cx;
@@ -501,7 +505,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi
ScopeData::IfThen
};
visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data });
- visitor.cx.var_parent = visitor.cx.parent;
+ visitor.cx.set_var_parent();
visitor.visit_expr(cond);
visitor.visit_expr(then);
visitor.cx = expr_cx;
@@ -560,7 +564,7 @@ fn resolve_local<'tcx>(
) {
debug!("resolve_local(pat={:?}, init={:?})", pat, init);
- let blk_scope = visitor.cx.var_parent.map(|(p, _)| p);
+ let blk_scope = visitor.cx.var_parent;
// As an exception to the normal rules governing temporary
// lifetimes, initializers in a let have a temporary lifetime
@@ -625,10 +629,7 @@ fn resolve_local<'tcx>(
if is_binding_pat(pat) {
visitor.scope_tree.record_rvalue_candidate(
expr.hir_id,
- RvalueCandidateType::Pattern {
- target: expr.hir_id.local_id,
- lifetime: blk_scope,
- },
+ RvalueCandidate { target: expr.hir_id.local_id, lifetime: blk_scope },
);
}
}
@@ -733,10 +734,7 @@ fn record_rvalue_scope_if_borrow_expr<'tcx>(
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
visitor.scope_tree.record_rvalue_candidate(
subexpr.hir_id,
- RvalueCandidateType::Borrow {
- target: subexpr.hir_id.local_id,
- lifetime: blk_id,
- },
+ RvalueCandidate { target: subexpr.hir_id.local_id, lifetime: blk_id },
);
}
hir::ExprKind::Struct(_, fields, _) => {
@@ -857,13 +855,12 @@ fn visit_body(&mut self, body: &hir::Body<'tcx>) {
self.enter_body(body.value.hir_id, |this| {
if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() {
// The arguments and `self` are parented to the fn.
- this.cx.var_parent = this.cx.parent.take();
+ this.cx.set_var_parent();
for param in body.params {
this.visit_pat(param.pat);
}
// The body of the every fn is a root scope.
- this.cx.parent = this.cx.var_parent;
this.visit_expr(body.value)
} else {
// Only functions have an outer terminating (drop) scope, while
diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 98d7f77..973dc71 100644
--- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
@@ -2,7 +2,7 @@
use hir::def_id::DefId;
use rustc_hir as hir;
use rustc_middle::bug;
-use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
+use rustc_middle::middle::region::{RvalueCandidate, Scope, ScopeTree};
use rustc_middle::ty::RvalueScopes;
use tracing::debug;
@@ -55,15 +55,11 @@ fn record_rvalue_scope_rec(
fn record_rvalue_scope(
rvalue_scopes: &mut RvalueScopes,
expr: &hir::Expr<'_>,
- candidate: &RvalueCandidateType,
+ candidate: &RvalueCandidate,
) {
debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
- match candidate {
- RvalueCandidateType::Borrow { lifetime, .. }
- | RvalueCandidateType::Pattern { lifetime, .. } => {
- record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime)
- } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
- }
+ record_rvalue_scope_rec(rvalue_scopes, expr, candidate.lifetime)
+ // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
}
pub(crate) fn resolve_rvalue_scopes<'a, 'tcx>(
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 6686151..66ece8f 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -224,7 +224,7 @@ pub struct ScopeTree {
/// and not the enclosing *statement*. Expressions that are not present in this
/// table are not rvalue candidates. The set of rvalue candidates is computed
/// during type check based on a traversal of the AST.
- pub rvalue_candidates: HirIdMap<RvalueCandidateType>,
+ pub rvalue_candidates: HirIdMap<RvalueCandidate>,
/// Backwards incompatible scoping that will be introduced in future editions.
/// This information is used later for linting to identify locals and
@@ -308,15 +308,14 @@ pub struct ScopeTree {
pub yield_in_scope: UnordMap<Scope, Vec<YieldData>>,
}
-/// Identifies the reason that a given expression is an rvalue candidate
-/// (see the `rvalue_candidates` field for more information what rvalue
-/// candidates in general). In constants, the `lifetime` field is None
-/// to indicate that certain expressions escape into 'static and
-/// should have no local cleanup scope.
+/// See the `rvalue_candidates` field for more information on rvalue
+/// candidates in general.
+/// The `lifetime` field is None to indicate that certain expressions escape
+/// into 'static and should have no local cleanup scope.
#[derive(Debug, Copy, Clone, HashStable)]
-pub enum RvalueCandidateType {
- Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
- Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
+pub struct RvalueCandidate {
+ pub target: hir::ItemLocalId,
+ pub lifetime: Option<Scope>,
}
#[derive(Debug, Copy, Clone, HashStable)]
@@ -344,16 +343,12 @@ pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) {
self.var_map.insert(var, lifetime);
}
- pub fn record_rvalue_candidate(&mut self, var: HirId, candidate_type: RvalueCandidateType) {
- debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
- match &candidate_type {
- RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
- | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
- assert!(var.local_id != lifetime.local_id)
- }
- _ => {}
+ pub fn record_rvalue_candidate(&mut self, var: HirId, candidate: RvalueCandidate) {
+ debug!("record_rvalue_candidate(var={var:?}, candidate={candidate:?})");
+ if let Some(lifetime) = &candidate.lifetime {
+ assert!(var.local_id != lifetime.local_id)
}
- self.rvalue_candidates.insert(var, candidate_type);
+ self.rvalue_candidates.insert(var, candidate);
}
/// Returns the narrowest scope that encloses `id`, if any.
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 85d9db7..d4cc562 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -73,9 +73,7 @@ pub fn to_early_bound_region_data(&self) -> ty::EarlyParamRegion {
pub fn is_anonymous_lifetime(&self) -> bool {
match self.kind {
- GenericParamDefKind::Lifetime => {
- self.name == kw::UnderscoreLifetime || self.name == kw::Empty
- }
+ GenericParamDefKind::Lifetime => self.name == kw::UnderscoreLifetime,
_ => false,
}
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6bdd0a0..ac98cbc 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -457,7 +457,7 @@ impl EarlyParamRegion {
/// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`).
pub fn has_name(&self) -> bool {
- self.name != kw::UnderscoreLifetime && self.name != kw::Empty
+ self.name != kw::UnderscoreLifetime
}
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3ef8ecc..3281cb41 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2591,11 +2591,9 @@ pub fn pretty_print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), fm
// to fit that into a short string. Hence the recommendation to use
// `explain_region()` or `note_and_explain_region()`.
match *region {
- ty::ReEarlyParam(ref data) => {
- if data.name != kw::Empty {
- p!(write("{}", data.name));
- return Ok(());
- }
+ ty::ReEarlyParam(data) => {
+ p!(write("{}", data.name));
+ return Ok(());
}
ty::ReLateParam(ty::LateParamRegion { kind, .. }) => {
if let Some(name) = kind.get_name() {
@@ -2834,7 +2832,7 @@ fn name_by_region_index(
(name, ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name))
}
- ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime | kw::Empty) => {
+ ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime) => {
let name = next_name(self);
if let Some(lt_idx) = lifetime_idx {
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index fb52cf9..c78306f 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -400,9 +400,7 @@ pub fn from_bound(var: BoundVar, br: BoundRegionKind) -> LateParamRegionKind {
pub fn is_named(&self) -> bool {
match *self {
- LateParamRegionKind::Named(_, name) => {
- name != kw::UnderscoreLifetime && name != kw::Empty
- }
+ LateParamRegionKind::Named(_, name) => name != kw::UnderscoreLifetime,
_ => false,
}
}
@@ -475,7 +473,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl BoundRegionKind {
pub fn is_named(&self) -> bool {
match *self {
- BoundRegionKind::Named(_, name) => name != kw::UnderscoreLifetime && name != kw::Empty,
+ BoundRegionKind::Named(_, name) => name != kw::UnderscoreLifetime,
_ => false,
}
}
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 9ecde2a..6bbd650 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -16,7 +16,8 @@
use crate::{errors, parse_in};
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
- if attr.is_doc_comment() || attr.has_name(sym::cfg_attr_trace) {
+ if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
+ {
return;
}
@@ -215,11 +216,7 @@ pub fn check_builtin_meta_item(
template: AttributeTemplate,
deny_unsafety: bool,
) {
- // Some special attributes like `cfg` must be checked
- // before the generic check, so we skip them here.
- let should_skip = |name| name == sym::cfg;
-
- if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
+ if !is_attr_template_compatible(&template, &meta.kind) {
emit_malformed_attribute(psess, style, meta.span, name, template);
}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 9238c73..1e1fb42 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -272,6 +272,7 @@ fn check_attributes(
| sym::forbid
| sym::cfg
| sym::cfg_attr
+ | sym::cfg_trace
| sym::cfg_attr_trace
// need to be fixed
| sym::cfi_encoding // FIXME(cfi_encoding)
@@ -574,8 +575,7 @@ fn check_naked(
// NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate
const ALLOW_LIST: &[rustc_span::Symbol] = &[
// conditional compilation
- sym::cfg,
- sym::cfg_attr,
+ sym::cfg_trace,
sym::cfg_attr_trace,
// testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
sym::test,
@@ -2656,7 +2656,7 @@ fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'
// only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed
// if we allow more attributes (e.g., tool attributes and `allow/deny/warn`)
// in where clauses. After that, only `self.check_attributes` should be enough.
- const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr, sym::cfg_attr_trace];
+ const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace];
let spans = self
.tcx
.hir_attrs(where_predicate.hir_id)
diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
index 852d93b..25778ad 100644
--- a/compiler/rustc_query_system/src/ich/mod.rs
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -8,7 +8,7 @@
mod impls_syntax;
pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
- sym::cfg,
+ sym::cfg_trace, // FIXME should this really be ignored?
sym::rustc_if_this_changed,
sym::rustc_then_this_would_need,
sym::rustc_dirty,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index cf8db22..e40f84e 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1665,41 +1665,81 @@ fn smart_resolve_context_dependent_help(
// the struct literal syntax at all, as that will cause a subsequent error.
let fields = this.r.field_idents(def_id);
let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty());
- let (fields, applicability) = match fields {
- Some(fields) => {
- let fields = if let Some(old_fields) = old_fields {
- fields
- .iter()
- .enumerate()
- .map(|(idx, new)| (new, old_fields.get(idx)))
- .map(|(new, old)| {
- if let Some(Some(old)) = old
- && new.as_str() != old
- {
- format!("{new}: {old}")
- } else {
- new.to_string()
- }
- })
- .collect::<Vec<String>>()
- } else {
- fields
- .iter()
- .map(|f| format!("{f}{tail}"))
- .collect::<Vec<String>>()
- };
- (fields.join(", "), applicability)
- }
- None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
- };
- let pad = if has_fields { " " } else { "" };
- err.span_suggestion(
+ if let PathSource::Expr(Some(Expr {
+ kind: ExprKind::Call(path, args),
span,
- format!("use struct {descr} syntax instead"),
- format!("{path_str} {{{pad}{fields}{pad}}}"),
- applicability,
- );
+ ..
+ })) = source
+ && !args.is_empty()
+ && let Some(fields) = &fields
+ && args.len() == fields.len()
+ // Make sure we have same number of args as fields
+ {
+ let path_span = path.span;
+ let mut parts = Vec::new();
+
+ // Start with the opening brace
+ parts.push((
+ path_span.shrink_to_hi().until(args[0].span),
+ "{".to_owned(),
+ ));
+
+ for (field, arg) in fields.iter().zip(args.iter()) {
+ // Add the field name before the argument
+ parts.push((arg.span.shrink_to_lo(), format!("{}: ", field)));
+ }
+
+ // Add the closing brace
+ parts.push((
+ args.last().unwrap().span.shrink_to_hi().until(span.shrink_to_hi()),
+ "}".to_owned(),
+ ));
+
+ err.multipart_suggestion_verbose(
+ format!("use struct {descr} syntax instead of calling"),
+ parts,
+ applicability,
+ );
+ } else {
+ let (fields, applicability) = match fields {
+ Some(fields) => {
+ let fields = if let Some(old_fields) = old_fields {
+ fields
+ .iter()
+ .enumerate()
+ .map(|(idx, new)| (new, old_fields.get(idx)))
+ .map(|(new, old)| {
+ if let Some(Some(old)) = old
+ && new.as_str() != old
+ {
+ format!("{new}: {old}")
+ } else {
+ new.to_string()
+ }
+ })
+ .collect::<Vec<String>>()
+ } else {
+ fields
+ .iter()
+ .map(|f| format!("{f}{tail}"))
+ .collect::<Vec<String>>()
+ };
+
+ (fields.join(", "), applicability)
+ }
+ None => {
+ ("/* fields */".to_string(), Applicability::HasPlaceholders)
+ }
+ };
+ let pad = if has_fields { " " } else { "" };
+ err.span_suggestion(
+ span,
+ format!("use struct {descr} syntax instead"),
+ format!("{path_str} {{{pad}{fields}{pad}}}"),
+ applicability,
+ );
+ }
}
if let PathSource::Expr(Some(Expr {
kind: ExprKind::Call(path, args),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 555764c..6807f96 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -623,6 +623,7 @@
cfg_target_has_atomic_equal_alignment,
cfg_target_thread_local,
cfg_target_vendor,
+ cfg_trace: "<cfg>", // must not be a valid identifier
cfg_ub_checks,
cfg_version,
cfi,
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 068e237..6d63709 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -24,31 +24,11 @@ pub(crate) fn parse(config: &str) -> Config {
#[test]
fn download_ci_llvm() {
- let config = parse("");
- let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions);
- if is_available {
- assert!(config.llvm_from_ci);
- }
-
- let config = Config::parse_inner(
- Flags::parse(&[
- "check".to_string(),
- "--config=/does/not/exist".to_string(),
- "--ci".to_string(),
- "false".to_string(),
- ]),
- |&_| toml::from_str("llvm.download-ci-llvm = true"),
- );
- let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions);
- if is_available {
- assert!(config.llvm_from_ci);
- }
-
let config = parse("llvm.download-ci-llvm = false");
assert!(!config.llvm_from_ci);
let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\"");
- if if_unchanged_config.llvm_from_ci {
+ if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci {
let has_changes = if_unchanged_config
.last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true)
.is_none();
diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs
index 885fff9..862c444 100644
--- a/src/bootstrap/src/utils/metrics.rs
+++ b/src/bootstrap/src/utils/metrics.rs
@@ -9,9 +9,10 @@
use std::io::BufWriter;
use std::time::{Duration, Instant, SystemTime};
+use build_helper::ci::CiEnv;
use build_helper::metrics::{
- JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test,
- TestOutcome, TestSuite, TestSuiteMetadata,
+ CiMetadata, JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats,
+ Test, TestOutcome, TestSuite, TestSuiteMetadata,
};
use sysinfo::{CpuRefreshKind, RefreshKind, System};
@@ -217,7 +218,12 @@ pub(crate) fn persist(&self, build: &Build) {
children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(),
});
- let json = JsonRoot { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations };
+ let json = JsonRoot {
+ format_version: CURRENT_FORMAT_VERSION,
+ system_stats,
+ invocations,
+ ci_metadata: get_ci_metadata(CiEnv::current()),
+ };
t!(std::fs::create_dir_all(dest.parent().unwrap()));
let mut file = BufWriter::new(t!(File::create(&dest)));
@@ -245,6 +251,16 @@ fn prepare_json_step(&self, step: StepMetrics) -> JsonNode {
}
}
+fn get_ci_metadata(ci_env: CiEnv) -> Option<CiMetadata> {
+ if ci_env != CiEnv::GitHubActions {
+ return None;
+ }
+ let workflow_run_id =
+ std::env::var("GITHUB_WORKFLOW_RUN_ID").ok().and_then(|id| id.parse::<u64>().ok())?;
+ let repository = std::env::var("GITHUB_REPOSITORY").ok()?;
+ Some(CiMetadata { workflow_run_id, repository })
+}
+
struct MetricsState {
finished_steps: Vec<StepMetrics>,
running_steps: Vec<StepMetrics>,
diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs
index fdff9cd..8b82e62 100644
--- a/src/build_helper/src/metrics.rs
+++ b/src/build_helper/src/metrics.rs
@@ -9,6 +9,19 @@ pub struct JsonRoot {
pub format_version: usize,
pub system_stats: JsonInvocationSystemStats,
pub invocations: Vec<JsonInvocation>,
+ #[serde(default)]
+ pub ci_metadata: Option<CiMetadata>,
+}
+
+/// Represents metadata about bootstrap's execution in CI.
+#[derive(Serialize, Deserialize)]
+pub struct CiMetadata {
+ /// GitHub run ID of the workflow where bootstrap was executed.
+ /// Note that the run ID will be shared amongst all jobs executed in that workflow.
+ pub workflow_run_id: u64,
+ /// Full name of a GitHub repository where bootstrap was executed in CI.
+ /// e.g. `rust-lang-ci/rust`.
+ pub repository: String,
}
#[derive(Serialize, Deserialize)]
diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs
index 2b001f2..7fbfad4 100644
--- a/src/ci/citool/src/analysis.rs
+++ b/src/ci/citool/src/analysis.rs
@@ -1,5 +1,6 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::Debug;
+use std::time::Duration;
use build_helper::metrics::{
BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name,
@@ -184,11 +185,70 @@ fn write_row(
}
/// Outputs a report of test differences between the `parent` and `current` commits.
-pub fn output_test_diffs(job_metrics: HashMap<JobName, JobMetrics>) {
+pub fn output_test_diffs(job_metrics: &HashMap<JobName, JobMetrics>) {
let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
report_test_diffs(aggregated_test_diffs);
}
+/// Prints the ten largest differences in bootstrap durations.
+pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics>) {
+ struct Entry<'a> {
+ job: &'a JobName,
+ before: Duration,
+ after: Duration,
+ change: f64,
+ }
+
+ let mut changes: Vec<Entry> = vec![];
+ for (job, metrics) in job_metrics {
+ if let Some(parent) = &metrics.parent {
+ let duration_before = parent
+ .invocations
+ .iter()
+ .map(|i| BuildStep::from_invocation(i).duration)
+ .sum::<Duration>();
+ let duration_after = metrics
+ .current
+ .invocations
+ .iter()
+ .map(|i| BuildStep::from_invocation(i).duration)
+ .sum::<Duration>();
+ let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64();
+ let pct_change = pct_change * 100.0;
+ // Normalize around 100, to get + for regression and - for improvements
+ let pct_change = pct_change - 100.0;
+ changes.push(Entry {
+ job,
+ before: duration_before,
+ after: duration_after,
+ change: pct_change,
+ });
+ }
+ }
+ changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse());
+
+ println!("# Job duration changes");
+ for (index, entry) in changes.into_iter().take(10).enumerate() {
+ println!(
+ "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)",
+ index + 1,
+ entry.job,
+ entry.before.as_secs_f64(),
+ entry.after.as_secs_f64(),
+ entry.change
+ );
+ }
+
+ println!();
+ output_details("How to interpret the job duration changes?", || {
+ println!(
+ r#"Job durations can vary a lot, based on the actual runner instance
+that executed the job, system noise, invalidated caches, etc. The table above is provided
+mostly for t-infra members, for simpler debugging of potential CI slow-downs."#
+ );
+ });
+}
+
#[derive(Default)]
struct TestSuiteRecord {
passed: u64,
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index 5f5c50d..6db5eab 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -15,7 +15,7 @@
use jobs::JobDatabase;
use serde_yaml::Value;
-use crate::analysis::output_test_diffs;
+use crate::analysis::{output_largest_duration_changes, output_test_diffs};
use crate::cpu_usage::load_cpu_usage;
use crate::datadog::upload_datadog_metric;
use crate::jobs::RunType;
@@ -160,7 +160,7 @@ fn postprocess_metrics(
job_name,
JobMetrics { parent: Some(parent_metrics), current: metrics },
)]);
- output_test_diffs(job_metrics);
+ output_test_diffs(&job_metrics);
return Ok(());
}
Err(error) => {
@@ -180,7 +180,8 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow
let metrics = download_auto_job_metrics(&db, &parent, ¤t)?;
println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
- output_test_diffs(metrics);
+ output_test_diffs(&metrics);
+ output_largest_duration_changes(&metrics);
Ok(())
}
diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs
index 086aa50..a816fb3 100644
--- a/src/ci/citool/src/metrics.rs
+++ b/src/ci/citool/src/metrics.rs
@@ -1,5 +1,5 @@
use std::collections::HashMap;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use anyhow::Context;
use build_helper::metrics::{JsonNode, JsonRoot, TestSuite};
@@ -74,6 +74,17 @@ pub fn download_auto_job_metrics(
}
pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
+ // Best effort cache to speed-up local re-executions of citool
+ let cache_path = PathBuf::from(".citool-cache").join(sha).join(format!("{job_name}.json"));
+ if cache_path.is_file() {
+ if let Ok(metrics) = std::fs::read_to_string(&cache_path)
+ .map_err(|err| err.into())
+ .and_then(|data| anyhow::Ok::<JsonRoot>(serde_json::from_str::<JsonRoot>(&data)?))
+ {
+ return Ok(metrics);
+ }
+ }
+
let url = get_metrics_url(job_name, sha);
let mut response = ureq::get(&url).call()?;
if !response.status().is_success() {
@@ -87,6 +98,13 @@ pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoo
.body_mut()
.read_json()
.with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
+
+ if let Ok(_) = std::fs::create_dir_all(cache_path.parent().unwrap()) {
+ if let Ok(data) = serde_json::to_string(&data) {
+ let _ = std::fs::write(cache_path, data);
+ }
+ }
+
Ok(data)
}
diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs
index b9b1bf4..a4c6ff8 100644
--- a/src/ci/citool/src/utils.rs
+++ b/src/ci/citool/src/utils.rs
@@ -23,7 +23,6 @@ pub fn output_details<F>(summary: &str, func: F)
println!(
r"<details>
<summary>{summary}</summary>
-
"
);
func();
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 2805bb1..00d791e 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -355,6 +355,8 @@
--env GITHUB_ACTIONS \
--env GITHUB_REF \
--env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \
+ --env GITHUB_WORKFLOW_RUN_ID \
+ --env GITHUB_REPOSITORY \
--env RUST_BACKTRACE \
--env TOOLSTATE_REPO_ACCESS_TOKEN \
--env TOOLSTATE_REPO \
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ada370a..c08ae16 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1943,14 +1943,11 @@ fn clean_trait_object_lifetime_bound<'tcx>(
// latter contrary to `clean_middle_region`.
match *region {
ty::ReStatic => Some(Lifetime::statik()),
- ty::ReEarlyParam(region) if region.name != kw::Empty => Some(Lifetime(region.name)),
- ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. })
- if name != kw::Empty =>
- {
+ ty::ReEarlyParam(region) => Some(Lifetime(region.name)),
+ ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => {
Some(Lifetime(name))
}
- ty::ReEarlyParam(_)
- | ty::ReBound(..)
+ ty::ReBound(..)
| ty::ReLateParam(_)
| ty::ReVar(_)
| ty::RePlaceholder(_)
@@ -2773,7 +2770,7 @@ fn add_without_unwanted_attributes<'hir>(
if ident == sym::doc {
filter_doc_attr(&mut normal.args, is_inline);
attrs.push((Cow::Owned(attr), import_parent));
- } else if is_inline || ident != sym::cfg {
+ } else if is_inline || ident != sym::cfg_trace {
// If it's not a `cfg()` attribute, we keep it.
attrs.push((Cow::Owned(attr), import_parent));
}
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2cfbbd7..143191a 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1068,7 +1068,7 @@ fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
// `doc(cfg())` overrides `cfg()`).
attrs
.clone()
- .filter(|attr| attr.has_name(sym::cfg))
+ .filter(|attr| attr.has_name(sym::cfg_trace))
.filter_map(|attr| single(attr.meta_item_list()?))
.filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index 5c486eb..4c84e61 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -37,7 +37,6 @@ fn check_duplicated_attr(
let Some(ident) = attr.ident() else { return };
let name = ident.name;
if name == sym::doc
- || name == sym::cfg_attr
|| name == sym::cfg_attr_trace
|| name == sym::rustc_on_unimplemented
|| name == sym::reason {
@@ -47,7 +46,7 @@ fn check_duplicated_attr(
return;
}
if let Some(direct_parent) = parent.last()
- && ["cfg", "cfg_attr"].contains(&direct_parent.as_str())
+ && direct_parent == sym::cfg_trace.as_str()
&& [sym::all, sym::not, sym::any].contains(&name)
{
// FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one
diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
index 84136a2..7590fe9 100644
--- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
+++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
@@ -32,7 +32,7 @@
impl EarlyLintPass for CfgNotTest {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) {
- if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) {
+ if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) {
span_lint_and_then(
cx,
CFG_NOT_TEST,
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index 7c190e1..4c81b22 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool {
cx.tcx
.hir_parent_id_iter(id)
- .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg)))
+ .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace)))
}
/// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 1307ff7..668b0cb 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2629,7 +2629,7 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>
pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
if let Res::Def(_, def_id) = path.res {
- return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
+ return cx.tcx.has_attr(def_id, sym::cfg_trace) || cx.tcx.has_attr(def_id, sym::cfg_attr);
}
}
false
@@ -2699,7 +2699,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
/// use [`is_in_cfg_test`]
pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
tcx.hir_attrs(id).iter().any(|attr| {
- if attr.has_name(sym::cfg)
+ if attr.has_name(sym::cfg_trace)
&& let Some(items) = attr.meta_item_list()
&& let [item] = &*items
&& item.has_name(sym::test)
@@ -2723,11 +2723,11 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
- tcx.has_attr(def_id, sym::cfg)
+ tcx.has_attr(def_id, sym::cfg_trace)
|| tcx
.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
.flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id))
- .any(|attr| attr.has_name(sym::cfg))
+ .any(|attr| attr.has_name(sym::cfg_trace))
}
/// Walks up the HIR tree from the given expression in an attempt to find where the value is
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 3ec984e..950566b 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -22,6 +22,7 @@
use core::panic;
use std::collections::HashSet;
use std::ffi::OsString;
+use std::fmt::Write;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
@@ -570,18 +571,22 @@ pub fn run_tests(config: Arc<Config>) {
// easy to miss which tests failed, and as such fail to reproduce
// the failure locally.
- println!(
- "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
- config.suite,
- config
- .compare_mode
- .as_ref()
- .map(|c| format!(" compare_mode={:?}", c))
- .unwrap_or_default(),
- config.mode,
- config.host,
- config.target
- );
+ let mut msg = String::from("Some tests failed in compiletest");
+ write!(msg, " suite={}", config.suite).unwrap();
+
+ if let Some(compare_mode) = config.compare_mode.as_ref() {
+ write!(msg, " compare_mode={}", compare_mode).unwrap();
+ }
+
+ if let Some(pass_mode) = config.force_pass_mode.as_ref() {
+ write!(msg, " pass_mode={}", pass_mode).unwrap();
+ }
+
+ write!(msg, " mode={}", config.mode).unwrap();
+ write!(msg, " host={}", config.host).unwrap();
+ write!(msg, " target={}", config.target).unwrap();
+
+ println!("{msg}");
std::process::exit(1);
}
diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp
index 31449b5..d6a2c0f 100644
--- a/tests/pretty/tests-are-sorted.pp
+++ b/tests/pretty/tests-are-sorted.pp
@@ -10,7 +10,6 @@
//@ pp-exact:tests-are-sorted.pp
extern crate test;
-#[cfg(test)]
#[rustc_test_marker = "m_test"]
#[doc(hidden)]
pub const m_test: test::TestDescAndFn =
@@ -35,7 +34,6 @@
fn m_test() {}
extern crate test;
-#[cfg(test)]
#[rustc_test_marker = "z_test"]
#[doc(hidden)]
pub const z_test: test::TestDescAndFn =
@@ -61,7 +59,6 @@
fn z_test() {}
extern crate test;
-#[cfg(test)]
#[rustc_test_marker = "a_test"]
#[doc(hidden)]
pub const a_test: test::TestDescAndFn =
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 9a04155..416145a 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -29,7 +29,6 @@ macro_rules! generate_s10 {
($expr: expr) => {
#[cfg(feature = $expr)]
//~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")`
- //~| ERROR expected unsuffixed literal, found expression `concat!("nonexistent")`
struct S10;
}
}
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 21a3712..d02d0d7 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -65,19 +65,7 @@
|
= note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: expected unsuffixed literal, found expression `concat!("nonexistent")`
- --> $DIR/cfg-attr-syntax-validation.rs:30:25
- |
-LL | #[cfg(feature = $expr)]
- | ^^^^^
-...
-LL | generate_s10!(concat!("nonexistent"));
- | ------------------------------------- in this macro invocation
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
- = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 11 previous errors
+error: aborting due to 10 previous errors
Some errors have detailed explanations: E0537, E0565.
For more information about an error, try `rustc --explain E0537`.
diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs
index 794e6fa..7c42be3 100644
--- a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs
+++ b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs
@@ -1,11 +1,12 @@
// This was triggering an assertion failure in `NodeRange::new`.
+//@ check-pass
+
#![feature(cfg_eval)]
#![feature(stmt_expr_attributes)]
fn f() -> u32 {
#[cfg_eval] #[cfg(not(FALSE))] 0
- //~^ ERROR removing an expression is not supported in this position
}
fn main() {}
diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr
deleted file mode 100644
index 0699e18..0000000
--- a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: removing an expression is not supported in this position
- --> $DIR/invalid-node-range-issue-129166.rs:7:17
- |
-LL | #[cfg_eval] #[cfg(not(FALSE))] 0
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs
index 2d0c6db..937390a 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs
@@ -2,7 +2,6 @@
($attr_item: meta) => {
#[cfg($attr_item)]
//~^ ERROR expected unsuffixed literal, found `meta` metavariable
- //~| ERROR expected unsuffixed literal, found `meta` metavariable
struct S;
}
}
@@ -11,7 +10,6 @@
#[cfg(feature = -1)]
//~^ ERROR expected unsuffixed literal, found `-`
-//~| ERROR expected unsuffixed literal, found `-`
fn handler() {}
fn main() {}
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
index dea574f..9c6ab5a 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
@@ -1,5 +1,5 @@
error: expected unsuffixed literal, found `-`
- --> $DIR/attr-bad-meta-4.rs:12:17
+ --> $DIR/attr-bad-meta-4.rs:11:17
|
LL | #[cfg(feature = -1)]
| ^
@@ -15,25 +15,5 @@
|
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: expected unsuffixed literal, found `meta` metavariable
- --> $DIR/attr-bad-meta-4.rs:3:15
- |
-LL | #[cfg($attr_item)]
- | ^^^^^^^^^^
-...
-LL | mac!(an(arbitrary token stream));
- | -------------------------------- in this macro invocation
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
- = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: expected unsuffixed literal, found `-`
- --> $DIR/attr-bad-meta-4.rs:12:17
- |
-LL | #[cfg(feature = -1)]
- | ^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
diff --git a/tests/ui/proc-macro/cfg-attr-trace.rs b/tests/ui/proc-macro/cfg-attr-trace.rs
index b4927f7..140dd10 100644
--- a/tests/ui/proc-macro/cfg-attr-trace.rs
+++ b/tests/ui/proc-macro/cfg-attr-trace.rs
@@ -3,6 +3,7 @@
//@ check-pass
//@ proc-macro: test-macros.rs
+#![feature(cfg_boolean_literals)]
#![feature(cfg_eval)]
#[macro_use]
@@ -10,8 +11,13 @@
#[cfg_eval]
#[test_macros::print_attr]
-#[cfg_attr(FALSE, test_macros::print_attr)]
-#[cfg_attr(all(), test_macros::print_attr)]
+#[cfg_attr(false, test_macros::print_attr)]
+#[cfg_attr(true, test_macros::print_attr)]
struct S;
+#[cfg_eval]
+#[test_macros::print_attr]
+#[cfg(true)]
+struct Z;
+
fn main() {}
diff --git a/tests/ui/proc-macro/cfg-attr-trace.stdout b/tests/ui/proc-macro/cfg-attr-trace.stdout
index 394c388..52f9ff4 100644
--- a/tests/ui/proc-macro/cfg-attr-trace.stdout
+++ b/tests/ui/proc-macro/cfg-attr-trace.stdout
@@ -4,59 +4,75 @@
Punct {
ch: '#',
spacing: Alone,
- span: #0 bytes(271..272),
+ span: #0 bytes(305..306),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "test_macros",
- span: #0 bytes(289..300),
+ span: #0 bytes(322..333),
},
Punct {
ch: ':',
spacing: Joint,
- span: #0 bytes(300..301),
+ span: #0 bytes(333..334),
},
Punct {
ch: ':',
spacing: Alone,
- span: #0 bytes(301..302),
+ span: #0 bytes(334..335),
},
Ident {
ident: "print_attr",
- span: #0 bytes(302..312),
+ span: #0 bytes(335..345),
},
],
- span: #0 bytes(272..314),
+ span: #0 bytes(306..347),
},
Ident {
ident: "struct",
- span: #0 bytes(315..321),
+ span: #0 bytes(348..354),
},
Ident {
ident: "S",
- span: #0 bytes(322..323),
+ span: #0 bytes(355..356),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(323..324),
+ span: #0 bytes(356..357),
},
]
PRINT-ATTR INPUT (DISPLAY): struct S;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #0 bytes(315..321),
+ span: #0 bytes(348..354),
},
Ident {
ident: "S",
- span: #0 bytes(322..323),
+ span: #0 bytes(355..356),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(323..324),
+ span: #0 bytes(356..357),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): struct Z;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "struct",
+ span: #0 bytes(411..417),
+ },
+ Ident {
+ ident: "Z",
+ span: #0 bytes(418..419),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #0 bytes(419..420),
},
]
diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.rs b/tests/ui/structs/struct-construct-with-call-issue-138931.rs
new file mode 100644
index 0000000..5d50eb1
--- /dev/null
+++ b/tests/ui/structs/struct-construct-with-call-issue-138931.rs
@@ -0,0 +1,25 @@
+struct PersonOnlyName {
+ name: String
+}
+
+struct PersonWithAge {
+ name: String,
+ age: u8,
+ height: u8,
+}
+
+
+
+fn main() {
+ let wilfred = PersonOnlyName("Name1".to_owned());
+ //~^ ERROR expected function, tuple struct or tuple variant, found struct `PersonOnlyName` [E0423]
+
+ let bill = PersonWithAge( //~ ERROR expected function, tuple struct or tuple variant, found struct `PersonWithAge` [E0423]
+ "Name2".to_owned(),
+ 20,
+ 180,
+ );
+
+ let person = PersonWithAge("Name3".to_owned());
+ //~^ ERROR expected function, tuple struct or tuple variant, found struct `PersonWithAge` [E0423]
+}
diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr
new file mode 100644
index 0000000..acae01d
--- /dev/null
+++ b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr
@@ -0,0 +1,58 @@
+error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonOnlyName`
+ --> $DIR/struct-construct-with-call-issue-138931.rs:14:19
+ |
+LL | / struct PersonOnlyName {
+LL | | name: String
+LL | | }
+ | |_- `PersonOnlyName` defined here
+...
+LL | let wilfred = PersonOnlyName("Name1".to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use struct literal syntax instead of calling
+ |
+LL - let wilfred = PersonOnlyName("Name1".to_owned());
+LL + let wilfred = PersonOnlyName{name: "Name1".to_owned()};
+ |
+
+error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge`
+ --> $DIR/struct-construct-with-call-issue-138931.rs:17:16
+ |
+LL | / struct PersonWithAge {
+LL | | name: String,
+LL | | age: u8,
+LL | | height: u8,
+LL | | }
+ | |_- `PersonWithAge` defined here
+...
+LL | let bill = PersonWithAge(
+ | ________________^
+LL | | "Name2".to_owned(),
+LL | | 20,
+LL | | 180,
+LL | | );
+ | |_____^
+ |
+help: use struct literal syntax instead of calling
+ |
+LL ~ let bill = PersonWithAge{name: "Name2".to_owned(),
+LL ~ age: 20,
+LL ~ height: 180};
+ |
+
+error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge`
+ --> $DIR/struct-construct-with-call-issue-138931.rs:23:18
+ |
+LL | / struct PersonWithAge {
+LL | | name: String,
+LL | | age: u8,
+LL | | height: u8,
+LL | | }
+ | |_- `PersonWithAge` defined here
+...
+LL | let person = PersonWithAge("Name3".to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0423`.