Date: Sat, 20 Jan 2024 04:22:52 +0000
Let me analyze these cases (except for the definition).
> * https://wg21.link/basic.def.odr#14.5.1.1
Looks a bit strange. It seems to me that the requirements should be either strengthened or relaxed.
> * https://wg21.link/basic.types.general#10
> * https://wg21.link/expr.prim.lambda.closure#example-3
NonLiteral is just a non-normative name in an example.
> * https://wg21.link/expr.prim.lambda.capture#12
The requirements seems insufficient. We also need to specify that copy construction of such a member is a constant subexpression whenever expected (the exact wording may be lengthy).
> * https://wg21.link/expr.const#2.2
The mentioning looks normatively redundant to me.
> * https://wg21.link/dcl.constexpr#6
> * https://wg21.link/expr.const#5.9.2
> * https://wg21.link/expr.const#5.16
> * https://wg21.link/expr.const#12
I originally thought that these were redundant. But I was wrong since `struct X {}; constexpr X x = x;` is valid since C++11 - and a non-constexpr default constructor should have no effects here.
> * https://wg21.link/expr.const#4.7
The type requirements should be consistent with constexpr objects (see above).
> * https://wg21.link/expr.const#7
This is interesting. Without requirements on literal types we can dynamically allocate arrays for shared_ptr in constant evaluation, and implementations already accept this (https://godbolt.org/z/Y56KhjdhK).
> * https://wg21.link/temp.param#7.3
Perhaps structural class types should be specified in a more general way.
> * https://wg21.link/concept.swappable#2.3.1
> If the type wasn't a literal type but all of `E1 = std::move(E2); E2 = std::move(E1); T t1(std::move(E1)); T t2(std::move(E2));` were constant expressions, what is the harm in allowing it to be a constant expression?
Hmm, such a case seems made possible in C++23 per P2448R2. GCC/libstdc++ is already accepting it (https://godbolt.org/z/KPEzWh6Yq). I'm trying to submit an LWG issue for this.
> * https://wg21.link/complex.numbers.general#2
It's redundant to mention literal type here, since constexpr constructors are explicitly specified.
> * https://wg21.link/zombie.names#1.25
> * https://wg21.link/zombie.names#1.26
> * https://wg21.link/diff.cpp17.depr#7
No removal should be made as these contents are indicating removals themselves (see P0619R4).
Conclusion:
It seems that the definition of "literal type" was broken at first, and we should specify some stuffs in a more proper way.
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of Mital Ashok via Std-Proposals <std-proposals_at_[hidden]>
Sent: Friday, January 19, 2024 21:36
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Cc: Mital Ashok <mital_at_[hidden]>
Subject: [std-proposals] Do we still need literal types?
There are exactly 17 paragraphs in the standard referring to literal types:
* https://wg21.link/basic.def.odr#14.5.1.1
* https://wg21.link/basic.types.general#10
* https://wg21.link/expr.prim.lambda.closure#example-3
* https://wg21.link/expr.prim.lambda.capture#12
* https://wg21.link/expr.const#2.2
* https://wg21.link/expr.const#4.7
* https://wg21.link/expr.const#5.9.2
* https://wg21.link/expr.const#5.16
* https://wg21.link/expr.const#7
* https://wg21.link/expr.const#12
* https://wg21.link/dcl.constexpr#6
* https://wg21.link/temp.param#7.3
* https://wg21.link/zombie.names#1.25
* https://wg21.link/zombie.names#1.26
* https://wg21.link/concept.swappable#2.3.1
* https://wg21.link/complex.numbers.general#2
* https://wg21.link/diff.cpp17.depr#7
Some of these are just unnecessarily qualified as literal types.
For example, [concept.swappable] doesn't need to mention literal
types. If the type wasn't a literal type but all of `E1 =
std::move(E2); E2 = std::move(E1); T t1(std::move(E1)); T
t2(std::move(E2));` were constant expressions, what is the harm in
allowing it to be a constant expression?
Likewise for [expr.const]: If a type is not literal but is being used
in a way that would be a constant expression otherwise, why disallow
it?
I'm assuming the original rationale for literal types in C++11 was to
restrict it so much that compilers would be able to implement
constexpr functions. But nowadays the restrictions are so broad that
basically any type can be accepted. For example, this is a literal
type:
struct Literal { constexpr LiteralType(int) = delete; };
And this is not:
struct NotLiteral { constexpr NotLiteral(const NotLiteral&) = default; };
constexpr NotLiteral f = f; // (The *only* reason this doesn't
work is that `NotLiteral` isn't a literal type)
This goes against the note given in its definition: "A literal type is
one for which it might be possible to create an object within a
constant expression.".
It also excludes extension types and is apparently difficult to get
right, because the following is accepted:
struct ActuallyNotLiteral { ActuallyNotLiteral();
ActuallyNotLiteral(const ActuallyNotLiteral&); };
union AccidentallyLiteral {
ActuallyNotLiteral m;
constexpr AccidentallyLiteral(int) = delete;
};
// AccidentallyLiteral is supposedly a literal type
because CWG2598's resolution now no longer asks for a variant member
to have a literal type if there is a constexpr constructor, where it
did with the prior wording.
I propose getting rid of "literal type" entirely. This involves nixing
[basic.types.general]p10 entirely and removing mentions to literal
types (e.g., [basic.def.odr]p(14.5.1.1) goes from "has the same
literal type" to "has the same type" and removing after ", except ..."
in [expr.const]p(2.2))
> * https://wg21.link/basic.def.odr#14.5.1.1
Looks a bit strange. It seems to me that the requirements should be either strengthened or relaxed.
> * https://wg21.link/basic.types.general#10
> * https://wg21.link/expr.prim.lambda.closure#example-3
NonLiteral is just a non-normative name in an example.
> * https://wg21.link/expr.prim.lambda.capture#12
The requirements seems insufficient. We also need to specify that copy construction of such a member is a constant subexpression whenever expected (the exact wording may be lengthy).
> * https://wg21.link/expr.const#2.2
The mentioning looks normatively redundant to me.
> * https://wg21.link/dcl.constexpr#6
> * https://wg21.link/expr.const#5.9.2
> * https://wg21.link/expr.const#5.16
> * https://wg21.link/expr.const#12
I originally thought that these were redundant. But I was wrong since `struct X {}; constexpr X x = x;` is valid since C++11 - and a non-constexpr default constructor should have no effects here.
> * https://wg21.link/expr.const#4.7
The type requirements should be consistent with constexpr objects (see above).
> * https://wg21.link/expr.const#7
This is interesting. Without requirements on literal types we can dynamically allocate arrays for shared_ptr in constant evaluation, and implementations already accept this (https://godbolt.org/z/Y56KhjdhK).
> * https://wg21.link/temp.param#7.3
Perhaps structural class types should be specified in a more general way.
> * https://wg21.link/concept.swappable#2.3.1
> If the type wasn't a literal type but all of `E1 = std::move(E2); E2 = std::move(E1); T t1(std::move(E1)); T t2(std::move(E2));` were constant expressions, what is the harm in allowing it to be a constant expression?
Hmm, such a case seems made possible in C++23 per P2448R2. GCC/libstdc++ is already accepting it (https://godbolt.org/z/KPEzWh6Yq). I'm trying to submit an LWG issue for this.
> * https://wg21.link/complex.numbers.general#2
It's redundant to mention literal type here, since constexpr constructors are explicitly specified.
> * https://wg21.link/zombie.names#1.25
> * https://wg21.link/zombie.names#1.26
> * https://wg21.link/diff.cpp17.depr#7
No removal should be made as these contents are indicating removals themselves (see P0619R4).
Conclusion:
It seems that the definition of "literal type" was broken at first, and we should specify some stuffs in a more proper way.
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of Mital Ashok via Std-Proposals <std-proposals_at_[hidden]>
Sent: Friday, January 19, 2024 21:36
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Cc: Mital Ashok <mital_at_[hidden]>
Subject: [std-proposals] Do we still need literal types?
There are exactly 17 paragraphs in the standard referring to literal types:
* https://wg21.link/basic.def.odr#14.5.1.1
* https://wg21.link/basic.types.general#10
* https://wg21.link/expr.prim.lambda.closure#example-3
* https://wg21.link/expr.prim.lambda.capture#12
* https://wg21.link/expr.const#2.2
* https://wg21.link/expr.const#4.7
* https://wg21.link/expr.const#5.9.2
* https://wg21.link/expr.const#5.16
* https://wg21.link/expr.const#7
* https://wg21.link/expr.const#12
* https://wg21.link/dcl.constexpr#6
* https://wg21.link/temp.param#7.3
* https://wg21.link/zombie.names#1.25
* https://wg21.link/zombie.names#1.26
* https://wg21.link/concept.swappable#2.3.1
* https://wg21.link/complex.numbers.general#2
* https://wg21.link/diff.cpp17.depr#7
Some of these are just unnecessarily qualified as literal types.
For example, [concept.swappable] doesn't need to mention literal
types. If the type wasn't a literal type but all of `E1 =
std::move(E2); E2 = std::move(E1); T t1(std::move(E1)); T
t2(std::move(E2));` were constant expressions, what is the harm in
allowing it to be a constant expression?
Likewise for [expr.const]: If a type is not literal but is being used
in a way that would be a constant expression otherwise, why disallow
it?
I'm assuming the original rationale for literal types in C++11 was to
restrict it so much that compilers would be able to implement
constexpr functions. But nowadays the restrictions are so broad that
basically any type can be accepted. For example, this is a literal
type:
struct Literal { constexpr LiteralType(int) = delete; };
And this is not:
struct NotLiteral { constexpr NotLiteral(const NotLiteral&) = default; };
constexpr NotLiteral f = f; // (The *only* reason this doesn't
work is that `NotLiteral` isn't a literal type)
This goes against the note given in its definition: "A literal type is
one for which it might be possible to create an object within a
constant expression.".
It also excludes extension types and is apparently difficult to get
right, because the following is accepted:
struct ActuallyNotLiteral { ActuallyNotLiteral();
ActuallyNotLiteral(const ActuallyNotLiteral&); };
union AccidentallyLiteral {
ActuallyNotLiteral m;
constexpr AccidentallyLiteral(int) = delete;
};
// AccidentallyLiteral is supposedly a literal type
because CWG2598's resolution now no longer asks for a variant member
to have a literal type if there is a constexpr constructor, where it
did with the prior wording.
I propose getting rid of "literal type" entirely. This involves nixing
[basic.types.general]p10 entirely and removing mentions to literal
types (e.g., [basic.def.odr]p(14.5.1.1) goes from "has the same
literal type" to "has the same type" and removing after ", except ..."
in [expr.const]p(2.2))
-- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2024-01-20 04:22:58