cplusplus / CWG

Core Working Group
24 stars 7 forks source link

[temp.dep.type] p5 The lookup result for a qualified-name that is not dependent #357

Closed xmh0511 closed 1 year ago

xmh0511 commented 1 year ago

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

[basic.lookup.general] p1 says:

Unless otherwise specified, the program is ill-formed if no declarations are found.

The "otherwise specified" presumably refers to [temp.res.general] p1

If the name is dependent (as specified in [temp.dep]), it is looked up for each specialization (after substitution) because the lookup depends on a template parameter.

Consider this example:

template<class T>
struct A{
    void fun(){
        this->show();  // #1
    }
};

The name show is qualified-name and whose lookup context is A<T>, as per [temp.dep.type] p5, and is not a dependent name

A qualified name ([basic.lookup.qual]) is dependent if

  • [...]
  • its lookup context is dependent and is not the current instantiation, or

The lookup context is A<T> that is the current instantiation. So, the "otherwise specified" principle does not apply to this case. However, this example can be compiled by GCC, Clang and MSVC. See https://godbolt.org/z/GaPxobTTe.

So, which rule in the current standard supress [basic.lookup.general] p1? Is it [temp.dep.type] p6? However, that rule just intend to determine whether the name would be ambiguous(in both context).

Suggested Resolution

The implementations seem to not act as the as that defined in the standard.

jensmaurer commented 1 year ago

The program is ill-formed, no diagnostic required, per temp.res.general p6.1 ("no valid specialization can be generated").

xmh0511 commented 1 year ago

The program is ill-formed, no diagnostic required, per temp.res.general p6.1 ("no valid specialization can be generated").

However, [basic.lookup.general] p1 explicitly says: the program is ill-formed, which asks the diagnosis, anyway.

jensmaurer commented 1 year ago

IFNDR trumps ill-formed; see [intro.comliance.general] p2 and in particular the "otherwise" in bullet 2.3.

xmh0511 commented 1 year ago

IFNDR trumps ill-formed; see [intro.comliance.general] p2 and in particular the "otherwise" in bullet 2.3.

However, the program contains both of them(i.e. [basic.lookup.general] p1 and [temp.res.general] p6.1), it is not clear that [temp.res.general] p6.1 has a high priority to trump [basic.lookup.general] p1, that is, [temp.res.general] p6.1 is the "otherwise part" mentioned by [basic.lookup.general] p1. Moreover, the "if" and "otherwise" in [intro.compliance.general] p2 does not mean that they state a mutual exclusion relationship to apply for the same construct.

IFNDR trumps ill-formed

If the program obeyed this meaning, the following example wouldn't emit a diagnosis

template<class T>
struct A{
   void show(){
       this->fun();  // #1
   }
};
int main(){
    void* p = 1; // #2
}

The program contains IFNDR(at #1) and ill-formed(at #2), according to [intro.comliance.general] p2, IFNDR trumps ill-formed, the program wouldn't emit an error for the construct at #2.

The wording should be phrased as

For the same construct, if the construct contains a violation of a rule for which no diagnostic is required...

Otherwise...

this may be correct to convey the intent, I think. In other words, for the same construct in a program, IFNDR trumps ill-formed.

languagelawyer commented 1 year ago

IFNDR trumps ill-formed, the program wouldn't emit an error.

How does this follow? Per (2.3), «this document places no requirement on implementations with respect to that program», so an implementation can do anything, including emitting an error.

xmh0511 commented 1 year ago

IFNDR trumps ill-formed, the program wouldn't emit an error.

How does this follow? Per (2.3), «this document places no requirement on implementations with respect to that program», so an implementation can do anything, including emitting an error.

See the last example, do you mean the implementation may choose not to emit an error for #2?

jensmaurer commented 1 year ago

Absolutely.

Once you have a program with #1, the behavior of the compiler (or the entire program) is no longer governed by the rules of the standard. Note that "no diagnostic required" means exactly that: No diagnostic is required, but there is no requirement that diagnostics are forbidden. (In fact, an implementation can issue diagnostics for a well-formed program, too; those are usually called "warnings".)

I'd also like to point out that IFNDR situations are those that are hard to detect, in general, and thus it would be too burdensome if implementations were required to issue a diagnostic for such cases.

xmh0511 commented 1 year ago

Confirming that, the implementation can choose to not emit an error for the ill-formed construct at #2 due to the IFNDR at #1, in other words, IFNDR trumps ill-formed in any case.