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:
Richard Smith
2024-01-30 02:19:38 +00:00
committed by GitHub
co-authored by Chandler Carruth
parent 7f11012f58
commit 3fa70de101
9 changed files with 71 additions and 60 deletions
+3 -5
View File
@@ -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
+1 -1
View File
@@ -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) {
+3 -3
View File
@@ -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
View File
@@ -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);
+3 -2
View File
@@ -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()];
+2 -2
View File
@@ -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>) {
+16 -6
View File
@@ -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
+4 -3
View File
@@ -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>);
}
}
+6 -9
View File
@@ -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) {}