Files
carbon-lang/toolchain/check/testdata/interop/cpp/function/import/overloads.carbon
T
Chandler Carruth d0badecd2a Switch tests to use the rendered form of diagnostics (#8070)
Historically, we disabled the rendered form in tests outside of
`toolchain/diagnostics`. The idea was to keep tests shorter and avoid
very long chains of autoupdate before stabilizing due to all the line
numbers and other artifacts in the rendered form.

This PR adds `--diagnostic-line-numbers=[all|first]` and defaults to
`first` in tests. This keeps the rendered form so that we can easily
code review that form and the visual cues it does or doesn't provide.
But it removes all but the first location's line numbers to provide
significantly more stability in tests.

By default, tests get the full unicode line-drawing form of diagnostics
so we can ensure all of the artifacts there make sense with the specific
case being diagnosed, but we do retain some focused ASCII-rendering
tests to ensure that fallback remains usable.

There are some issues here that will be fixed in subsequent PRs.
Notably, we try to keep the frame together in the check lines, and so
force some parts to use the first location. This largely works, but
fails in some edge cases, causing the entire frame to be located
incorrectly. There is a TODO about this that we need to fix, and it only
occurs 6 times across the test suite, so it didn't seem worth
front-loading a fix for here.

Assisted-by: Claude Code
2026-11-05 07:19:59 +00:00

1005 lines
48 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
//
// 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/overloads.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/import/overloads.carbon
// ============================================================================
// Overloaded sets tests
// ============================================================================
// --- multiple_functions_no_overloads.h
auto no_overloads_foo(short a) -> void;
auto no_overloads_bar(short a) -> void;
// --- import_multiple_functions_no_overloads.carbon
library "[[@TEST_NAME]]";
import Cpp library "multiple_functions_no_overloads.h";
fn F() {
Cpp.no_overloads_bar(1 as i16);
}
// --- overloaded_functions.h
auto overloaded_foo(short a) -> void;
auto overloaded_foo(int a) -> void;
// --- import_overloaded_functions.carbon
library "[[@TEST_NAME]]";
import Cpp library "overloaded_functions.h";
fn F() {
Cpp.overloaded_foo(1 as i32);
}
// --- both_overloaded_functions_called.h
auto both_called_foo(short a) -> void;
auto both_called_foo(int a) -> void;
// --- import_both_overloaded_functions_called.carbon
library "[[@TEST_NAME]]";
import Cpp library "both_overloaded_functions_called.h";
fn F() {
Cpp.both_called_foo(1 as i32);
Cpp.both_called_foo(1 as i16);
}
// --- multiple_overloaded_sets.h
auto multi_set_foo(short a) -> void;
auto multi_set_foo(int a) -> void;
auto multi_set_bar(long a) -> void;
auto multi_set_bar(int a) -> void;
// --- import_multiple_overloaded_sets.carbon
library "[[@TEST_NAME]]";
import Cpp library "multiple_overloaded_sets.h";
fn F() {
Cpp.multi_set_foo(1 as i32);
Cpp.multi_set_bar(1 as i32);
}
// ============================================================================
// Call args tests
// ============================================================================
// --- int_literal.h
auto int_literal_foo(int a) -> int;
auto int_literal_foo(unsigned int a) -> unsigned int;
auto int_literal_foo(long a) -> long;
auto int_literal_foo(unsigned long a) -> unsigned long;
auto int_literal_foo(long long a) -> long long;
auto int_literal_foo(unsigned long long a) -> unsigned long long;
auto int_literal_foo(__int128 a) -> __int128;
auto int_literal_foo(unsigned __int128 a) -> unsigned __int128;
// --- import_int_literal.carbon
library "[[@TEST_NAME]]";
import Cpp library "int_literal.h";
fn F() {
// i32_max
let unused a: i32 = Cpp.int_literal_foo(2147483647);
// i32_max + 1
// It could fit to unsigned int, but only signed integers are considered, so assigned to long.
// Decimal, hexadecimal and binary integer literals are treated the same when assigning a C++ type.
let unused b: i64 = Cpp.int_literal_foo(2147483648);
let unused b_hexa: i64 = Cpp.int_literal_foo(0x8000_0000);
let unused b_binary: i64 = Cpp.int_literal_foo(0b1000_0000_0000_0000_0000_0000_0000_0000);
// i64_max
let unused c: i64 = Cpp.int_literal_foo(9223372036854775807);
// i64_max + 1
// Could fit to unsigned long, but only signed integers are considered, so fitted to _int128.
let unused d: i128 = Cpp.int_literal_foo(9223372036854775808);
// u64_max
let unused e: i128 = Cpp.int_literal_foo(18446744073709551615);
// u64_max + 1
let unused f: i128 = Cpp.int_literal_foo(18446744073709551616);
// i128_max
let unused g: i128 = Cpp.int_literal_foo(170141183460469231731687303715884105727);
}
// --- fail_import_large_int_literal.carbon
library "[[@TEST_NAME]]";
import Cpp library "int_literal.h";
fn F() {
// TODO: get rid of the second error message here.
// i128_max + 1
// CHECK:STDERR: ╭─┤ fail_import_large_int_literal.carbon:[[@LINE+18]]:44
// CHECK:STDERR: -> │ ...ed h: i128 = Cpp.int_literal_foo(170141183460469231731687303715884105728);
// CHECK:STDERR: · ━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
// CHECK:STDERR: · ┃ error: integer value 170141183460469231731687303715884105728 too large to fit
// CHECK:STDERR: · ┃ in a signed C++ integer type; requires 129 bits, but max is 128
// CHECK:STDERR: · ┃ [IntTooLargeForCppType]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
// CHECK:STDERR: ╭─┤ fail_import_large_int_literal.carbon:[[@LINE+9]]:44
// CHECK:STDERR: -> │ ...ed h: i128 = Cpp.int_literal_foo(170141183460469231731687303715884105728);
// CHECK:STDERR: · ┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: call argument of type
// CHECK:STDERR: · ┃ `Core.IntLiteral` is not
// CHECK:STDERR: · ┃ supported
// CHECK:STDERR: · ┃ [CppCallArgTypeNotSupported]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
let unused h: i128 = Cpp.int_literal_foo(170141183460469231731687303715884105728);
}
// --- negative_int_literal.h
auto neg_literal_foo(long a) -> void;
auto neg_literal_foo(int a) -> void;
// --- import_negative_int_literal.carbon
library "[[@TEST_NAME]]";
import Cpp library "negative_int_literal.h";
fn F() {
// selects `auto neg_literal_foo(int a) -> void;`
Cpp.neg_literal_foo(-1);
}
// --- negative_literal_passed_to_unsigned.h
auto neg_to_unsigned_foo(unsigned int a) -> void;
// --- fail_import_negative_literal_passed_to_unsigned.carbon
library "[[@TEST_NAME]]";
import Cpp library "negative_literal_passed_to_unsigned.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_negative_literal_passed_to_unsigned.carbon:[[@LINE+14]]:27
// CHECK:STDERR: -> │ Cpp.neg_to_unsigned_foo(-1);
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: negative integer value -1 converted to
// CHECK:STDERR: · ┃ unsigned type `u32`
// CHECK:STDERR: · ┃ [NegativeIntInUnsignedType]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./negative_literal_passed_to_unsigned.h
// CHECK:STDERR: │ auto neg_to_unsigned_foo(unsigned int a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.neg_to_unsigned_foo(-1);
}
// --- floating_point_literal.h
auto float_literal_foo(float a) -> float;
auto float_literal_foo(double a) -> double;
// --- import_floating_point_literal.carbon
library "[[@TEST_NAME]]";
import Cpp library "floating_point_literal.h";
fn F() {
let unused d: f64 = Cpp.float_literal_foo(1.0);
}
// --- fail_import_large_floating_point_literal.carbon
library "[[@TEST_NAME]]";
import Cpp library "floating_point_literal.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_large_floating_point_literal.carbon:[[@LINE+14]]:25
// CHECK:STDERR: -> │ Cpp.float_literal_foo(1.8e+308);
// CHECK:STDERR: · ┳━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: value 18*10^307 too large for floating-point
// CHECK:STDERR: · ┃ type `f64`
// CHECK:STDERR: · ┃ [FloatLiteralTooLargeForType]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./floating_point_literal.h
// CHECK:STDERR: │ auto float_literal_foo(double a) -> double;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.float_literal_foo(1.8e+308);
}
// --- struct_init.h
struct NoFields {};
auto PassNoFields(NoFields s) -> void;
struct ThreeFields {
int a, b, c;
};
auto PassThreeFields(ThreeFields t) -> void;
// --- struct_init.carbon
library "[[@TEST_NAME]]";
import Cpp library "struct_init.h";
fn MakeEmpty() -> {};
fn Empty(value: {}, ref reference: {}) {
Cpp.PassNoFields({});
Cpp.PassNoFields(value);
Cpp.PassNoFields(reference);
Cpp.PassNoFields(MakeEmpty());
}
// --- fail_todo_struct_init_nonempty.carbon
library "[[@TEST_NAME]]";
import Cpp library "struct_init.h";
fn MakeThreeFields() -> {.a: i32, .b: i32, .c: i32};
fn ThreeFields(value: {.a: i32, .b: i32, .c: i32}, ref reference: {.a: i32, .b: i32, .c: i32}) {
// CHECK:STDERR: ╭─┤ fail_todo_struct_init_nonempty.carbon:[[@LINE+20]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields({.a = 1, .b = 2, .c = 3});
// CHECK:STDERR: · ━━━━━━━━━━━━┳━━━━━━━━━━━
// CHECK:STDERR: · ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
// CHECK:STDERR: · ┃ error: cannot implicitly convert expression of type
// CHECK:STDERR: · ┃ `{.a: Core.IntLiteral, .b: Core.IntLiteral, .c: Core.IntLiteral}` to
// CHECK:STDERR: · ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · ┃ [ConversionFailure]
// CHECK:STDERR: · ╭─────────────────────────────────╯
// CHECK:STDERR: · │ type `{.a: Core.IntLiteral, .b: Core.IntLiteral, .c: Core.IntLiteral}` does
// CHECK:STDERR: · │ not implement interface `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields({.a = 1, .b = 2, .c = 3});
// CHECK:STDERR: ╭─┤ fail_todo_struct_init_nonempty.carbon:[[@LINE+19]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(value);
// CHECK:STDERR: · ┳━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `{.a: i32, .b: i32, .c: i32}` to
// CHECK:STDERR: · │ ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `{.a: i32, .b: i32, .c: i32}` does not
// CHECK:STDERR: · │ implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(value);
// CHECK:STDERR: ╭─┤ fail_todo_struct_init_nonempty.carbon:[[@LINE+19]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(reference);
// CHECK:STDERR: · ┳━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `{.a: i32, .b: i32, .c: i32}` to
// CHECK:STDERR: · │ ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `{.a: i32, .b: i32, .c: i32}` does not
// CHECK:STDERR: · │ implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(reference);
// CHECK:STDERR: ╭─┤ fail_todo_struct_init_nonempty.carbon:[[@LINE+19]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(MakeThreeFields());
// CHECK:STDERR: · ┳━━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `{.a: i32, .b: i32, .c: i32}` to
// CHECK:STDERR: · │ ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `{.a: i32, .b: i32, .c: i32}` does not
// CHECK:STDERR: · │ implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(MakeThreeFields());
// CHECK:STDERR: ╭─┤ fail_todo_struct_init_nonempty.carbon:[[@LINE+20]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields({.b = 1, .c = 2, .a = 3});
// CHECK:STDERR: · ━━━━━━━━━━━━┳━━━━━━━━━━━
// CHECK:STDERR: · ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
// CHECK:STDERR: · ┃ error: cannot implicitly convert expression of type
// CHECK:STDERR: · ┃ `{.b: Core.IntLiteral, .c: Core.IntLiteral, .a: Core.IntLiteral}` to
// CHECK:STDERR: · ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · ┃ [ConversionFailure]
// CHECK:STDERR: · ╭─────────────────────────────────╯
// CHECK:STDERR: · │ type `{.b: Core.IntLiteral, .c: Core.IntLiteral, .a: Core.IntLiteral}` does
// CHECK:STDERR: · │ not implement interface `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields({.b = 1, .c = 2, .a = 3});
}
// --- fail_struct_init_field_mismatch.carbon
library "[[@TEST_NAME]]";
import Cpp library "struct_init.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_struct_init_field_mismatch.carbon:[[@LINE+15]]:3
// CHECK:STDERR: -> │ Cpp.PassThreeFields({.a = 1, .b = 2, .c = 3, .d = 4});
// CHECK:STDERR: · ━━━━━━━━━┳━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: no matching function for call to 'PassThreeFields'
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬ ┬────────────
// CHECK:STDERR: · ╰──────────────────┤ candidate function not viable [CppInteropParseNote]
// CHECK:STDERR: · ╰────┤ cannot convert initializer list argument to
// CHECK:STDERR: · │ 'ThreeFields'
// CHECK:STDERR: · │ [CppInteropParseNoteReason]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields({.a = 1, .b = 2, .c = 3, .d = 4});
// CHECK:STDERR: ╭─┤ fail_struct_init_field_mismatch.carbon:[[@LINE+15]]:3
// CHECK:STDERR: -> │ Cpp.PassThreeFields({.a = 1, .x = 2, .c = 3});
// CHECK:STDERR: · ━━━━━━━━━┳━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: no matching function for call to 'PassThreeFields'
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬ ┬────────────
// CHECK:STDERR: · ╰──────────────────┤ candidate function not viable [CppInteropParseNote]
// CHECK:STDERR: · ╰────┤ cannot convert initializer list argument to
// CHECK:STDERR: · │ 'ThreeFields'
// CHECK:STDERR: · │ [CppInteropParseNoteReason]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields({.a = 1, .x = 2, .c = 3});
}
// --- fail_struct_init_unsupported_field_name.carbon
library "[[@TEST_NAME]]";
import Cpp library "struct_init.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_struct_init_unsupported_field_name.carbon:[[@LINE+7]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields({.base = 1});
// CHECK:STDERR: · ━━━┳━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: field name `base` cannot be mapped into C++
// CHECK:STDERR: · ┃ [CppCallFieldNameNotSupported]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields({.base = 1});
}
// --- fail_struct_init_from_tuple.carbon
library "[[@TEST_NAME]]";
import Cpp library "struct_init.h";
// TODO: Struct init from an undesignated list is allowed in C++, but not in
// Carbon. Should we allow it when initializing a C++ class type?
fn MakeEmpty() -> ();
fn Empty(value: (), ref reference: ()) {
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:20
// CHECK:STDERR: -> │ Cpp.PassNoFields(());
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `()`
// CHECK:STDERR: · │ ┃ to `Cpp.NoFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.NoFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassNoFields(NoFields s) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassNoFields(());
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:20
// CHECK:STDERR: -> │ Cpp.PassNoFields(value);
// CHECK:STDERR: · ┳━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `()`
// CHECK:STDERR: · │ ┃ to `Cpp.NoFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.NoFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassNoFields(NoFields s) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassNoFields(value);
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:20
// CHECK:STDERR: -> │ Cpp.PassNoFields(reference);
// CHECK:STDERR: · ┳━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `()`
// CHECK:STDERR: · │ ┃ to `Cpp.NoFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.NoFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassNoFields(NoFields s) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassNoFields(reference);
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:20
// CHECK:STDERR: -> │ Cpp.PassNoFields(MakeEmpty());
// CHECK:STDERR: · ┳━━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `()`
// CHECK:STDERR: · │ ┃ to `Cpp.NoFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.NoFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassNoFields(NoFields s) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassNoFields(MakeEmpty());
}
fn MakeThreeFields() -> (i32, i32, i32);
fn ThreeFields(value: (i32, i32, i32), ref reference: (i32, i32, i32)) {
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+21]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields((1, 2, 3));
// CHECK:STDERR: · ┳━━━━━━━━
// CHECK:STDERR: · ┏━━━━━━━━━━━━━━━━━━━━━┛
// CHECK:STDERR: · ┃ error: cannot implicitly convert expression of type
// CHECK:STDERR: · ┃ `(Core.IntLiteral, Core.IntLiteral, Core.IntLiteral)` to
// CHECK:STDERR: · ┃ `Cpp.ThreeFields`
// CHECK:STDERR: · ┃ [ConversionFailure]
// CHECK:STDERR: · ╰──┤ type
// CHECK:STDERR: · │ `(Core.IntLiteral, Core.IntLiteral, Core.IntLiteral)`
// CHECK:STDERR: · │ does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields((1, 2, 3));
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(value);
// CHECK:STDERR: · ┳━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `(i32, i32, i32)` to `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `(i32, i32, i32)` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(value);
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(reference);
// CHECK:STDERR: · ┳━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `(i32, i32, i32)` to `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `(i32, i32, i32)` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(reference);
// CHECK:STDERR: ╭─┤ fail_struct_init_from_tuple.carbon:[[@LINE+17]]:23
// CHECK:STDERR: -> │ Cpp.PassThreeFields(MakeThreeFields());
// CHECK:STDERR: · ┳━━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `(i32, i32, i32)` to `Cpp.ThreeFields`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `(i32, i32, i32)` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(Cpp.ThreeFields)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./struct_init.h
// CHECK:STDERR: │ auto PassThreeFields(ThreeFields t) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassThreeFields(MakeThreeFields());
}
// --- int_from_struct.h
auto PassInt(int n) -> void;
struct S {};
auto PassOverloaded(int n) -> void;
auto PassOverloaded(S n) -> void;
// --- fail_int_from_struct.carbon
library "[[@TEST_NAME]]";
import Cpp library "int_from_struct.h";
fn F() {
// C++ permits `{}` to be used to initialize an int, but Carbon does not.
// CHECK:STDERR: ╭─┤ fail_int_from_struct.carbon:[[@LINE+16]]:15
// CHECK:STDERR: -> │ Cpp.PassInt({});
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `{}` to
// CHECK:STDERR: · │ ┃ `i32`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `{}` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(i32)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./int_from_struct.h
// CHECK:STDERR: │ auto PassInt(int n) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassInt({});
// CHECK:STDERR: ╭─┤ fail_int_from_struct.carbon:[[@LINE+16]]:15
// CHECK:STDERR: -> │ Cpp.PassInt(());
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type `()` to
// CHECK:STDERR: · │ ┃ `i32`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(i32)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./int_from_struct.h
// CHECK:STDERR: │ auto PassInt(int n) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassInt(());
}
// --- fail_int_from_struct_overloaded.carbon
library "[[@TEST_NAME]]";
import Cpp library "int_from_struct.h";
fn F() {
// C++ overload resolution prefers to convert `{}` to `int` rather than to an
// empty struct. So that's the overload we pick, even though we can't call it.
// CHECK:STDERR: ╭─┤ fail_int_from_struct_overloaded.carbon:[[@LINE+17]]:22
// CHECK:STDERR: -> │ Cpp.PassOverloaded({});
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `{}` to `i32`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `{}` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(i32)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./int_from_struct.h
// CHECK:STDERR: │ auto PassOverloaded(int n) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassOverloaded({});
// CHECK:STDERR: ╭─┤ fail_int_from_struct_overloaded.carbon:[[@LINE+17]]:22
// CHECK:STDERR: -> │ Cpp.PassOverloaded(());
// CHECK:STDERR: · ┳━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `()` to `i32`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `()` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(i32)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./int_from_struct.h
// CHECK:STDERR: │ auto PassOverloaded(int n) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.PassOverloaded(());
}
// --- nested_structs.h
struct A {
int x, y;
};
struct B {
A a;
int n;
};
void TakeB(B);
// --- fail_pass_nested_structs_inner_field_mismatch.carbon
library "[[@TEST_NAME]]";
import Cpp library "nested_structs.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_pass_nested_structs_inner_field_mismatch.carbon:[[@LINE+14]]:3
// CHECK:STDERR: -> │ Cpp.TakeB({.a = {.x = 1, .z = 2}, .n = 3});
// CHECK:STDERR: · ━━━━┳━━━━
// CHECK:STDERR: · ┗━━┫ error: no matching function for call to 'TakeB'
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./nested_structs.h
// CHECK:STDERR: │ void TakeB(B);
// CHECK:STDERR: · ┬ ┬
// CHECK:STDERR: · ╰────────┤ candidate function not viable [CppInteropParseNote]
// CHECK:STDERR: · ╰────┤ cannot convert initializer list argument to 'B'
// CHECK:STDERR: · │ [CppInteropParseNoteReason]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.TakeB({.a = {.x = 1, .z = 2}, .n = 3});
}
// --- fail_todo_pass_nested_structs.carbon
library "[[@TEST_NAME]]";
import Cpp library "nested_structs.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_todo_pass_nested_structs.carbon:[[@LINE+19]]:13
// CHECK:STDERR: -> │ Cpp.TakeB({.a = {.x = 1, .y = 2}, .n = 3});
// CHECK:STDERR: · ━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┛
// CHECK:STDERR: · ┃ error: cannot implicitly convert expression of type
// CHECK:STDERR: · ┃ `{.a: {.x: Core.IntLiteral, .y: Core.IntLiteral}, .n: Core.IntLiteral}`
// CHECK:STDERR: · ┃ to `Cpp.B`
// CHECK:STDERR: · ┃ [ConversionFailure]
// CHECK:STDERR: · ╭──────────────────────────╯
// CHECK:STDERR: · │ type `{.a: {.x: Core.IntLiteral, .y: Core.IntLiteral}, .n: Core.IntLiteral}`
// CHECK:STDERR: · │ does not implement interface `Core.ImplicitAs(Cpp.B)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./nested_structs.h
// CHECK:STDERR: │ void TakeB(B);
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.TakeB({.a = {.x = 1, .y = 2}, .n = 3});
}
// ============================================================================
// Overload rejected on Carbon side
// ============================================================================
// --- upsizing.h
auto upsizing_foo(int a) -> void;
// --- upsizing.carbon
library "[[@TEST_NAME]]";
import Cpp library "upsizing.h";
fn F() {
Cpp.upsizing_foo(1 as i16);
}
// --- signedness_change.h
auto signedness_foo(unsigned int a) -> void;
// --- fail_signedness_change_rejected.carbon
library "[[@TEST_NAME]]";
import Cpp library "signedness_change.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_signedness_change_rejected.carbon:[[@LINE+17]]:22
// CHECK:STDERR: -> │ Cpp.signedness_foo(1 as i32);
// CHECK:STDERR: · ┳━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `i32` to `u32`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `i32` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(u32)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./signedness_change.h
// CHECK:STDERR: │ auto signedness_foo(unsigned int a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.signedness_foo(1 as i32);
}
// --- downsizing_rejected.h
auto downsizing_foo(short a) -> void;
// --- fail_import_downsizing_rejected.carbon
library "[[@TEST_NAME]]";
import Cpp library "downsizing_rejected.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_downsizing_rejected.carbon:[[@LINE+17]]:22
// CHECK:STDERR: -> │ Cpp.downsizing_foo(1 as i32);
// CHECK:STDERR: · ┳━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot implicitly convert expression of type
// CHECK:STDERR: · │ ┃ `i32` to `i16`
// CHECK:STDERR: · │ ┃ [ConversionFailure]
// CHECK:STDERR: · ╰────┤ type `i32` does not implement interface
// CHECK:STDERR: · │ `Core.ImplicitAs(i16)`
// CHECK:STDERR: · │ [MissingImplInMemberAccessInContext]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./downsizing_rejected.h
// CHECK:STDERR: │ auto downsizing_foo(short a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ initializing function parameter
// CHECK:STDERR: · │ [InCallToFunctionParam]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.downsizing_foo(1 as i32);
}
// ============================================================================
// No viable function found
// ============================================================================
// --- no_viable_function.h
auto no_viable_foo(short a, int b) -> void;
// --- fail_import_no_viable_function.carbon
library "[[@TEST_NAME]]";
import Cpp library "no_viable_function.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_no_viable_function.carbon:[[@LINE+15]]:3
// CHECK:STDERR: -> │ Cpp.no_viable_foo(1 as i64);
// CHECK:STDERR: · ━━━━━━━━┳━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: no matching function for call to 'no_viable_foo'
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./no_viable_function.h
// CHECK:STDERR: │ auto no_viable_foo(short a, int b) -> void;
// CHECK:STDERR: · ┬ ───────┬──────
// CHECK:STDERR: · ╰───────────────────────┤ candidate function not viable
// CHECK:STDERR: · │ │ [CppInteropParseNote]
// CHECK:STDERR: · ╰────┤ requires 2 arguments, but 1 was provided
// CHECK:STDERR: · │ [CppInteropParseNoteReason]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.no_viable_foo(1 as i64);
}
// ============================================================================
// Ambiguous overload found
// ============================================================================
// --- ambiguous_overload.h
auto ambiguous_foo(short a) -> void;
auto ambiguous_foo(int a) -> void;
// --- fail_import_ambiguous_overload.carbon
library "[[@TEST_NAME]]";
import Cpp library "ambiguous_overload.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_ambiguous_overload.carbon:[[@LINE+15]]:3
// CHECK:STDERR: -> │ Cpp.ambiguous_foo(1 as i64);
// CHECK:STDERR: · ━━━━━━━━┳━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: call to 'ambiguous_foo' is ambiguous
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./ambiguous_overload.h
// CHECK:STDERR: │ auto ambiguous_foo(short a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ candidate function [CppInteropParseNote]
// CHECK:STDERR: │ auto ambiguous_foo(int a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ candidate function [CppInteropParseNote]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.ambiguous_foo(1 as i64);
}
// ============================================================================
// Deleted function found
// ============================================================================
// --- deleted_function.h
auto deleted_foo(short a) -> void;
auto deleted_foo(int a) -> void = delete;
// --- fail_import_deleted_function.carbon
library "[[@TEST_NAME]]";
import Cpp library "deleted_function.h";
fn F() {
// CHECK:STDERR: ╭─┤ fail_import_deleted_function.carbon:[[@LINE+15]]:3
// CHECK:STDERR: -> │ Cpp.deleted_foo(1 as i32);
// CHECK:STDERR: · ━━━━━━━┳━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: call to deleted function 'deleted_foo'
// CHECK:STDERR: · ┃ [CppInteropParseError]
// CHECK:STDERR: ┆
// CHECK:STDERR: ├─┤ ./deleted_function.h
// CHECK:STDERR: │ auto deleted_foo(short a) -> void;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ candidate function [CppInteropParseNote]
// CHECK:STDERR: │ auto deleted_foo(int a) -> void = delete;
// CHECK:STDERR: · ┬
// CHECK:STDERR: · ╰──┤ candidate function has been explicitly deleted [CppInteropParseNote]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
Cpp.deleted_foo(1 as i32);
}
// --- fail_missing_impl.carbon
library "[[@TEST_NAME]]";
import Cpp inline '''
void missing_impl_foo();
void missing_impl_foo(int);
''';
interface I {}
fn EchoValue[ValueT: I](unused generic value: ValueT) {}
fn F() {
// CHECK:STDERR: ╭─┤ fail_missing_impl.carbon:[[@LINE+13]]:3
// CHECK:STDERR: │ fn EchoValue[ValueT: I](unused generic value: ValueT) {}
// CHECK:STDERR: · ─────────────────────────┬─────────────────────────────
// CHECK:STDERR: · ╰──┤ while deducing parameters of generic declared here
// CHECK:STDERR: · │ [DeductionGenericHere]
// CHECK:STDERR: ┆
// CHECK:STDERR: -> │ EchoValue(Cpp.missing_impl_foo);
// CHECK:STDERR: · ┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CHECK:STDERR: · ┗━━┫ error: cannot convert type `<type of Cpp.missing_impl_foo>` into type
// CHECK:STDERR: · ┃ implementing `I`
// CHECK:STDERR: · ┃ [ConversionFailureTypeToFacet]
// CHECK:STDERR: ╰────
// CHECK:STDERR:
EchoValue(Cpp.missing_impl_foo);
}