1
Fork 0

Rollup merge of #86838 - lambinoo:I-69630-rust_const_unstable_check_const, r=oli-obk

Checking that function is const if marked with rustc_const_unstable

Fixes #69630

This one is still missing tests to check the behavior but I checked by hand and it seemed to work.
I would not mind some direction for writing those unit tests!
This commit is contained in:
Guillaume Gomez 2021-07-08 18:30:34 +02:00 committed by GitHub
commit d85718ad01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 220 additions and 7 deletions

View file

@ -20,6 +20,7 @@ use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use std::cmp::Ordering;
use std::iter;
@ -95,10 +96,12 @@ struct Annotator<'a, 'tcx> {
impl<'a, 'tcx> Annotator<'a, 'tcx> {
// Determine the stability for a node based on its attributes and inherited
// stability. The stability is recorded in the index and used as the parent.
// If the node is a function, `fn_sig` is its signature
fn annotate<F>(
&mut self,
hir_id: HirId,
item_sp: Span,
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
kind: AnnotationKind,
inherit_deprecation: InheritDeprecation,
inherit_const_stability: InheritConstStability,
@ -163,13 +166,30 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, _)| {
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
let const_stab = self.tcx.intern_const_stability(const_stab);
self.index.const_stab_map.insert(hir_id, const_stab);
const_span = Some(const_span_node);
const_stab
});
// If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
// check if the function/method is const or the parent impl block is const
if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) {
if fn_sig.header.abi != Abi::RustIntrinsic
&& fn_sig.header.abi != Abi::PlatformIntrinsic
&& !fn_sig.header.is_const()
{
if !self.in_trait_impl
|| (self.in_trait_impl && !self.tcx.is_const_fn_raw(hir_id.owner.to_def_id()))
{
missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
}
}
}
// `impl const Trait for Type` items forward their const stability to their
// immediate children.
if const_stab.is_none() {
@ -367,6 +387,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
let orig_in_trait_impl = self.in_trait_impl;
let mut kind = AnnotationKind::Required;
let mut const_stab_inherit = InheritConstStability::No;
let mut fn_sig = None;
match i.kind {
// Inherent impls and foreign modules serve only as containers for other items,
// they don't have their own stability. They still can be annotated as unstable
@ -387,6 +409,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
ctor_hir_id,
i.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -395,12 +418,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
)
}
}
hir::ItemKind::Fn(ref item_fn_sig, _, _) => {
fn_sig = Some(item_fn_sig);
}
_ => {}
}
self.annotate(
i.hir_id(),
i.span,
fn_sig,
kind,
InheritDeprecation::Yes,
const_stab_inherit,
@ -411,9 +438,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
let fn_sig = match ti.kind {
hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
_ => None,
};
self.annotate(
ti.hir_id(),
ti.span,
fn_sig,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -427,9 +460,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
let kind =
if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
let fn_sig = match ii.kind {
hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
_ => None,
};
self.annotate(
ii.hir_id(),
ii.span,
fn_sig,
kind,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -444,6 +484,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
var.id,
var.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -453,6 +494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
v.annotate(
ctor_hir_id,
var.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -470,6 +512,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
s.hir_id,
s.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -484,6 +527,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
i.hir_id(),
i.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -498,6 +542,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
md.hir_id(),
md.span,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -517,6 +562,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
self.annotate(
p.hir_id,
p.span,
None,
kind,
InheritDeprecation::No,
InheritConstStability::No,
@ -687,6 +733,7 @@ fn stability_index(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> {
annotator.annotate(
hir::CRATE_HIR_ID,
krate.item.inner,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -969,3 +1016,15 @@ fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
.emit();
}
fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
and `#[rustc_const_stable]` require \
the function or method to be `const`";
session
.struct_span_err(fn_sig_span, ERROR_MSG)
.span_help(fn_sig_span, "make the function or method const")
.span_label(const_span, "attribute specified here")
.emit();
}