This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Add `explicit` to a bunch of private detail ctors.
ClosedPublic

Authored by Quuxplusone on Feb 15 2022, 2:39 PM.

Details

Summary
Notably the following ctors remain non-explicit because they
are used as implicit conversions in too many places:
* __debug_less(_Compare&)
* __map_iterator(_TreeIterator)
* __map_const_iterator(_TreeIterator)
* __hash_map_iterator(_HashIterator)
* __hash_map_const_iterator(_HashIterator)

This has been on my to-do list for a while, just for general code cleanliness. This was not done with any mechanical assistance (e.g. a compiler warning for non-explicit ctors); it was just me knowing about certain ctors for a long time (e.g. __bit_reference), and then brainstorming or randomly happening across some others.

Oddly, only Clang (not GCC or MSVC) thinks that this change has beneficial effects on overload resolution. I'm not sure who's correct here, but, C++ being C++, I would guess that GCC and MSVC are correct and Clang is wrong. https://godbolt.org/z/K76sr5MG9

Diff Detail

Event Timeline

Quuxplusone requested review of this revision.Feb 15 2022, 2:39 PM
Quuxplusone created this revision.
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald TranscriptFeb 15 2022, 2:39 PM
ldionne requested changes to this revision.Feb 16 2022, 6:14 AM
ldionne added a subscriber: philnik.

LGTM in essence, but the patch itself has a few mistakes (I think).

libcxx/include/__memory/compressed_pair.h
47

This looks like a merge conflict to me -- you seem to have undone part of a recent patch by @philnik. Reintroducing INLINE_VISIBILITY and changing the template parameters.

This revision now requires changes to proceed.Feb 16 2022, 6:14 AM
Quuxplusone edited the summary of this revision. (Show Details)

Fix merge conflict; add __deque_iterator and a few more.

Quuxplusone marked an inline comment as done.Feb 16 2022, 12:00 PM
Mordante accepted this revision as: Mordante.Feb 21 2022, 10:51 AM

LGTM!

libcxx/include/__debug
144

Just curious, but is there a good reason to make a default constructor explicit?

libcxx/include/__debug
144

Just the usual: it prevents implicit conversions.(*)

  • explicit Foo(int, int) prevents void f(Foo); f({1,1});
  • explicit Foo() prevents void f(Foo); f({});

My personal rule is "Make every ctor explicit unless you intend it to be called implicitly (which should be rare because implicit conversions are confusing)." The exceptions of course are the copy and move ctors, because we do intend them to be called implicitly all over the place.

(* - pedantic note: the "conversion" from a braced initializer list is not technically a conversion, because the braced initializer list doesn't have a type to begin with. But it's the same idea, both to a human who thinks of {1,1} as "a pair of ints" and to the compiler who thinks of it as a context requiring a non-explicit ctor.)

ldionne accepted this revision.Mar 1 2022, 10:35 AM
This revision is now accepted and ready to land.Mar 1 2022, 10:35 AM