[cfe-dev] const_cast and p0388 (array boundloss becomes const_cast)

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Wed Apr 14 11:39:46 PDT 2021


On Wed, 14 Apr 2021 at 08:49, Nathan Sidwell via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> P0388
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0388r4.html
> Makes conversions between bounded-array and unbounded-array look like
> qualification conversions.  This means you can use const-cast to add
> array bounds (and implicitly lose bounds)
>

I think we changed the const_cast rules to disallow that. Here:

Modify 7.6.1.10 [expr.const.cast] ΒΆ3:

"For two similar types T1 and T2, a prvalue of type T1 may be explicitly
converted to the type T2 using a const_cast <ins>if, considering the
cv-decompositions ([conv.qual]) of both types, all Pi1 are the same as
Pi2</ins>."

A change in array bound would result in the Pi's differing between T1 and
T2, so a const_cast can't do that.

But, ConstCast has a cast-kind of CK_NoOp:
> AST/ExprCXX.h:
>    CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op,
>                     TypeSourceInfo *writtenTy, SourceLocation l,
>                     SourceLocation RParenLoc, SourceRange AngleBrackets)
>        : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, 0,
>                           /*HasFPFeatures*/ false, writtenTy, l, RParenLoc,
>                           AngleBrackets) {}
>
> That will no longer be true -- adding or removing bounds changes the
> type more than CK_NoOp permits.  This results in code emission assert
> failure when things like [4 x i32]* meets [0 x i32]*.
>
> so, should such constcasts generate non-ConstCast AST?, or should the
> ConstCast node sometimes not be CK_NoOp?  The latter seems better to me,
> but perhaps there's a different opinion?
>

Regardless of the above observation about const_cast, I think we do need to
think about the cast kind for array bound conversions, because implicit
conversions can now remove an array bound, and static_cast can now add one.
Seems like the choices are CK_NoOp, CK_BitCast, or something new. I don't
like using CK_BitCast for this, since that usually implies something more
violent is happening (and would cause problems for constant evaluation,
which generally allows pointer bitcasts).

CK_NoOp is really a misnomer, and should probably be renamed to something
that indicates what it actually models: a change in qualifiers. I think
that changing array bounds is notionally  the same kind of type change as
changing type qualifiers or 'noexcept' on a function type (even though in
IR it will result in a type change until the work to remove pointee types
is completed), so my inclination would be to call that a CK_NoOp too,
unless we have a reason not to -- and that's probably also easier because
it means we don't need to work out how to decompose an arbitrary
qualification conversion into a change of cv-qualifiers and a separate
change of array bounds. I think it should be relatively straightforward to
get CodeGen to insert bitcasts for CK_NoOp casts where necessary.

On the subject of constant evaluation, do we have clear rules on whether
things like this work:

constexpr int a[3][4] = {};
constexpr int (*p)[] = a;
constexpr int (*q)[12] = static_cast<int (*)[12]>(p);
constexpr int r = (*q)[5];

? I think that's probably valid up until the final line, which we should
reject for out-of-bounds array indexing because q points to an array of 4
ints. (Though it might be nicer if we could reject the incorrect array
bound in the static_cast.) I think that's the behavior we'll get by
modeling this as a CK_NoOp.

nathan
>
> --
> Nathan Sidwell
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20210414/177776cf/attachment.html>


More information about the cfe-dev mailing list