Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,8 +645,9 @@ macro_rules! common_visitor_and_walkers {
fn visit_fn(
&mut self,
fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>,
_: &AttrVec,
_: Span,
_: NodeId
_: NodeId,
) -> Self::Result {
walk_fn(self, fk)
}
Expand Down Expand Up @@ -740,6 +741,7 @@ macro_rules! common_visitor_and_walkers {
type Ctxt;
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
attrs: &AttrVec,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
Expand Down Expand Up @@ -773,7 +775,7 @@ macro_rules! common_visitor_and_walkers {
) -> V::Result {
let Item { attrs, id, kind, vis, span, tokens: _ } = item;
visit_visitable!($($mut)? visitor, id, attrs, vis);
try_visit!(kind.walk(*span, *id, vis, ctxt, visitor));
try_visit!(kind.walk(attrs, *span, *id, vis, ctxt, visitor));
visit_visitable!($($mut)? visitor, span);
V::Result::output()
}
Expand All @@ -799,6 +801,7 @@ macro_rules! common_visitor_and_walkers {
type Ctxt = ();
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
attrs: &AttrVec,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
Expand All @@ -808,7 +811,7 @@ macro_rules! common_visitor_and_walkers {
match self {
ItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Free, visibility, &$($mut)? *func);
try_visit!(vis.visit_fn(kind, span, id));
try_visit!(vis.visit_fn(kind, attrs, span, id));
}
ItemKind::ExternCrate(orig_name, ident) =>
visit_visitable!($($mut)? vis, orig_name, ident),
Expand Down Expand Up @@ -856,6 +859,7 @@ macro_rules! common_visitor_and_walkers {
type Ctxt = AssocCtxt;
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
attrs: &AttrVec,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
Expand All @@ -867,7 +871,7 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, item),
AssocItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &$($mut)? *func);
try_visit!(vis.visit_fn(kind, span, id))
try_visit!(vis.visit_fn(kind, attrs, span, id))
}
AssocItemKind::Type(alias) =>
visit_visitable!($($mut)? vis, alias),
Expand All @@ -886,6 +890,7 @@ macro_rules! common_visitor_and_walkers {
type Ctxt = ();
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
attrs: &AttrVec,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
Expand All @@ -897,7 +902,7 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, item),
ForeignItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Foreign, visibility, &$($mut)?*func);
try_visit!(vis.visit_fn(kind, span, id))
try_visit!(vis.visit_fn(kind, attrs, span, id))
}
ForeignItemKind::TyAlias(alias) =>
visit_visitable!($($mut)? vis, alias),
Expand Down Expand Up @@ -999,7 +1004,7 @@ macro_rules! common_visitor_and_walkers {
}) => {
visit_visitable!($($mut)? vis, constness, movability, capture_clause);
let kind = FnKind::Closure(binder, coroutine_kind, fn_decl, body);
try_visit!(vis.visit_fn(kind, *span, *id));
try_visit!(vis.visit_fn(kind, attrs, *span, *id));
visit_visitable!($($mut)? vis, fn_decl_span, fn_arg_span);
}
ExprKind::Block(block, opt_label) =>
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"`
.label = `extern "{$abi}"` because of this
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list

ast_passes_c_variadic_bad_naked_extern = `...` is not supported for `extern "{$abi}"` naked functions
.label = `extern "{$abi}"` because of this
.help = C-variadic function must have a compatible calling convention

ast_passes_c_variadic_must_be_unsafe =
functions with a C variable argument list must be unsafe
.suggestion = add the `unsafe` keyword to this definition
Expand Down
115 changes: 86 additions & 29 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
use std::str::FromStr;

use itertools::{Either, Itertools};
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
use rustc_abi::{CVariadicStatus, CanonAbi, ExternAbi, InterruptKind};
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
Expand All @@ -35,6 +35,7 @@ use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
PATTERNS_IN_FNS_WITHOUT_BODY,
};
use rustc_session::parse::feature_err;
use rustc_span::{Ident, Span, kw, sym};
use rustc_target::spec::{AbiMap, AbiMapping};
use thin_vec::thin_vec;
Expand Down Expand Up @@ -659,7 +660,7 @@ impl<'a> AstValidator<'a> {
/// C-variadics must be:
/// - Non-const
/// - Either foreign, or free and `unsafe extern "C"` semantically
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
// `...` is already rejected when it is not the final parameter.
let variadic_param = match fk.decl().inputs.last() {
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
Expand Down Expand Up @@ -691,36 +692,92 @@ impl<'a> AstValidator<'a> {

match fn_ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free | FnCtxt::Assoc(_) => match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
FnCtxt::Free | FnCtxt::Assoc(_) => {
match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
// Just bail if the ABI is not even recognized.
let Ok(abi) = ExternAbi::from_str(symbol_unescaped.as_str()) else {
return;
};

self.check_c_variadic_abi(abi, attrs, variadic_param.span, sig);

if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
}
}
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: variadic_param.span,
abi: symbol_unescaped,
extern_span: sig.extern_span(),
});
}
}
}

