소스 검색

Use explicit(false) for implicit construction (#6039)

Echoing what was added in #5608, updating existing uses. Unfortunately
there's divergent behavior for operators versus constructors, so keeping
the nolint on those.
Jon Ross-Perkins 7 달 전
부모
커밋
3f799bd987

+ 1 - 1
common/enum_base.h

@@ -122,7 +122,7 @@ class EnumBase : public Printable<DerivedT> {
   // function.
   //
   // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr operator RawEnumType() const { return value_; }
+  explicit(false) constexpr operator RawEnumType() const { return value_; }
 
   // Conversion to bool is deleted to prevent direct use in an `if` condition
   // instead of comparing with another value.

+ 7 - 12
common/error.h

@@ -104,8 +104,7 @@ class [[nodiscard]] ErrorOr {
 
   // Constructs with an error; the error must not be Error::Success().
   // Implicit for easy construction on returns.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ErrorOr(ErrorT err) : val_(std::move(err)) {}
+  explicit(false) ErrorOr(ErrorT err) : val_(std::move(err)) {}
 
   // Constructs from a custom error type derived from `ErrorBase` into an
   // `ErrorOr` for `Error` to facilitate returning errors transparently.
@@ -113,8 +112,7 @@ class [[nodiscard]] ErrorOr {
     requires(std::same_as<ErrorT, Error> &&
              std::derived_from<OtherErrorT, ErrorBase<OtherErrorT>>)
   // Implicit for easy construction on returns.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ErrorOr(OtherErrorT other_err) : val_(other_err.ToError()) {}
+  explicit(false) ErrorOr(OtherErrorT other_err) : val_(other_err.ToError()) {}
 
   // Constructs with any convertible error type, necessary for return statements
   // that are already converting to the `ErrorOr` wrapper.
@@ -126,21 +124,18 @@ class [[nodiscard]] ErrorOr {
     requires(std::constructible_from<ErrorT, OtherErrorT> &&
              std::derived_from<OtherErrorT, ErrorBase<OtherErrorT>>)
   // Implicit for easy construction on returns.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ErrorOr(OtherErrorT other_err)
+  explicit(false) ErrorOr(OtherErrorT other_err)
       : val_(std::in_place_type<ErrorT>, std::move(other_err)) {}
 
   // Constructs with a reference.
   // Implicit for easy construction on returns.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ErrorOr(T ref)
+  explicit(false) ErrorOr(T ref)
     requires std::is_reference_v<T>
       : val_(std::ref(ref)) {}
 
   // Constructs with a value.
   // Implicit for easy construction on returns.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ErrorOr(T val)
+  explicit(false) ErrorOr(T val)
     requires(!std::is_reference_v<T>)
       : val_(std::move(val)) {}
 
@@ -224,11 +219,11 @@ class ErrorBuilder {
   }
 
   // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
-  operator Error() { return Error(out_->TakeStr()); }
+  explicit(false) operator Error() { return Error(out_->TakeStr()); }
 
   template <typename T>
   // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
-  operator ErrorOr<T>() {
+  explicit(false) operator ErrorOr<T>() {
     return Error(out_->TakeStr());
   }
 

+ 1 - 0
common/error_test_helpers.h

@@ -95,6 +95,7 @@ class IsSuccessMatcher {
       : matcher_(std::move(matcher)) {}
 
   template <typename T, typename ErrorT>
+  explicit(false)
   // NOLINTNEXTLINE(google-explicit-constructor): Required for matcher APIs.
   operator ::testing::Matcher<const ErrorOr<T, ErrorT>&>() const {
     return ::testing::Matcher<const ErrorOr<T, ErrorT>&>(

+ 5 - 6
common/map.h

@@ -89,8 +89,8 @@ class MapView
   // type. This is always safe to do with a view. We use a template to avoid
   // needing all 3 versions.
   template <typename OtherKeyT, typename OtherValueT>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  MapView(MapView<OtherKeyT, OtherValueT, KeyContextT> other_view)
+  explicit(false)
+      MapView(MapView<OtherKeyT, OtherValueT, KeyContextT> other_view)
     requires(SameAsOneOf<KeyT, OtherKeyT, const OtherKeyT> &&
              SameAsOneOf<ValueT, OtherValueT, const OtherValueT>)
       : ImplT(other_view) {}
@@ -134,8 +134,7 @@ class MapView
   friend class MapView<const KeyT, const ValueT, KeyContextT>;
 
   MapView() = default;
-  // NOLINTNEXTLINE(google-explicit-constructor): Implicit by design.
-  MapView(ImplT base) : ImplT(base) {}
+  explicit(false) MapView(ImplT base) : ImplT(base) {}
   MapView(ssize_t size, RawHashtable::Storage* storage)
       : ImplT(size, storage) {}
 };
@@ -185,13 +184,13 @@ class MapBase : protected RawHashtable::BaseImpl<InputKeyT, InputValueT,
   // Implicitly convertible to the relevant view type.
   //
   // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
-  operator ViewT() const { return this->view_impl(); }
+  explicit(false) operator ViewT() const { return this->view_impl(); }
 
   // We can't chain the above conversion with the conversions on `ViewT` to add
   // const, so explicitly support adding const to produce a view here.
   template <typename OtherKeyT, typename OtherValueT>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  operator MapView<OtherKeyT, OtherValueT, KeyContextT>() const
+  explicit(false) operator MapView<OtherKeyT, OtherValueT, KeyContextT>() const
     requires(SameAsOneOf<OtherKeyT, KeyT, const KeyT> &&
              SameAsOneOf<OtherValueT, ValueT, const ValueT>)
   {

+ 3 - 3
common/raw_hashtable.h

@@ -373,8 +373,8 @@ class ViewImpl {
 
   // Support adding `const` to either key or value type of some other view.
   template <typename OtherKeyT, typename OtherValueT>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  ViewImpl(ViewImpl<OtherKeyT, OtherValueT, KeyContextT> other_view)
+  explicit(false)
+      ViewImpl(ViewImpl<OtherKeyT, OtherValueT, KeyContextT> other_view)
     requires(SameAsOneOf<KeyT, OtherKeyT, const OtherKeyT> &&
              SameAsOneOf<ValueT, OtherValueT, const OtherValueT>)
       : alloc_size_(other_view.alloc_size_), storage_(other_view.storage_) {}
@@ -493,7 +493,7 @@ class BaseImpl {
   ~BaseImpl() = default;
 
   // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
-  operator ViewImplT() const { return view_impl(); }
+  explicit(false) operator ViewImplT() const { return view_impl(); }
 
   auto view_impl() const -> ViewImplT { return view_impl_; }
 

+ 7 - 6
common/set.h

@@ -78,8 +78,8 @@ class SetView : RawHashtable::ViewImpl<InputKeyT, void, InputKeyContextT> {
   };
 
   // Enable implicit conversions that add `const`-ness to the key type.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  SetView(const SetView<std::remove_const_t<KeyT>, KeyContextT>& other_view)
+  explicit(false)
+      SetView(const SetView<std::remove_const_t<KeyT>, KeyContextT>& other_view)
     requires(!std::same_as<KeyT, std::remove_const_t<KeyT>>)
       : ImplT(other_view) {}
 
@@ -115,8 +115,7 @@ class SetView : RawHashtable::ViewImpl<InputKeyT, void, InputKeyContextT> {
   using EntryT = typename ImplT::EntryT;
 
   SetView() = default;
-  // NOLINTNEXTLINE(google-explicit-constructor): Implicit by design.
-  SetView(ImplT base) : ImplT(base) {}
+  explicit(false) SetView(ImplT base) : ImplT(base) {}
   SetView(ssize_t size, RawHashtable::Storage* storage)
       : ImplT(size, storage) {}
 };
@@ -161,13 +160,15 @@ class SetBase
   // Implicitly convertible to the relevant view type.
   //
   // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
-  operator ViewT() const { return this->view_impl(); }
+  explicit(false) operator ViewT() const { return this->view_impl(); }
 
   // We can't chain the above conversion with the conversions on `ViewT` to add
   // const, so explicitly support adding const to produce a view here.
   //
   // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
-  operator SetView<const KeyT, KeyContextT>() const { return ViewT(*this); }
+  explicit(false) operator SetView<const KeyT, KeyContextT>() const {
+    return ViewT(*this);
+  }
 
   // Convenience forwarder to the view type.
   template <typename LookupKeyT>

+ 2 - 2
common/struct_reflection.h

@@ -37,11 +37,11 @@ template <typename T>
 struct AnyField {
   template <typename FieldT>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  operator FieldT&() const;
+  explicit(false) operator FieldT&() const;
 
   template <typename FieldT>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  operator FieldT&&() const;
+  explicit(false) operator FieldT&&() const;
 
   // Don't allow conversion to T itself. This ensures we don't match against a
   // copy or move constructor.

+ 5 - 6
common/template_string.h

@@ -43,11 +43,10 @@ struct TemplateString {
   // `enable_if` attribute to require the array to be usable as a C string with
   // the expected length. This checks both for null-termination and no embedded
   // `0` bytes.
-  //
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr TemplateString(const char (&str)[N + 1]) __attribute__((
-      enable_if(__builtin_strlen(str) == N,
-                "character array is not null-terminated valid C string"))) {
+  explicit(false) constexpr TemplateString(const char (&str)[N + 1])
+      __attribute__((
+          enable_if(__builtin_strlen(str) == N,
+                    "character array is not null-terminated valid C string"))) {
     // Rely on Clang's constexpr `__builtin_memcpy` to minimize compile time
     // overhead copying the string contents around.
     __builtin_memcpy(storage_, str, N + 1);
@@ -57,7 +56,7 @@ struct TemplateString {
   // storage necessary to be used as a template parameter.
   //
   // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr operator llvm::StringRef() const {
+  explicit(false) constexpr operator llvm::StringRef() const {
     return llvm::StringRef(storage_, N);
   }
 

+ 2 - 2
common/template_string_test.cpp

@@ -35,8 +35,8 @@ constexpr auto IsValidTemplateString(int /*unused*/) -> std::true_type {
 struct AnythingAsTemplateArg {
   // An implicit constructor that can accept any argument and discards it.
   template <typename T>
-  // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
-  constexpr AnythingAsTemplateArg(T&& /*unused*/) {}
+  // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
+  explicit(false) constexpr AnythingAsTemplateArg(T&& /*unused*/) {}
 };
 
 // An overload that will be active for any template argument. Returns a false

+ 1 - 1
common/type_enum.h

@@ -71,7 +71,7 @@ class TypeEnum : public Printable<TypeEnum<Types...>> {
   // Implicitly convert to the raw enum type, for use in `switch`.
   //
   // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr operator RawEnumType() const { return value_; }
+  explicit(false) constexpr operator RawEnumType() const { return value_; }
 
   // Conversion to bool is deleted to prevent direct use in an `if` condition
   // instead of comparing with another value.

+ 7 - 12
toolchain/check/diagnostic_helpers.h

@@ -28,8 +28,7 @@ class LocIdForDiagnostics {
 
   template <typename LocT>
     requires std::constructible_from<SemIR::LocId, LocT>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  LocIdForDiagnostics(LocT loc_id)
+  explicit(false) LocIdForDiagnostics(LocT loc_id)
       : LocIdForDiagnostics(SemIR::LocId(loc_id), false) {}
 
   auto loc_id() const -> SemIR::LocId { return loc_id_; }
@@ -60,8 +59,7 @@ using MakeDiagnosticBuilderFn = llvm::function_ref<auto()->DiagnosticBuilder>;
 struct InstIdAsConstant {
   using DiagnosticType = Diagnostics::TypeInfo<std::string>;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  InstIdAsConstant(SemIR::InstId inst_id) : inst_id(inst_id) {}
+  explicit(false) InstIdAsConstant(SemIR::InstId inst_id) : inst_id(inst_id) {}
 
   SemIR::InstId inst_id;
 };
@@ -80,8 +78,7 @@ struct InstIdAsConstant {
 struct TypeOfInstId {
   using DiagnosticType = Diagnostics::TypeInfo<std::string>;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  TypeOfInstId(SemIR::InstId inst_id) : inst_id(inst_id) {}
+  explicit(false) TypeOfInstId(SemIR::InstId inst_id) : inst_id(inst_id) {}
 
   SemIR::InstId inst_id;
 };
@@ -112,8 +109,7 @@ using InstIdAsType = InstIdAsConstant;
 struct InstIdAsRawType {
   using DiagnosticType = Diagnostics::TypeInfo<std::string>;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  InstIdAsRawType(SemIR::InstId inst_id) : inst_id(inst_id) {}
+  explicit(false) InstIdAsRawType(SemIR::InstId inst_id) : inst_id(inst_id) {}
 
   SemIR::InstId inst_id;
 };
@@ -127,8 +123,7 @@ struct InstIdAsRawType {
 struct TypeIdAsRawType {
   using DiagnosticType = Diagnostics::TypeInfo<std::string>;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  TypeIdAsRawType(SemIR::TypeId type_id) : type_id(type_id) {}
+  explicit(false) TypeIdAsRawType(SemIR::TypeId type_id) : type_id(type_id) {}
 
   SemIR::TypeId type_id;
 };
@@ -145,8 +140,8 @@ struct TypedInt {
 struct SpecificInterfaceIdAsRawType {
   using DiagnosticType = Diagnostics::TypeInfo<std::string>;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  SpecificInterfaceIdAsRawType(SemIR::SpecificInterfaceId specific_interface_id)
+  explicit(false) SpecificInterfaceIdAsRawType(
+      SemIR::SpecificInterfaceId specific_interface_id)
       : specific_interface_id(specific_interface_id) {}
 
   SemIR::SpecificInterfaceId specific_interface_id;

+ 1 - 2
toolchain/check/keyword_modifier_set.h

@@ -65,8 +65,7 @@ class KeywordModifierSet {
 
   // Support implicit conversion so that the difference with the member enum is
   // opaque.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr KeywordModifierSet(RawEnumType set) : set_(set) {}
+  explicit(false) constexpr KeywordModifierSet(RawEnumType set) : set_(set) {}
 
   // Adds entries to the set.
   auto Add(KeywordModifierSet set) -> void { set_ |= set.set_; }

+ 2 - 4
toolchain/diagnostics/format_providers.h

@@ -18,8 +18,7 @@ namespace Carbon::Diagnostics {
 //   `|`, with the true case first. the example would yield standard bool
 //   formatting.
 struct BoolAsSelect {
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  BoolAsSelect(bool value) : value(value) {}
+  explicit(false) BoolAsSelect(bool value) : value(value) {}
 
   bool value;
 };
@@ -47,8 +46,7 @@ struct BoolAsSelect {
 //
 // As another example, `{0:=1:is|:are}` is a way to handle plural-based output.
 struct IntAsSelect {
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  IntAsSelect(int value) : value(value) {}
+  explicit(false) IntAsSelect(int value) : value(value) {}
 
   int value;
 };

+ 2 - 2
toolchain/lex/lex.cpp

@@ -66,8 +66,8 @@ class [[clang::internal_linkage]] Lexer {
    public:
     // Consumes (and discard) a valid token to construct a result
     // indicating a token has been produced. Relies on implicit conversions.
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    LexResult(TokenIndex /*discarded_token*/) : LexResult(true) {}
+    explicit(false) LexResult(TokenIndex /*discarded_token*/)
+        : LexResult(true) {}
 
     // Returns a result indicating no token was produced.
     static auto NoMatch() -> LexResult { return LexResult(false); }

+ 1 - 2
toolchain/parse/node_category.h

@@ -64,8 +64,7 @@ class NodeCategory : public Printable<NodeCategory> {
 
   // Support implicit conversion so that the difference with the member enum is
   // opaque.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeCategory(RawEnumType value) : value_(value) {}
+  explicit(false) constexpr NodeCategory(RawEnumType value) : value_(value) {}
 
   // Returns true if there's a non-empty set intersection.
   constexpr auto HasAnyOf(NodeCategory other) const -> bool {

+ 13 - 16
toolchain/parse/node_ids.h

@@ -36,8 +36,7 @@ struct NodeId : public IdBase<NodeId> {
     CARBON_DCHECK(index < Max, "Index out of range: {0}", index);
   }
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeId(NoneNodeId /*none*/) : IdBase(NoneIndex) {}
+  explicit(false) constexpr NodeId(NoneNodeId /*none*/) : IdBase(NoneIndex) {}
 };
 
 // For looking up the type associated with a given id type.
@@ -57,8 +56,8 @@ struct NodeIdForKind : public NodeId {
     return NodeIdForKind(node_id);
   }
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeIdForKind(NoneNodeId /*none*/) : NodeId(NoneIndex) {}
+  explicit(false) constexpr NodeIdForKind(NoneNodeId /*none*/)
+      : NodeId(NoneIndex) {}
 
  private:
   // Private to prevent accidental explicit construction from an untyped
@@ -84,13 +83,13 @@ struct NodeIdInCategory : public NodeId {
   // Support conversion from `NodeIdForKind<Kind>` if Kind's category
   // overlaps with `Category`.
   template <const NodeKind& Kind>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  NodeIdInCategory(NodeIdForKind<Kind> node_id) : NodeId(node_id) {
+  explicit(false) NodeIdInCategory(NodeIdForKind<Kind> node_id)
+      : NodeId(node_id) {
     CARBON_CHECK(Kind.category().HasAnyOf(Category));
   }
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeIdInCategory(NoneNodeId /*none*/) : NodeId(NoneIndex) {}
+  explicit(false) constexpr NodeIdInCategory(NoneNodeId /*none*/)
+      : NodeId(NoneIndex) {}
 
  private:
   // Private to prevent accidental explicit construction from an untyped
@@ -142,16 +141,14 @@ struct NodeIdOneOf : public NodeId {
 
   template <const NodeKind& Kind>
     requires(Contains<NodeIdForKind<Kind>>)
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  NodeIdOneOf(NodeIdForKind<Kind> node_id) : NodeId(node_id) {}
+  explicit(false) NodeIdOneOf(NodeIdForKind<Kind> node_id) : NodeId(node_id) {}
 
   template <typename OtherNodeIdOneOf>
     requires(IsSubset<OtherNodeIdOneOf>)
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  NodeIdOneOf(OtherNodeIdOneOf node_id) : NodeId(node_id) {}
+  explicit(false) NodeIdOneOf(OtherNodeIdOneOf node_id) : NodeId(node_id) {}
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeIdOneOf(NoneNodeId /*none*/) : NodeId(NoneIndex) {}
+  explicit(false) constexpr NodeIdOneOf(NoneNodeId /*none*/)
+      : NodeId(NoneIndex) {}
 };
 
 using AnyClassDeclId =
@@ -179,8 +176,8 @@ using AnyRuntimeBindingPatternName =
 template <typename T>
 struct NodeIdNot : public NodeId {
   constexpr explicit NodeIdNot(NodeId node_id) : NodeId(node_id) {}
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr NodeIdNot(NoneNodeId /*none*/) : NodeId(NoneIndex) {}
+  explicit(false) constexpr NodeIdNot(NoneNodeId /*none*/)
+      : NodeId(NoneIndex) {}
 };
 
 // Note that the support for extracting these types using the `Tree::Extract*`

+ 1 - 2
toolchain/parse/precedence.h

@@ -131,8 +131,7 @@ class PrecedenceGroup {
 
   // We rely on implicit conversions via `int8_t` for enumerators defined in the
   // implementation.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  PrecedenceGroup(int8_t level) : level_(level) {}
+  explicit(false) PrecedenceGroup(int8_t level) : level_(level) {}
 
   // The precedence level.
   int8_t level_;

+ 12 - 20
toolchain/sem_ir/ids.h

@@ -100,8 +100,7 @@ class AbsoluteInstId : public InstId {
 
   // Support implicit conversion from InstId so that InstId and AbsoluteInstId
   // have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr AbsoluteInstId(InstId inst_id) : InstId(inst_id) {}
+  explicit(false) constexpr AbsoluteInstId(InstId inst_id) : InstId(inst_id) {}
 
   using InstId::InstId;
 };
@@ -124,8 +123,7 @@ class DestInstId : public InstId {
 
   // Support implicit conversion from InstId so that InstId and DestInstId
   // have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr DestInstId(InstId inst_id) : InstId(inst_id) {}
+  explicit(false) constexpr DestInstId(InstId inst_id) : InstId(inst_id) {}
 
   using InstId::InstId;
 };
@@ -149,8 +147,7 @@ class MetaInstId : public InstId {
 
   // Support implicit conversion from InstId so that InstId and MetaInstId
   // have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr MetaInstId(InstId inst_id) : InstId(inst_id) {}
+  explicit(false) constexpr MetaInstId(InstId inst_id) : InstId(inst_id) {}
 
   using InstId::InstId;
 };
@@ -698,8 +695,7 @@ constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(NoneIndex - 1);
 // `InstBlockId` (unlike for the singleton error `InstId`).
 class InstBlockIdOrError {
  public:
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  InstBlockIdOrError(InstBlockId inst_block_id)
+  explicit(false) InstBlockIdOrError(InstBlockId inst_block_id)
       : InstBlockIdOrError(inst_block_id, false) {}
 
   static auto MakeError() -> InstBlockIdOrError {
@@ -743,8 +739,7 @@ class AbsoluteInstBlockId : public InstBlockId {
  public:
   // Support implicit conversion from InstBlockId so that InstBlockId and
   // AbsoluteInstBlockId have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr AbsoluteInstBlockId(InstBlockId inst_block_id)
+  explicit(false) constexpr AbsoluteInstBlockId(InstBlockId inst_block_id)
       : InstBlockId(inst_block_id) {}
 
   using InstBlockId::InstBlockId;
@@ -759,8 +754,7 @@ class DeclInstBlockId : public InstBlockId {
  public:
   // Support implicit conversion from InstBlockId so that InstBlockId and
   // DeclInstBlockId have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr DeclInstBlockId(InstBlockId inst_block_id)
+  explicit(false) constexpr DeclInstBlockId(InstBlockId inst_block_id)
       : InstBlockId(inst_block_id) {}
 
   using InstBlockId::InstBlockId;
@@ -774,8 +768,8 @@ class LabelId : public InstBlockId {
  public:
   // Support implicit conversion from InstBlockId so that InstBlockId and
   // LabelId have the same interface.
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr LabelId(InstBlockId inst_block_id) : InstBlockId(inst_block_id) {}
+  explicit(false) constexpr LabelId(InstBlockId inst_block_id)
+      : InstBlockId(inst_block_id) {}
 
   using InstBlockId::InstBlockId;
 };
@@ -936,19 +930,17 @@ struct LocId : public IdBase<LocId> {
 
   using IdBase::IdBase;
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr LocId(ImportIRInstId import_ir_inst_id)
+  explicit(false) constexpr LocId(ImportIRInstId import_ir_inst_id)
       : IdBase(import_ir_inst_id.has_value()
                    ? FirstImportIRInstId - import_ir_inst_id.index
                    : NoneIndex) {}
 
   explicit constexpr LocId(InstId inst_id) : IdBase(inst_id.index) {}
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr LocId(Parse::NoneNodeId /*none*/) : IdBase(NoneIndex) {}
+  explicit(false) constexpr LocId(Parse::NoneNodeId /*none*/)
+      : IdBase(NoneIndex) {}
 
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr LocId(Parse::NodeId node_id)
+  explicit(false) constexpr LocId(Parse::NodeId node_id)
       : IdBase(FirstNodeId - node_id.index) {}
 
   // Forms an equivalent LocId for a desugared location. Prefer calling

+ 1 - 2
toolchain/sem_ir/inst.h

@@ -229,8 +229,7 @@ class Inst : public Printable<Inst> {
 
   template <typename TypedInst>
     requires Internal::InstLikeType<TypedInst>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  Inst(TypedInst typed_inst)
+  explicit(false) Inst(TypedInst typed_inst)
       // kind_ is always overwritten below.
       : kind_(),
         type_id_(TypeId::None),

+ 1 - 2
toolchain/sem_ir/type_iterator.h

@@ -210,8 +210,7 @@ class TypeIterator::Step {
   // explicitly first).
   template <typename T>
     requires std::constructible_from<Any, T>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  Step(T any) : any(any) {}
+  explicit(false) Step(T any) : any(any) {}
 
   Any any;
 };