Skip to content

Commit 8608ba7

Browse files
committed
add c-variadic const eval test
1 parent 7b44318 commit 8608ba7

File tree

8 files changed

+437
-4
lines changed

8 files changed

+437
-4
lines changed

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_abi::{self as abi, HasDataLayout};
44
use rustc_codegen_ssa::traits::{
55
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
66
};
7+
use rustc_middle::bug;
78
use rustc_middle::mir::Mutability;
89
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
910
use rustc_middle::ty::layout::LayoutOf;

compiler/rustc_const_eval/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ const_eval_unwind_past_top =
434434
435435
## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
436436
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
437+
const_eval_va_arg_out_of_bounds = more C-variadic arguments read than were passed
438+
437439
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
438440
439441
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -620,14 +620,21 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
620620
err_unsup_format!("va_arg on unknown va_list allocation {:?}", alloc_id)
621621
})?;
622622

623-
let src_mplace = arguments
624-
.get(index)
625-
.ok_or_else(|| err_unsup_format!("va_arg out of bounds (index={index})"))?
626-
.clone();
623+
let Some(src_mplace) = arguments.get(index).cloned() else {
624+
throw_ub!(VaArgOutOfBounds)
625+
};
627626

628627
// NOTE: In C some type conversions are allowed (e.g. casting between signed and
629628
// unsigned integers). For now we require c-variadic arguments to be read with the
630629
// exact type they were passed as.
630+
if src_mplace.layout.ty != dest.layout.ty {
631+
throw_unsup_format!(
632+
"va_arg type mismatch: requested `{}`, but next argument is `{}`",
633+
dest.layout.ty,
634+
src_mplace.layout.ty
635+
);
636+
}
637+
631638
ecx.copy_op(&src_mplace, dest)?;
632639
}
633640

compiler/rustc_const_eval/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
510510
InvalidNichedEnumVariantWritten { .. } => {
511511
const_eval_invalid_niched_enum_variant_written
512512
}
513+
VaArgOutOfBounds => const_eval_va_arg_out_of_bounds,
513514
AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
514515
AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
515516
}
@@ -536,6 +537,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
536537
| InvalidMeta(InvalidMetaKind::TooBig)
537538
| InvalidUninitBytes(None)
538539
| DeadLocal
540+
| VaArgOutOfBounds
539541
| UninhabitedEnumVariantWritten(_)
540542
| UninhabitedEnumVariantRead(_) => {}
541543

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
436436
},
437437
/// ABI-incompatible return types.
438438
AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
439+
/// `va_arg` was called on an exhausted `VaList`.
440+
VaArgOutOfBounds,
439441
}
440442