fn check_c_variadic_abi(
&self,
abi: ExternAbi,
attrs: &'a AttrVec,
dotdotdot_span: Span,
sig: &FnSig,
) {
// For naked functions we accept any ABI that is accepted on c-variadic
// foreign functions, if the c_variadic_naked_functions feature is enabled.
if attr::contains_name(attrs, sym::naked) {
match abi.supports_c_variadic() {
CVariadicStatus::Stable if let ExternAbi::C { .. } = abi => {
// With `c_variadic` naked c-variadic `extern "C"` functions are allowed.
}
CVariadicStatus::Stable => {
// For e.g. aapcs or sysv64 `c_variadic_naked_functions` must also be enabled.
if !self.features.enabled(sym::c_variadic_naked_functions) {
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
.emit();
}
}
CVariadicStatus::Unstable { feature } => {
// Some ABIs need additional features.
if !self.features.enabled(sym::c_variadic_naked_functions) {
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
.emit();
}

if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
if !self.features.enabled(feature) {
let msg = format!(
"C-variadic functions with the {abi} calling convention are unstable"
);
feature_err(&self.sess, feature, sig.span, msg).emit();
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
CVariadicStatus::NotSupported => {
// Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions.
self.dcx().emit_err(errors::CVariadicBadNakedExtern {
span: dotdotdot_span,
abi: abi.as_str(),
extern_span: sig.extern_span(),
});
}
},
}
} else if !matches!(abi, ExternAbi::C { .. }) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: dotdotdot_span,
abi: abi.as_str(),
extern_span: sig.extern_span(),
});
}
}

Expand Down Expand Up @@ -1104,7 +1161,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}

let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
self.visit_fn(kind, item.span, item.id);
self.visit_fn(kind, &item.attrs, item.span, item.id);
}
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
Expand Down Expand Up @@ -1478,7 +1535,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_param_bound(self, bound)
}

fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) {
// Only associated `fn`s can have `self` parameters.
let self_semantic = match fk.ctxt() {
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
Expand All @@ -1497,7 +1554,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
}

self.check_c_variadic_type(fk);
self.check_c_variadic_type(fk, attrs);

// Functions cannot both be `const async` or `const gen`
if let Some(&FnHeader {
Expand Down Expand Up @@ -1648,7 +1705,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
{
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
self.visit_fn(kind, item.span, item.id);
self.visit_fn(kind, &item.attrs, item.span, item.id);
}
AssocItemKind::Type(_) => {
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,18 @@ pub(crate) struct CVariadicMustBeUnsafe {
pub(crate) struct CVariadicBadExtern {
#[primary_span]
pub span: Span,
pub abi: Symbol,
pub abi: &'static str,
#[label]
pub extern_span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_bad_naked_extern)]
#[help]
pub(crate) struct CVariadicBadNakedExtern {
#[primary_span]
pub span: Span,
pub abi: &'static str,
#[label]
pub extern_span: Span,
}
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{NodeId, PatKind, attr, token};
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
use rustc_session::Session;
use rustc_session::parse::{feature_err, feature_warn};
Expand Down Expand Up @@ -392,7 +391,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
visit::walk_poly_trait_ref(self, t);
}

fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId) {
if let Some(_header) = fn_kind.header() {
// Stability of const fn methods are covered in `visit_assoc_item` below.
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ declare_features! (
(unstable, avx10_target_feature, "1.88.0", Some(138843)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows defining c-variadic naked functions with any extern ABI that is allowed
/// on c-variadic foreign functions.
(unstable, c_variadic_naked_functions, "CURRENT_RUSTC_VERSION", Some(148767)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! syntactical lints.

use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
use rustc_ast::{self as ast, HasAttrs};
use rustc_ast::{self as ast, AttrVec, HasAttrs};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
use rustc_feature::Features;
Expand Down Expand Up @@ -135,7 +135,7 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
});
}

fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) {
fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id: ast::NodeId) {
lint_callback!(self, check_fn, fk, span, id);
ast_visit::walk_fn(self, fk);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_passes/src/input_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// completely accurate (some things might be counted twice, others missed).

use rustc_ast::visit::BoundKind;
use rustc_ast::{self as ast, NodeId, visit as ast_visit};
use rustc_ast::{self as ast, AttrVec, NodeId, visit as ast_visit};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::thousands::usize_with_underscores;
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
Expand Down Expand Up @@ -709,7 +709,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_where_predicate(self, p)
}

fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: Span, _: NodeId) {
fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: &AttrVec, _: Span, _: NodeId) {
self.record("FnDecl", None, fk.decl());
ast_visit::walk_fn(self, fk)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
// Visit attributes after items for backward compatibility.
// This way they can use `macro_rules` defined later.
self.visit_vis(&item.vis);
item.kind.walk(item.span, item.id, &item.vis, (), self);
item.kind.walk(&item.attrs, item.span, item.id, &item.vis, (), self);
visit::walk_list!(self, visit_attribute, &item.attrs);
}
_ => visit::walk_item(self, item),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
});
}

fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId) {
match fn_kind {
FnKind::Fn(
_ctxt,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
}
}
}
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: NodeId) {
let previous_value = self.diag_metadata.current_function;
match fn_kind {
// Bail if the function is foreign, and thus cannot validly have
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ symbols! {
c_str_literals,
c_unwind,
c_variadic,
c_variadic_naked_functions,
c_void,
call,
call_mut,
Expand Down
Loading
Loading