Skip to content

[expr.unary.op] [expr.cast] Unspecified behavior with incomplete types #990

Description

@Halalaluyafail3

Full name of submitter (unless configured in github; will be published with the issue): Jay Ghiron

Reference (section label): [expr.unary.op]/5 [expr.cast]/5

Issue description:

[expr.unary.op]/5 is intended to allow implementations to use unary operator& in examples such as:

extern struct S s;
void foo(){
    auto p=&s;
}
struct S{
    void operator&(){}
};
S s;

This is invalid if unary operator& is used instead of the built in address of operator. However, consider the following variation:

extern struct S s;
auto foo(){
    return&s;
}
template<typename>struct T;
template<>struct T<void>{};
template<>struct T<S*>{
    void operator&(){}
};
struct S:T<decltype(foo())>{};
S s;

If the built in address of operator is used, then decltype(foo()) is S* which means that S has a unary operator& that could be used. Therefore it appears that unary operator& might be used instead, but if that were used then decltype(foo()) is void which means that S does not have a unary operator& that could be used. [expr.cast]/5 has the same situation, but it is a bit more complicated:

struct A{};
extern struct B b;
constexpr A*bar(){
    return(A*)&b;
}
template<decltype(^^::)n>constexpr static bool t=requires{(char(*)[(void([:n:]::bar()),1)])0;};
template<bool>struct C{};
template<>struct C<false>:A{};
struct B:C<t<^^::>>{};
B b;

If the reinterpret_cast interpretation is used then bar() is not a valid constant expression hence t<^^::> is false and B indirectly inherits A. Therefore it appears that the static_cast interpretation might be used instead, but if that were used then bar() would be a valid constant expression hence t<^^::> is true and B does not inherit A. What was the intent in these situations? It seems unintended that by using this type of program to have a class definition depend upon itself it can effectively force one interpretation. There are also some other issues with these paragraphs:

//TU 1
extern struct D d;
extern struct E e;
void baz(){
    auto x=&d;
    auto y=&e;
}
struct E{
    void operator&()&&;
};
E e;
void qux(){
    auto z=&e;
}

//TU 2
struct D{
    void operator&(){}
};
D d;

The wording in [expr.unary.op]/5 does not seem to make an exception for the definition being in a different translation unit though I do not think it was intended for different translation units to be considered. That is, it would not make sense for the declaration of x to be possibly invalid. Additionally, the wording does not seem to require that overload resolution would actually pick the unary operator& though I do not think that was the intent. That is, it would not make sense for the declaration of y to be possibly invalid while the declaration of z is always valid.

struct F;
extern struct G g;
constexpr F*idk(){
    return(F*)&g;
}
struct F{};
struct G{};
G g;

The wording in [expr.cast]/5 says it unspecified whether the static_cast interpretation or the reinterpret_cast interpretation is used even if an inheritance relationship is later established, but it does not clarify any further if no inheritance relationship is established or even if the types are never completed at all. I do not think it was intended that this should be unspecified, perhaps it can be inferred from the fact that the static_cast interpretation would never actually be valid. The previous example that defines A assumes that the static_cast interpretation will never be chosen if an inheritance relationship is not established. A resolution to this should consider whether the static_cast interpretation can be used if both types are always incomplete in the translation unit where the cast is performed, then both are completed in another translation unit with an inheritance relationship.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions