Interop support for initialization via std::initializer_list. (#6672)

Add a new builtin function `cpp.std.initializer_list.make` that takes an
array and returns a `std::initializer_list`, initialized to refer to
that array. When C++ initialization wants to perform a
`std::initializer_list`-from-array construction, synthesize a
declaration of a matching builtin function and use that to perform the
initialization.

Ideally we would specify this conversion as an impl of `ImplicitAs` in
the prelude instead of hardcoding it in the interop layer, but
unfortunately that's not currently possible, for various reasons -- we
can't make the conversion form-generic, we can't deduce the array length
from the initializer, and we can't deduce against the arguments of
imported C++ class templates yet -- so for now synthesizing a builtin
function on demand is the best we can do.

Assisted-by: Gemini 3 Pro via Antigravity
This commit is contained in:
Richard Smith
2026-01-30 22:24:18 +00:00
committed by GitHub
parent 20a5c43e95
commit c0b24047dd
27 changed files with 2137 additions and 525 deletions
+30 -11
View File
@@ -6,6 +6,7 @@
#include <utility>
#include "toolchain/sem_ir/cpp_initializer_list.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/type_info.h"
@@ -146,14 +147,24 @@ struct CharCompatible {
}
};
// Constraint that requires the type to be a sized integer type.
struct AnySizedInt {
// Constraint that requires the type to be an type of the specified kind.
template <typename InstT>
struct Any {
static auto CheckType(const File& sem_ir, ValidateState& /*state*/,
TypeId type_id) -> bool {
return sem_ir.types().Is<IntType>(type_id);
return sem_ir.types().Is<InstT>(type_id);
}
};
// Constraint that requires the type to be a sized integer type.
using AnySizedInt = Any<IntType>;
// Constraint that requires the type to be a sized floating-point type.
using AnySizedFloat = Any<FloatType>;
// Constraint that requires the type to be an array type.
using AnyArray = Any<ArrayType>;
// Constraint that requires the type to be an integer type: either a sized
// integer type or a literal.
struct AnyInt {
@@ -165,14 +176,6 @@ struct AnyInt {
}
};
// Constraint that requires the type to be a sized floating-point type.
struct AnySizedFloat {
static auto CheckType(const File& sem_ir, ValidateState& /*state*/,
TypeId type_id) -> bool {
return sem_ir.types().Is<FloatType>(type_id);
}
};
// Constraint that requires the type to be a float type: either a sized float
// type or a literal.
struct AnyFloat {
@@ -222,6 +225,16 @@ struct CoreCharType {
}
};
// Constraint that requires the type to have a recognized layout, compatible
// with `std::initializer_list<T>`.
struct StdInitializerList {
static auto CheckType(const File& sem_ir, ValidateState& /*state*/,
TypeId type_id) -> bool {
return GetStdInitializerListLayout(sem_ir, type_id).kind !=
StdInitializerListLayout::None;
}
};
// Constraint that requires the type to be the type type.
using Type = BuiltinType<TypeType::TypeInstId>;
@@ -734,6 +747,12 @@ constexpr BuiltinInfo PointerUnsafeConvert = {
constexpr BuiltinInfo TypeAnd = {"type.and",
ValidateSignature<auto(Type, Type)->Type>};
// "cpp.std.initializer_list.make": construct a std::initializer_list from an
// array.
constexpr BuiltinInfo CppStdInitializerListMake = {
"cpp.std.initializer_list.make",
ValidateSignature<auto(AnyArray)->StdInitializerList>};
} // namespace BuiltinFunctionInfo
CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinFunctionKind) {