mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
We can't use a `CallExpr` to call a constructor; use a `CXXConstructExpr` instead. While this fixes the crash and gets us past the initial constant evaluation, we still can't map the constant value back into Carbon, so this doesn't actually make constexpr constructors work yet. But it does stop Clang from crashing. Fixes #7498.
275 lines
15 KiB
Plaintext
275 lines
15 KiB
Plaintext
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/full.carbon
|
|
// EXTRA-ARGS: --clang-arg=--std=c++20
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/function/import/constexpr.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/import/constexpr.carbon
|
|
|
|
// --- basic.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp inline '''
|
|
constexpr int f(int a, int b) { return a + b; }
|
|
''';
|
|
|
|
let a: array(i32, Cpp.f(1, 2)) = (1, 2, 3);
|
|
|
|
// --- bool_param.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp inline '''
|
|
constexpr int f(bool b) {
|
|
return b ? 3 : 0;
|
|
}
|
|
''';
|
|
|
|
let a: array(i32, Cpp.f(true)) = (1, 2, 3);
|
|
|
|
// --- float_param.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp inline '''
|
|
constexpr int f(float b) {
|
|
return static_cast<int>(b);
|
|
}
|
|
''';
|
|
|
|
let a: array(i32, Cpp.f(3.0)) = (1, 2, 3);
|
|
|
|
// --- return_bool.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp inline '''
|
|
constexpr bool f() {
|
|
return true;
|
|
}
|
|
''';
|
|
|
|
musteval fn F(b: bool) -> i32 {
|
|
return if b then 3 else 0;
|
|
}
|
|
|
|
let a: array(i32, F(Cpp.f())) = (1, 2, 3);
|
|
|
|
// --- fail_invalid_constant_eval.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp inline '''
|
|
constexpr int arr[1] = {0};
|
|
constexpr int f(int a) {
|
|
return arr[a];
|
|
}
|
|
''';
|
|
|
|
// CHECK:STDERR: fail_invalid_constant_eval.carbon:[[@LINE+4]]:19: error: array bound is not a constant [InvalidArrayExpr]
|
|
// CHECK:STDERR: let a: array(i32, Cpp.f(5)) = (1, 2, 3);
|
|
// CHECK:STDERR: ^~~~~~~~
|
|
// CHECK:STDERR:
|
|
let a: array(i32, Cpp.f(5)) = (1, 2, 3);
|
|
|
|
// --- nonconstant_constexpr_call.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp;
|
|
|
|
var a: i32 = 0;
|
|
|
|
inline Cpp '''
|
|
constexpr int f(const int &r) { return r; }
|
|
''';
|
|
|
|
// OK, runtime call.
|
|
var b: i32 = Cpp.f(a);
|
|
|
|
// --- fail_nonconstant_consteval_call.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp;
|
|
|
|
var a: i32 = 0;
|
|
|
|
// TODO: This is failing when building the thunk, not when calling it.
|
|
inline Cpp '''
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE+9]]:15: error: call to consteval function 'f' is not a constant expression [CppInteropParseError]
|
|
// CHECK:STDERR: 19 | consteval int f(const int &r) { return r; }
|
|
// CHECK:STDERR: | ^
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE+6]]:15: note: function parameter 'r' with unknown value cannot be used in a constant expression [CppInteropParseNote]
|
|
// CHECK:STDERR: 19 | consteval int f(const int &r) { return r; }
|
|
// CHECK:STDERR: | ^
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE+3]]:15: note: declared here [CppInteropParseNote]
|
|
// CHECK:STDERR: 19 | consteval int f(const int &r) { return r; }
|
|
// CHECK:STDERR: | ^
|
|
consteval int f(const int &r) { return r; }
|
|
''';
|
|
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE+11]]:14: note: in thunk for C++ function used here [InCppThunk]
|
|
// CHECK:STDERR: var b: i32 = Cpp.f(a);
|
|
// CHECK:STDERR: ^~~~~~~~
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE+7]]:14: error: non-constant call to compile-time-only function [NonConstantCallToCompTimeOnlyFunction]
|
|
// CHECK:STDERR: var b: i32 = Cpp.f(a);
|
|
// CHECK:STDERR: ^~~~~~~~
|
|
// CHECK:STDERR: fail_nonconstant_consteval_call.carbon:[[@LINE-10]]:15: note: compile-time-only function declared here [CompTimeOnlyFunctionHere]
|
|
// CHECK:STDERR: consteval int f(const int &r) { return r; }
|
|
// CHECK:STDERR: ^
|
|
// CHECK:STDERR:
|
|
var b: i32 = Cpp.f(a);
|
|
|
|
// --- fail_todo_constructor.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp;
|
|
|
|
inline Cpp '''
|
|
struct C {
|
|
constexpr C(int a) : a(a) {}
|
|
int a;
|
|
};
|
|
''';
|
|
|
|
// TODO: This should probably be allowed.
|
|
eval fn F() -> i32 {
|
|
//@dump-sem-ir-begin
|
|
// CHECK:STDERR: fail_todo_constructor.carbon:[[@LINE+3]]:18: error: expression is runtime; expected constant [EvalRequiresConstantValue]
|
|
// CHECK:STDERR: let c: Cpp.C = 3;
|
|
// CHECK:STDERR: ^
|
|
let c: Cpp.C = 3;
|
|
return c.a;
|
|
//@dump-sem-ir-end
|
|
}
|
|
|
|
// CHECK:STDERR: fail_todo_constructor.carbon:[[@LINE+4]]:19: note: in call to F here [InCallToEvalFn]
|
|
// CHECK:STDERR: let a: array(i32, F()) = (1, 2, 3);
|
|
// CHECK:STDERR: ^~~
|
|
// CHECK:STDERR:
|
|
let a: array(i32, F()) = (1, 2, 3);
|
|
|
|
// CHECK:STDOUT: --- fail_todo_constructor.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
|
|
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
|
// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic]
|
|
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
|
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
|
// CHECK:STDOUT: %C.elem: type = unbound_element_type %C, %i32 [concrete]
|
|
// CHECK:STDOUT: %pattern_type.bbc: type = pattern_type %C [concrete]
|
|
// CHECK:STDOUT: %c.patt: %pattern_type.bbc = value_binding_pattern c [concrete]
|
|
// CHECK:STDOUT: %int_3.1ba: Core.IntLiteral = int_value 3 [concrete]
|
|
// CHECK:STDOUT: %ptr.0a2: type = ptr_type %C [concrete]
|
|
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
|
|
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.type.914: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
|
|
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl.0e9(%To) [symbolic]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.845: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74 = struct_value () [symbolic]
|
|
// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness.a23: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.b3c, @Core.IntLiteral.as.ImplicitAs.impl.0e9(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.2ba: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl.0e9(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.2ba = struct_value () [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.facet.9f1: %ImplicitAs.type.914 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.a23) [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.740: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%i32, %ImplicitAs.facet.9f1) [concrete]
|
|
// CHECK:STDOUT: %.1c5: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.740, %ImplicitAs.facet.9f1 [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_3.1ba, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39 [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
|
|
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_3.1ba, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
|
// CHECK:STDOUT: %int_3.410: %i32 = int_value 3 [concrete]
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.ac8: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic]
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.5e0: %Int.as.Copy.impl.Op.type.ac8 = struct_value () [symbolic]
|
|
// CHECK:STDOUT: %Copy.impl_witness.0e0: <witness> = impl_witness imports.%Copy.impl_witness_table.367, @Int.as.Copy.impl(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.3f6: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.4f6: %Int.as.Copy.impl.Op.type.3f6 = struct_value () [concrete]
|
|
// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value %i32, (%Copy.impl_witness.0e0) [concrete]
|
|
// CHECK:STDOUT: %Copy.WithSelf.Op.type.d09: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet) [concrete]
|
|
// CHECK:STDOUT: %.7a6: type = fn_type_with_self_type %Copy.WithSelf.Op.type.d09, %Copy.facet [concrete]
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %Int.as.Copy.impl.Op.4f6, @Int.as.Copy.impl.Op(%int_32) [concrete]
|
|
// CHECK:STDOUT: %C.cpp_destructor.type: type = fn_type @C.cpp_destructor [concrete]
|
|
// CHECK:STDOUT: %C.cpp_destructor: %C.cpp_destructor.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %C.Op.type: type = fn_type @C.Op [concrete]
|
|
// CHECK:STDOUT: %C.Op: %C.Op.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
|
// CHECK:STDOUT: .C = %C.decl
|
|
// CHECK:STDOUT: import Cpp//...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
|
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: } {
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import_ref.edf: @Core.IntLiteral.as.ImplicitAs.impl.0e9.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.0e9.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.845)]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.b3c = impl_witness_table (%Core.import_ref.edf), @Core.IntLiteral.as.ImplicitAs.impl.0e9 [concrete]
|
|
// CHECK:STDOUT: %Core.import_ref.cd6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.ac8) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.5e0)]
|
|
// CHECK:STDOUT: %Copy.impl_witness_table.367 = impl_witness_table (%Core.import_ref.cd6), @Int.as.Copy.impl [concrete]
|
|
// CHECK:STDOUT: %C.cpp_destructor.decl: %C.cpp_destructor.type = fn_decl @C.cpp_destructor [concrete = constants.%C.cpp_destructor] {
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: } {
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: fn @F() -> out %return.param: %i32 {
|
|
// CHECK:STDOUT: !entry:
|
|
// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
|
|
// CHECK:STDOUT: %.loc19_18.1: ref %C = temporary_storage
|
|
// CHECK:STDOUT: %impl.elem0.loc19: %.1c5 = impl_witness_access constants.%ImplicitAs.impl_witness.a23, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e39]
|
|
// CHECK:STDOUT: %bound_method.loc19_18.1: <bound method> = bound_method %int_3, %impl.elem0.loc19 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
|
|
// CHECK:STDOUT: %specific_fn.loc19: <specific function> = specific_function %impl.elem0.loc19, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
|
// CHECK:STDOUT: %bound_method.loc19_18.2: <bound method> = bound_method %int_3, %specific_fn.loc19 [concrete = constants.%bound_method]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc19_18.2(%int_3) [concrete = constants.%int_3.410]
|
|
// CHECK:STDOUT: %.loc19_18.2: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_3.410]
|
|
// CHECK:STDOUT: %.loc19_18.3: %i32 = converted %int_3, %.loc19_18.2 [concrete = constants.%int_3.410]
|
|
// CHECK:STDOUT: %addr: %ptr.0a2 = addr_of %.loc19_18.1
|
|
// CHECK:STDOUT: %C__carbon_thunk.call: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%.loc19_18.3, %addr)
|
|
// CHECK:STDOUT: %.loc19_18.4: init %C to %.loc19_18.1 = mark_in_place_init %C__carbon_thunk.call
|
|
// CHECK:STDOUT: %.loc19_18.5: init %C = converted %int_3, %.loc19_18.4
|
|
// CHECK:STDOUT: %.loc19_18.6: ref %C = temporary %.loc19_18.1, %.loc19_18.5
|
|
// CHECK:STDOUT: %.loc19_18.7: %C = acquire_value %.loc19_18.6
|
|
// CHECK:STDOUT: %.loc19_13: type = splice_block %C.ref [concrete = constants.%C] {
|
|
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
|
// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %c: %C = wrapper_binding c, %.loc19_18.7
|
|
// CHECK:STDOUT: name_binding_decl {
|
|
// CHECK:STDOUT: %c.patt: %pattern_type.bbc = value_binding_pattern c [concrete = constants.%c.patt]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %c.ref: %C = name_ref c, %c
|
|
// CHECK:STDOUT: %a.ref: %C.elem = name_ref a, @C.%.1 [concrete = @C.%.1]
|
|
// CHECK:STDOUT: %.loc20_11.1: ref %i32 = class_element_access %c.ref, element0
|
|
// CHECK:STDOUT: %.loc20_11.2: %i32 = acquire_value %.loc20_11.1
|
|
// CHECK:STDOUT: %impl.elem0.loc20: %.7a6 = impl_witness_access constants.%Copy.impl_witness.0e0, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6]
|
|
// CHECK:STDOUT: %bound_method.loc20_11.1: <bound method> = bound_method %.loc20_11.2, %impl.elem0.loc20
|
|
// CHECK:STDOUT: %specific_fn.loc20: <specific function> = specific_function %impl.elem0.loc20, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
|
|
// CHECK:STDOUT: %bound_method.loc20_11.2: <bound method> = bound_method %.loc20_11.2, %specific_fn.loc20
|
|
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc20_11.2(%.loc20_11.2)
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: %C.Op.bound: <bound method> = bound_method %.loc19_18.6, constants.%C.Op
|
|
// CHECK:STDOUT: %Op.ref: %C.cpp_destructor.type = name_ref Op, imports.%C.cpp_destructor.decl [concrete = constants.%C.cpp_destructor]
|
|
// CHECK:STDOUT: %C.cpp_destructor.bound: <bound method> = bound_method %.loc19_18.6, %Op.ref
|
|
// CHECK:STDOUT: %C.cpp_destructor.call: init %empty_tuple.type = call %C.cpp_destructor.bound(%.loc19_18.6)
|
|
// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: fn @__global_init() {
|
|
// CHECK:STDOUT: !entry:
|
|
// CHECK:STDOUT: <elided>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|