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
6 changes: 4 additions & 2 deletions compiler/rustc_ast_lowering/src/expr/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&closure.body,
closure.fn_decl_span,
closure.fn_arg_span,
attrs,
),
span: self.lower_span(e.span),
},
Expand Down Expand Up @@ -240,7 +241,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)),
kind: closure_kind,
constness: self.lower_constness(constness),
constness: self.lower_constness(attrs, constness),
explicit_captures,
});

Expand Down Expand Up @@ -308,6 +309,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: &Expr,
fn_decl_span: Span,
fn_arg_span: Span,
attrs: &[hir::Attribute],
) -> hir::ExprKind<'hir> {
let closure_def_id = self.local_def_id(closure_id);
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
Expand Down Expand Up @@ -369,7 +371,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// knows that a `FnDecl` output type like `-> &str` actually means
// "coroutine that returns &str", rather than directly returning a `&str`.
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
constness: self.lower_constness(constness),
constness: self.lower_constness(attrs, constness),
explicit_captures: &[],
});
hir::ExprKind::Closure(c)
Expand Down
45 changes: 25 additions & 20 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.arena
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));

let constness = self.lower_constness(*constness);
let constness = self.lower_constness(attrs, *constness);

hir::ItemKind::Impl(hir::Impl {
generics,
Expand All @@ -499,7 +499,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounds,
items,
}) => {
let constness = self.lower_constness(*constness);
let constness = self.lower_constness(attrs, *constness);
let impl_restriction = self.lower_impl_restriction(impl_restriction);
let ident = self.lower_ident(*ident);
let (generics, (safety, items, bounds)) = self.lower_generics(
Expand Down Expand Up @@ -530,7 +530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
ItemKind::TraitAlias(TraitAlias { constness, ident, generics, bounds }) => {
let constness = self.lower_constness(*constness);
let constness = self.lower_constness(attrs, *constness);
let ident = self.lower_ident(*ident);
let (generics, bounds) = self.lower_generics(
generics,
Expand Down Expand Up @@ -1702,21 +1702,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
safety.into()
};

let mut constness = self.lower_constness(h.constness);
if let Some(&attr_span) = find_attr!(attrs, RustcComptime(span) => span) {
match std::mem::replace(&mut constness, rustc_hir::Constness::Const { always: true }) {
rustc_hir::Constness::Const { always: true } => {
unreachable!("lower_constness cannot produce comptime")
}
// A function can't be `const` and `comptime` at the same time
rustc_hir::Constness::Const { always: false } => {
let Const::Yes(span) = h.constness else { unreachable!() };
self.dcx().emit_err(ConstComptimeFn { span, attr_span });
}
// Good
rustc_hir::Constness::NotConst => {}
}
}
let constness = self.lower_constness(attrs, h.constness);

hir::FnHeader { safety, asyncness, constness, abi: self.lower_extern(h.ext) }
}
Expand Down Expand Up @@ -1778,11 +1764,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
}

pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
match c {
/// Lowers constness or comptime attribute.
/// Whether `const` is allowed here is checked by ast validation.
/// Whether `comptime` is allowed here is checked by the `comptime` attribute parser.
pub(super) fn lower_constness(&mut self, attrs: &[hir::Attribute], c: Const) -> hir::Constness {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to clarify in a comment here that ComptimeParser under compiler/rustc_attr_parsing/src/attributes/semantics.rs actually controls where a Comptime constness is actually allowed.

let mut constness = match c {
Const::Yes(_) => hir::Constness::Const { always: false },
Const::No => hir::Constness::NotConst,
};

if let Some(&attr_span) = find_attr!(attrs, RustcComptime(span) => span) {
match std::mem::replace(&mut constness, hir::Constness::Const { always: true }) {
hir::Constness::Const { always: true } => {
unreachable!("lower_constness cannot produce comptime")
}
// A function can't be `const` and `comptime` at the same time
hir::Constness::Const { always: false } => {
let Const::Yes(span) = c else { unreachable!() };
self.dcx().emit_err(ConstComptimeFn { span, attr_span });
}
// Good
hir::Constness::NotConst => {}
}
}
constness
}

pub(super) fn lower_safety(&self, s: Safety, default: hir::Safety) -> hir::Safety {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl NoArgsAttributeParser for ComptimeParser {
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Fn),
Allow(Target::Impl { of_trait: false }),
]);
const STABILITY: AttributeStability = unstable!(rustc_attrs);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcComptime;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,8 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>(
match tcx.impl_trait_header(impl_.impl_def_id).constness {
rustc_hir::Constness::Const { always } => {
if always {
unimplemented!()
// FIXME(comptime): just bailing for now to avoid an ICE in a test.
return Err(EvaluationFailure::NoSolution);
}
}
rustc_hir::Constness::NotConst => {
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/comptime/comptime_closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(rustc_attrs, stmt_expr_attributes)]

const _: () = {
let f = #[rustc_comptime]
//~^ ERROR: `#[rustc_comptime]` attribute cannot be used on closures
|| ();

// FIXME(comptime): closures should work, too.
f();
//~^ ERROR: cannot call non-const closure in constants
};

fn main() {}
20 changes: 20 additions & 0 deletions tests/ui/comptime/comptime_closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: `#[rustc_comptime]` attribute cannot be used on closures
--> $DIR/comptime_closure.rs:4:13
|
LL | let f = #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions, inherent impl blocks, and inherent methods

error[E0015]: cannot call non-const closure in constants
--> $DIR/comptime_closure.rs:9:5
|
LL | f();
| ^^^
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
35 changes: 35 additions & 0 deletions tests/ui/comptime/comptime_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#![feature(rustc_attrs, const_trait_impl)]

const trait Foo {
fn foo(&self);

fn bar(&self) {}
}

struct Bar;

#[rustc_comptime]
impl Bar {
fn boo(&self) {}
}

#[rustc_comptime]
//~^ ERROR: cannot be used on trait impl
impl Foo for Bar {
fn foo(&self) {
comptime_fn();
}
}

#[rustc_comptime]
fn comptime_fn() {}

const _: () = {
Bar.boo();
Bar.foo();
//~^ ERROR: `Bar: const Foo` is not satisfied
Bar.bar();
//~^ ERROR: `Bar: const Foo` is not satisfied
};

fn main() {}
33 changes: 33 additions & 0 deletions tests/ui/comptime/comptime_impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error: `#[rustc_comptime]` attribute cannot be used on trait impl blocks
--> $DIR/comptime_impl.rs:16:1
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent impl blocks

error[E0277]: the trait bound `Bar: const Foo` is not satisfied
--> $DIR/comptime_impl.rs:29:9
|
LL | Bar.foo();
| ^^^
|
help: make the `impl` of trait `Foo` `const`
|
LL | impl const Foo for Bar {
| +++++

error[E0277]: the trait bound `Bar: const Foo` is not satisfied
--> $DIR/comptime_impl.rs:31:9
|
LL | Bar.bar();
| ^^^
|
help: make the `impl` of trait `Foo` `const`
|
LL | impl const Foo for Bar {
| +++++

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
17 changes: 17 additions & 0 deletions tests/ui/comptime/comptime_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(rustc_attrs)]

struct Bar;

#[rustc_comptime]
impl Bar {
fn boo(&self) {}
}

const _: () = {
Bar.boo();
};

fn main() {
Bar.boo();
//~^ ERROR: comptime fns can only be called at compile time
}
8 changes: 8 additions & 0 deletions tests/ui/comptime/comptime_method.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: comptime fns can only be called at compile time
--> $DIR/comptime_method.rs:15:5
|
LL | Bar.boo();
| ^^^^^^^^^

error: aborting due to 1 previous error

24 changes: 24 additions & 0 deletions tests/ui/comptime/comptime_method_bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@check-pass

#![feature(rustc_attrs, const_trait_impl)]

struct Bar<T>(T);

const trait Trait {
fn method(&self) {}
}

#[rustc_comptime]
impl<T: const Trait> Bar<T> {
fn boo(&self) {
self.0.method()
}
}

const impl Trait for () {}

const _: () = {
Bar(()).boo();
};

fn main() {}
32 changes: 32 additions & 0 deletions tests/ui/comptime/comptime_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![feature(rustc_attrs, const_trait_impl, trait_alias)]

#[rustc_comptime]
//~^ ERROR: `#[rustc_comptime]` attribute cannot be used on traits
trait Trait {
fn method(&self) {}
}

const impl Trait for () {}

#[rustc_comptime]
//~^ ERROR: `#[rustc_comptime]` attribute cannot be used on trait impl
impl Trait for u32 {
fn method(&self) {
comptime_fn();
}
}

#[rustc_comptime]
fn comptime_fn() {}

#[rustc_comptime]
//~^ ERROR: `#[rustc_comptime]` attribute cannot be used on trait aliases
trait TraitAlias = const Trait;

#[rustc_comptime]
fn func<T: const TraitAlias>(t: &T) {
t.method()
//~^ ERROR: cannot call non-const method `<T as Trait>::method` in constants
}

fn main() {}
35 changes: 35 additions & 0 deletions tests/ui/comptime/comptime_trait.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error: `#[rustc_comptime]` attribute cannot be used on traits
--> $DIR/comptime_trait.rs:3:1
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent impl blocks

error: `#[rustc_comptime]` attribute cannot be used on trait impl blocks
--> $DIR/comptime_trait.rs:11:1
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent impl blocks

error: `#[rustc_comptime]` attribute cannot be used on trait aliases
--> $DIR/comptime_trait.rs:22:1
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent impl blocks

error[E0015]: cannot call non-const method `<T as Trait>::method` in constants
--> $DIR/comptime_trait.rs:28:7
|
LL | t.method()
| ^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0015`.
6 changes: 3 additions & 3 deletions tests/ui/comptime/trait_comptime.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ error: `#[rustc_comptime]` attribute cannot be used on required trait methods
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can only be applied to functions with a body
= help: `#[rustc_comptime]` can be applied to functions with a body and inherent impl blocks

error: `#[rustc_comptime]` attribute cannot be used on provided trait methods
--> $DIR/trait_comptime.rs:8:5
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent methods
= help: `#[rustc_comptime]` can be applied to functions, inherent impl blocks, and inherent methods

error: `#[rustc_comptime]` attribute cannot be used on trait methods in impl blocks
--> $DIR/trait_comptime.rs:21:5
|
LL | #[rustc_comptime]
| ^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_comptime]` can be applied to functions and inherent methods
= help: `#[rustc_comptime]` can be applied to functions, inherent impl blocks, and inherent methods

error: aborting due to 3 previous errors

Loading