mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 06:34:41 +01:00
Remove some C++17 workarounds now we build in C++20 mode. (#3653)
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
co-authored by
Chandler Carruth
parent
7f11012f58
commit
3fa70de101
@@ -13,7 +13,6 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId parse_node,
|
||||
bool is_generic) -> bool {
|
||||
auto [type_node, parsed_type_id] =
|
||||
context.node_stack().PopExprWithParseNode();
|
||||
auto type_node_copy = type_node;
|
||||
auto cast_type_id = ExprAsType(context, type_node, parsed_type_id);
|
||||
|
||||
// TODO: Handle `_` bindings.
|
||||
@@ -22,8 +21,7 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId parse_node,
|
||||
auto [name_node, name_id] = context.node_stack().PopNameWithParseNode();
|
||||
|
||||
// Create the appropriate kind of binding for this pattern.
|
||||
auto make_bind_name = [&, name_node = name_node, name_id = name_id](
|
||||
SemIR::TypeId type_id,
|
||||
auto make_bind_name = [&](SemIR::TypeId type_id,
|
||||
SemIR::InstId value_id) -> SemIR::ParseNodeAndInst {
|
||||
// TODO: Eventually the name will need to support associations with other
|
||||
// scopes, but right now we don't support qualified names here.
|
||||
@@ -73,7 +71,7 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId parse_node,
|
||||
"{0} has incomplete type `{1}`.", llvm::StringLiteral,
|
||||
std::string);
|
||||
return context.emitter().Build(
|
||||
type_node_copy, IncompleteTypeInVarDecl,
|
||||
type_node, IncompleteTypeInVarDecl,
|
||||
enclosing_class_decl ? llvm::StringLiteral("Field")
|
||||
: llvm::StringLiteral("Variable"),
|
||||
context.sem_ir().StringifyType(cast_type_id));
|
||||
@@ -139,7 +137,7 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId parse_node,
|
||||
"`let` binding has incomplete type `{0}`.",
|
||||
std::string);
|
||||
return context.emitter().Build(
|
||||
type_node_copy, IncompleteTypeInLetDecl,
|
||||
type_node, IncompleteTypeInLetDecl,
|
||||
context.sem_ir().StringifyType(cast_type_id));
|
||||
});
|
||||
// Create the instruction, but don't add it to a block until after we've
|
||||
|
||||
@@ -832,7 +832,7 @@ class Formatter {
|
||||
template <typename InstT>
|
||||
auto FormatInstructionRHS(InstT inst) -> void {
|
||||
// By default, an instruction has a comma-separated argument list.
|
||||
using Info = InstLikeTypeInfo<InstT>;
|
||||
using Info = Internal::InstLikeTypeInfo<InstT>;
|
||||
if constexpr (Info::NumArgs == 2) {
|
||||
FormatArgs(Info::template Get<0>(inst), Info::template Get<1>(inst));
|
||||
} else if constexpr (Info::NumArgs == 1) {
|
||||
|
||||
@@ -20,9 +20,9 @@ auto Inst::Print(llvm::raw_ostream& out) const -> void {
|
||||
};
|
||||
|
||||
switch (kind_) {
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
case Name::Kind: \
|
||||
print_args(InstLikeTypeInfo<Name>()); \
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
case Name::Kind: \
|
||||
print_args(Internal::InstLikeTypeInfo<Name>()); \
|
||||
break;
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
}
|
||||
|
||||
+33
-29
@@ -5,8 +5,8 @@
|
||||
#ifndef CARBON_TOOLCHAIN_SEM_IR_INST_H_
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_INST_H_
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/check.h"
|
||||
#include "common/ostream.h"
|
||||
@@ -18,20 +18,18 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// InstLikeTypeInfo is an implementation detail, and not public API.
|
||||
namespace Internal {
|
||||
|
||||
// Information about an instruction-like type, which is a type that an Inst can
|
||||
// be converted to and from. The `Enabled` parameter is used to check
|
||||
// requirements on the type in the specializations of this template.
|
||||
template <typename InstLikeType, bool Enabled = true>
|
||||
template <typename InstLikeType>
|
||||
struct InstLikeTypeInfo;
|
||||
|
||||
// A helper base class for instruction-like types that are structs.
|
||||
template <typename InstLikeType>
|
||||
struct InstLikeTypeInfoBase {
|
||||
// The derived class. Useful to allow SFINAE on whether a type is
|
||||
// instruction-like: `typename InstLikeTypeInfo<T>::Self` is valid only if `T`
|
||||
// is instruction-like.
|
||||
using Self = InstLikeTypeInfo<InstLikeType>;
|
||||
|
||||
// A corresponding std::tuple<...> type.
|
||||
using Tuple =
|
||||
decltype(StructReflection::AsTuple(std::declval<InstLikeType>()));
|
||||
@@ -54,13 +52,10 @@ struct InstLikeTypeInfoBase {
|
||||
|
||||
// A particular type of instruction is instruction-like.
|
||||
template <typename TypedInst>
|
||||
struct InstLikeTypeInfo<
|
||||
TypedInst,
|
||||
static_cast<bool>(
|
||||
std::is_same_v<const InstKind::Definition<
|
||||
typename decltype(TypedInst::Kind)::TypedNodeId>,
|
||||
decltype(TypedInst::Kind)>)>
|
||||
: InstLikeTypeInfoBase<TypedInst> {
|
||||
requires std::same_as<const InstKind::Definition<
|
||||
typename decltype(TypedInst::Kind)::TypedNodeId>,
|
||||
decltype(TypedInst::Kind)>
|
||||
struct InstLikeTypeInfo<TypedInst> : InstLikeTypeInfoBase<TypedInst> {
|
||||
static_assert(!HasKindMemberAsField<TypedInst>,
|
||||
"Instruction type should not have a kind field");
|
||||
static auto GetKind(TypedInst /*inst*/) -> InstKind {
|
||||
@@ -73,10 +68,8 @@ struct InstLikeTypeInfo<
|
||||
|
||||
// An instruction category is instruction-like.
|
||||
template <typename InstCat>
|
||||
struct InstLikeTypeInfo<
|
||||
InstCat, static_cast<bool>(
|
||||
std::is_same_v<const InstKind&, decltype(InstCat::Kinds[0])>)>
|
||||
: InstLikeTypeInfoBase<InstCat> {
|
||||
requires std::same_as<const InstKind&, decltype(InstCat::Kinds[0])>
|
||||
struct InstLikeTypeInfo<InstCat> : InstLikeTypeInfoBase<InstCat> {
|
||||
static_assert(HasKindMemberAsField<InstCat>,
|
||||
"Instruction category should have a kind field");
|
||||
static auto GetKind(InstCat cat) -> InstKind { return cat.kind; }
|
||||
@@ -102,6 +95,12 @@ struct InstLikeTypeInfo<
|
||||
}
|
||||
};
|
||||
|
||||
// A type is InstLike if InstLikeTypeInfo is defined for it.
|
||||
template <typename T>
|
||||
concept InstLikeType = requires { sizeof(InstLikeTypeInfo<T>); };
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
// A type-erased representation of a SemIR instruction, that may be constructed
|
||||
// from the specific kinds of instruction defined in `typed_insts.h`. This
|
||||
// provides access to common fields present on most or all kinds of
|
||||
@@ -123,8 +122,8 @@ struct InstLikeTypeInfo<
|
||||
// data where the instruction's kind is not known.
|
||||
class Inst : public Printable<Inst> {
|
||||
public:
|
||||
template <typename TypedInst,
|
||||
typename Info = typename InstLikeTypeInfo<TypedInst>::Self>
|
||||
template <typename TypedInst>
|
||||
requires Internal::InstLikeType<TypedInst>
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
Inst(TypedInst typed_inst)
|
||||
// kind_ is always overwritten below.
|
||||
@@ -132,14 +131,15 @@ class Inst : public Printable<Inst> {
|
||||
type_id_(TypeId::Invalid),
|
||||
arg0_(InstId::InvalidIndex),
|
||||
arg1_(InstId::InvalidIndex) {
|
||||
if constexpr (HasKindMemberAsField<TypedInst>) {
|
||||
if constexpr (Internal::HasKindMemberAsField<TypedInst>) {
|
||||
kind_ = typed_inst.kind;
|
||||
} else {
|
||||
kind_ = TypedInst::Kind;
|
||||
}
|
||||
if constexpr (HasTypeIdMember<TypedInst>) {
|
||||
if constexpr (Internal::HasTypeIdMember<TypedInst>) {
|
||||
type_id_ = typed_inst.type_id;
|
||||
}
|
||||
using Info = Internal::InstLikeTypeInfo<TypedInst>;
|
||||
if constexpr (Info::NumArgs > 0) {
|
||||
arg0_ = ToRaw(Info::template Get<0>(typed_inst));
|
||||
}
|
||||
@@ -149,19 +149,22 @@ class Inst : public Printable<Inst> {
|
||||
}
|
||||
|
||||
// Returns whether this instruction has the specified type.
|
||||
template <typename TypedInst, typename Info = InstLikeTypeInfo<TypedInst>>
|
||||
template <typename TypedInst>
|
||||
requires Internal::InstLikeType<TypedInst>
|
||||
auto Is() const -> bool {
|
||||
return Info::IsKind(kind());
|
||||
return Internal::InstLikeTypeInfo<TypedInst>::IsKind(kind());
|
||||
}
|
||||
|
||||
// Casts this instruction to the given typed instruction, which must match the
|
||||
// instruction's kind, and returns the typed instruction.
|
||||
template <typename TypedInst, typename Info = InstLikeTypeInfo<TypedInst>>
|
||||
template <typename TypedInst>
|
||||
requires Internal::InstLikeType<TypedInst>
|
||||
auto As() const -> TypedInst {
|
||||
using Info = Internal::InstLikeTypeInfo<TypedInst>;
|
||||
CARBON_CHECK(Is<TypedInst>()) << "Casting inst of kind " << kind()
|
||||
<< " to wrong kind " << Info::DebugName();
|
||||
auto build_with_type_id_onwards = [&](auto... type_id_onwards) {
|
||||
if constexpr (HasKindMemberAsField<TypedInst>) {
|
||||
if constexpr (Internal::HasKindMemberAsField<TypedInst>) {
|
||||
return TypedInst{kind(), type_id_onwards...};
|
||||
} else {
|
||||
return TypedInst{type_id_onwards...};
|
||||
@@ -169,7 +172,7 @@ class Inst : public Printable<Inst> {
|
||||
};
|
||||
|
||||
auto build_with_args = [&](auto... args) {
|
||||
if constexpr (HasTypeIdMember<TypedInst>) {
|
||||
if constexpr (Internal::HasTypeIdMember<TypedInst>) {
|
||||
return build_with_type_id_onwards(type_id(), args...);
|
||||
} else {
|
||||
return build_with_type_id_onwards(args...);
|
||||
@@ -191,6 +194,7 @@ class Inst : public Printable<Inst> {
|
||||
// If this instruction is the given kind, returns a typed instruction,
|
||||
// otherwise returns nullopt.
|
||||
template <typename TypedInst>
|
||||
requires Internal::InstLikeType<TypedInst>
|
||||
auto TryAs() const -> std::optional<TypedInst> {
|
||||
if (Is<TypedInst>()) {
|
||||
return As<TypedInst>();
|
||||
@@ -253,8 +257,8 @@ class Inst : public Printable<Inst> {
|
||||
static_assert(sizeof(Inst) == 16, "Unexpected Inst size");
|
||||
|
||||
// Instruction-like types can be printed by converting them to instructions.
|
||||
template <typename TypedInst,
|
||||
typename = typename InstLikeTypeInfo<TypedInst>::Self>
|
||||
template <typename TypedInst>
|
||||
requires Internal::InstLikeType<TypedInst>
|
||||
inline auto operator<<(llvm::raw_ostream& out, TypedInst inst)
|
||||
-> llvm::raw_ostream& {
|
||||
Inst(inst).Print(out);
|
||||
|
||||
@@ -23,8 +23,9 @@ auto InstKind::ir_name() const -> llvm::StringLiteral {
|
||||
|
||||
auto InstKind::value_kind() const -> InstValueKind {
|
||||
static constexpr InstValueKind Table[] = {
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
HasTypeIdMember<SemIR::Name> ? InstValueKind::Typed : InstValueKind::None,
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
Internal::HasTypeIdMember<SemIR::Name> ? InstValueKind::Typed \
|
||||
: InstValueKind::None,
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
};
|
||||
return Table[AsInt()];
|
||||
|
||||
@@ -72,11 +72,11 @@ static auto RealProfileArgFunction(llvm::FoldingSetNodeID& id,
|
||||
// namely `ProfileArgs<DefaultProfileArgFunction, DefaultProfileArgFunction>`.
|
||||
template <typename InstT, int N>
|
||||
static constexpr auto SelectProfileArgFunction() -> ProfileArgFunction* {
|
||||
if constexpr (N >= InstLikeTypeInfo<InstT>::NumArgs) {
|
||||
if constexpr (N >= Internal::InstLikeTypeInfo<InstT>::NumArgs) {
|
||||
// This argument is not used by this instruction; don't profile it.
|
||||
return NullProfileArgFunction;
|
||||
} else {
|
||||
using ArgT = typename InstLikeTypeInfo<InstT>::template ArgType<N>;
|
||||
using ArgT = Internal::InstLikeTypeInfo<InstT>::template ArgType<N>;
|
||||
if constexpr (std::is_same_v<ArgT, InstBlockId>) {
|
||||
return InstBlockProfileArgFunction;
|
||||
} else if constexpr (std::is_same_v<ArgT, TypeBlockId>) {
|
||||
|
||||
@@ -736,18 +736,28 @@ struct VarStorage {
|
||||
NameId name_id;
|
||||
};
|
||||
|
||||
// These concepts are an implementation detail of the library, not public API.
|
||||
namespace Internal {
|
||||
|
||||
// HasParseNode is true if T has an associated parse node.
|
||||
template <typename T>
|
||||
concept HasParseNode = !std::same_as<typename decltype(T::Kind)::TypedNodeId,
|
||||
Parse::InvalidNodeId>;
|
||||
|
||||
// HasKindMemberAsField<T> is true if T has a `InstKind kind` field, as opposed
|
||||
// to a `static constexpr InstKind::Definition Kind` member or no kind at all.
|
||||
template <typename T, typename KindType = InstKind T::*>
|
||||
inline constexpr bool HasKindMemberAsField = false;
|
||||
template <typename T>
|
||||
inline constexpr bool HasKindMemberAsField<T, decltype(&T::kind)> = true;
|
||||
concept HasKindMemberAsField = requires {
|
||||
{ &T::kind } -> std::same_as<InstKind T::*>;
|
||||
};
|
||||
|
||||
// HasTypeIdMember<T> is true if T has a `TypeId type_id` field.
|
||||
template <typename T, typename TypeIdType = TypeId T::*>
|
||||
inline constexpr bool HasTypeIdMember = false;
|
||||
template <typename T>
|
||||
inline constexpr bool HasTypeIdMember<T, decltype(&T::type_id)> = true;
|
||||
concept HasTypeIdMember = requires {
|
||||
{ &T::type_id } -> std::same_as<TypeId T::*>;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ template <typename TypedInst>
|
||||
auto CommonFieldOrder() -> void {
|
||||
Inst inst = MakeInstWithNumberedFields(TypedInst::Kind);
|
||||
auto typed = inst.As<TypedInst>();
|
||||
if constexpr (HasTypeIdMember<TypedInst>) {
|
||||
if constexpr (Internal::HasTypeIdMember<TypedInst>) {
|
||||
EXPECT_EQ(typed.type_id, TypeId(1));
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ auto RoundTrip() -> void {
|
||||
auto typed1 = inst1.As<TypedInst>();
|
||||
Inst inst2 = typed1;
|
||||
|
||||
ExpectEqInsts(inst1, inst2, HasTypeIdMember<TypedInst>);
|
||||
ExpectEqInsts(inst1, inst2, Internal::HasTypeIdMember<TypedInst>);
|
||||
|
||||
// If the typed instruction has no padding, we should get exactly the same
|
||||
// thing if we convert back from an instruction.
|
||||
@@ -119,7 +119,8 @@ auto StructLayout() -> void {
|
||||
if constexpr (std::has_unique_object_representations_v<TypedInst>) {
|
||||
auto typed =
|
||||
MakeInstWithNumberedFields(TypedInst::Kind).template As<TypedInst>();
|
||||
StructLayoutHelper(&typed, sizeof(typed), HasTypeIdMember<TypedInst>);
|
||||
StructLayoutHelper(&typed, sizeof(typed),
|
||||
Internal::HasTypeIdMember<TypedInst>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,19 +29,16 @@ struct ParseNodeAndInst {
|
||||
|
||||
// For the common case, support construction as:
|
||||
// context.AddInst({parse_node, SemIR::MyInst{...}});
|
||||
template <typename InstT, typename std::enable_if_t<!std::is_same_v<
|
||||
typename decltype(InstT::Kind)::TypedNodeId,
|
||||
Parse::InvalidNodeId>>* = nullptr>
|
||||
template <typename InstT>
|
||||
requires(Internal::HasParseNode<InstT>)
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
ParseNodeAndInst(typename decltype(InstT::Kind)::TypedNodeId parse_node,
|
||||
InstT inst)
|
||||
ParseNodeAndInst(decltype(InstT::Kind)::TypedNodeId parse_node, InstT inst)
|
||||
: parse_node(parse_node), inst(inst) {}
|
||||
|
||||
// For cases with no parse node, support construction as:
|
||||
// context.AddInst({SemIR::MyInst{...}});
|
||||
template <typename InstT, typename std::enable_if_t<std::is_same_v<
|
||||
typename decltype(InstT::Kind)::TypedNodeId,
|
||||
Parse::InvalidNodeId>>* = nullptr>
|
||||
template <typename InstT>
|
||||
requires(!Internal::HasParseNode<InstT>)
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
ParseNodeAndInst(InstT inst)
|
||||
: parse_node(Parse::NodeId::Invalid), inst(inst) {}
|
||||
@@ -379,7 +376,7 @@ class NameScopeStore {
|
||||
template <typename IdT>
|
||||
class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
|
||||
public:
|
||||
using ElementType = typename IdT::ElementType;
|
||||
using ElementType = IdT::ElementType;
|
||||
|
||||
explicit BlockValueStore(llvm::BumpPtrAllocator& allocator)
|
||||
: allocator_(&allocator) {}
|
||||
|
||||
Reference in New Issue
Block a user