441443
#[derive(Debug, Clone, Copy)]
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//@ build-fail
2+
3+
#![feature(c_variadic)]
4+
#![feature(const_destruct)]
5+
#![feature(c_variadic_const)]
6+
7+
const unsafe extern "C" fn read_n<const N: usize>(mut ap: ...) {
8+
let mut i = N;
9+
while i > 0 {
10+
i -= 1;
11+
let _ = ap.arg::<i32>();
12+
}
13+
}
14+
15+
unsafe fn read_too_many() {
16+
// None passed, none read.
17+
const { read_n::<0>() }
18+
19+
// One passed, none read. Ignoring arguments is fine.
20+
const { read_n::<0>(1) }
21+
22+
// None passed, one read.
23+
const { read_n::<1>() }
24+
//~^ ERROR more C-variadic arguments read than were passed
25+
26+
// One passed, two read.
27+
const { read_n::<2>(1) }
28+
//~^ ERROR more C-variadic arguments read than were passed
29+
}
30+
31+
const unsafe extern "C" fn read_as<T: core::ffi::VaArgSafe>(mut ap: ...) -> T {
32+
ap.arg::<T>()
33+
}
34+
35+
unsafe fn read_cast() {
36+
const { read_as::<i32>(1i32) };
37+
const { read_as::<u32>(1u32) };
38+
39+
const { read_as::<i32>(1i32, 2u64, 3.0f64) };
40+
const { read_as::<u32>(1u32, 2u64, 3.0f64) };
41+
42+
const { read_as::<i64>(1i64) };
43+
const { read_as::<u64>(1u64) };
44+
45+
const { read_as::<u32>(1i32) };
46+
//~^ ERROR va_arg type mismatch: requested `u32`, but next argument is `i32`
47+
48+
const { read_as::<i32>(1u32) };
49+
//~^ ERROR va_arg type mismatch: requested `i32`, but next argument is `u32`
50+
51+
const { read_as::<i32>(1u64) };
52+
//~^ ERROR va_arg type mismatch: requested `i32`, but next argument is `u64`
53+
54+
const { read_as::<f64>(1i32) };
55+
//~^ ERROR va_arg type mismatch: requested `f64`, but next argument is `i32`
56+
57+
const { read_as::<*const u8>(1i32) };
58+
//~^ ERROR va_arg type mismatch: requested `*const u8`, but next argument is `i32`
59+
}
60+
61+
fn main() {
62+
unsafe {
63+
read_too_many();
64+
read_cast();
65+
}
66+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
error[E0080]: more C-variadic arguments read than were passed
2+
--> $DIR/c-variadic-fail.rs:23:13
3+
|
4+
LL | const { read_n::<1>() }
5+
| ^^^^^^^^^^^^^ evaluation of `read_too_many::{constant#2}` failed inside this call
6+
|
7+
note: inside `read_n::<1>`
8+
--> $DIR/c-variadic-fail.rs:11:17
9+
|
10+
LL | let _ = ap.arg::<i32>();
11+
| ^^^^^^^^^^^^^^^
12+
note: inside `VaList::<'_>::arg::<i32>`
13+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
14+
15+
note: erroneous constant encountered
16+
--> $DIR/c-variadic-fail.rs:23:5
17+
|
18+
LL | const { read_n::<1>() }
19+
| ^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
note: erroneous constant encountered
22+
--> $DIR/c-variadic-fail.rs:23:5
23+
|
24+
LL | const { read_n::<1>() }
25+
| ^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
28+
29+
error[E0080]: more C-variadic arguments read than were passed
30+
--> $DIR/c-variadic-fail.rs:27:13
31+
|
32+
LL | const { read_n::<2>(1) }
33+
| ^^^^^^^^^^^^^^ evaluation of `read_too_many::{constant#3}` failed inside this call
34+
|
35+
note: inside `read_n::<2>`
36+
--> $DIR/c-variadic-fail.rs:11:17
37+
|
38+
LL | let _ = ap.arg::<i32>();
39+
| ^^^^^^^^^^^^^^^
40+
note: inside `VaList::<'_>::arg::<i32>`
41+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
42+
43+
note: erroneous constant encountered
44+
--> $DIR/c-variadic-fail.rs:27:5
45+
|
46+
LL | const { read_n::<2>(1) }
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
note: erroneous constant encountered
50+
--> $DIR/c-variadic-fail.rs:27:5
51+
|
52+
LL | const { read_n::<2>(1) }
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^
54+
|
55+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
56+
57+
error[E0080]: va_arg type mismatch: requested `u32`, but next argument is `i32`
58+
--> $DIR/c-variadic-fail.rs:45:13
59+
|
60+
LL | const { read_as::<u32>(1i32) };
61+
| ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#6}` failed inside this call
62+
|
63+
note: inside `read_as::<u32>`
64+
--> $DIR/c-variadic-fail.rs:32:5
65+
|
66+
LL | ap.arg::<T>()
67+
| ^^^^^^^^^^^^^
68+
note: inside `VaList::<'_>::arg::<u32>`
69+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
70+
71+
note: erroneous constant encountered
72+
--> $DIR/c-variadic-fail.rs:45:5
73+
|
74+
LL | const { read_as::<u32>(1i32) };
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76+
77+
note: erroneous constant encountered
78+
--> $DIR/c-variadic-fail.rs:45:5
79+
|
80+
LL | const { read_as::<u32>(1i32) };
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82+
|
83+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
84+
85+
error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u32`
86+
--> $DIR/c-variadic-fail.rs:48:13
87+
|
88+
LL | const { read_as::<i32>(1u32) };
89+
| ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#7}` failed inside this call
90+
|
91+
note: inside `read_as::<i32>`
92+
--> $DIR/c-variadic-fail.rs:32:5
93+
|
94+
LL | ap.arg::<T>()
95+
| ^^^^^^^^^^^^^
96+
note: inside `VaList::<'_>::arg::<i32>`
97+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
98+
99+
note: erroneous constant encountered
100+
--> $DIR/c-variadic-fail.rs:48:5
101+
|
102+
LL | const { read_as::<i32>(1u32) };
103+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
104+
105+
note: erroneous constant encountered
106+
--> $DIR/c-variadic-fail.rs:48:5
107+
|
108+
LL | const { read_as::<i32>(1u32) };
109+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
110+
|
111+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
112+
113+
error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u64`
114+
--> $DIR/c-variadic-fail.rs:51:13
115+
|
116+
LL | const { read_as::<i32>(1u64) };
117+
| ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#8}` failed inside this call
118+
|
119+
note: inside `read_as::<i32>`
120+
--> $DIR/c-variadic-fail.rs:32:5
121+
|
122+
LL | ap.arg::<T>()
123+
| ^^^^^^^^^^^^^
124+
note: inside `VaList::<'_>::arg::<i32>`
125+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
126+
127+
note: erroneous constant encountered
128+
--> $DIR/c-variadic-fail.rs:51:5
129+
|
130+
LL | const { read_as::<i32>(1u64) };
131+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+
133+
note: erroneous constant encountered
134+
--> $DIR/c-variadic-fail.rs:51:5
135+
|
136+
LL | const { read_as::<i32>(1u64) };
137+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138+
|
139+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
140+
141+
error[E0080]: va_arg type mismatch: requested `f64`, but next argument is `i32`
142+
--> $DIR/c-variadic-fail.rs:54:13
143+
|
144+
LL | const { read_as::<f64>(1i32) };
145+
| ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#9}` failed inside this call
146+
|
147+
note: inside `read_as::<f64>`
148+
--> $DIR/c-variadic-fail.rs:32:5
149+
|
150+
LL | ap.arg::<T>()
151+
| ^^^^^^^^^^^^^
152+
note: inside `VaList::<'_>::arg::<f64>`
153+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
154+
155+
note: erroneous constant encountered
156+
--> $DIR/c-variadic-fail.rs:54:5
157+
|
158+
LL | const { read_as::<f64>(1i32) };
159+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160+
161+
note: erroneous constant encountered
162+
--> $DIR/c-variadic-fail.rs:54:5
163+
|
164+
LL | const { read_as::<f64>(1i32) };
165+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
166+
|
167+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
168+
169+
error[E0080]: va_arg type mismatch: requested `*const u8`, but next argument is `i32`
170+
--> $DIR/c-variadic-fail.rs:57:13
171+
|
172+
LL | const { read_as::<*const u8>(1i32) };
173+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#10}` failed inside this call
174+
|
175+
note: inside `read_as::<*const u8>`
176+
--> $DIR/c-variadic-fail.rs:32:5
177+
|
178+
LL | ap.arg::<T>()
179+
| ^^^^^^^^^^^^^
180+
note: inside `VaList::<'_>::arg::<*const u8>`
181+
--> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
182+
183+
note: erroneous constant encountered
184+
--> $DIR/c-variadic-fail.rs:57:5
185+
|
186+
LL | const { read_as::<*const u8>(1i32) };
187+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
188+
189+
note: erroneous constant encountered
190+
--> $DIR/c-variadic-fail.rs:57:5
191+
|
192+
LL | const { read_as::<*const u8>(1i32) };
193+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
194+
|
195+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
196+
197+
error: aborting due to 7 previous errors
198+
199+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)