Topic: Possible DR: operations viability on pointers to incomplete types


Author: rani_sharoni@hotmail.com ("Rani Sharoni")
Date: Wed, 10 Dec 2003 02:46:58 +0000 (UTC)
Raw View
Hello,

Consider the following code:

struct A { operator int() const;};
int operator+(void*, A);

struct B; // incomplete

void f(B* p, A a)
{
   int i = p + a; // ill-formed ???
}

I was surprise to find out that EDG and BCC compiled the code while VC and
GCC rejected it due to an ambiguity.

In case that EDG is right then this pathologic behavior can be exploited to
detect incomplete type (which IMO is dubious trait in ODR perspective).

I saw that 3.9/7 specify that such operation on incomplete type is
ill-formed but I didn't found sentence that explicitly says that the
appropriate build-in operator is not viable for overloading and I think that
there was no intention for this. Therefore I assume that it's merely a "bug"
in EDG and the clarifying DR is appropriate in this case that was probably
overlooked.

Any thoughts?

Thanks,
Rani



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Wed, 10 Dec 2003 18:23:11 +0000 (UTC)
Raw View
On Wed, 10 Dec 2003 02:46:58 +0000 (UTC), rani_sharoni@hotmail.com
("Rani Sharoni") wrote:

>Hello,
>
>Consider the following code:
>
>struct A { operator int() const;};
>int operator+(void*, A);
>
>struct B; // incomplete
>
>void f(B* p, A a)
>{
>   int i = p + a; // ill-formed ???
>}
>
>I was surprise to find out that EDG and BCC compiled the code while VC and
>GCC rejected it due to an ambiguity.
>
>In case that EDG is right then this pathologic behavior can be exploited to
>detect incomplete type (which IMO is dubious trait in ODR perspective).
>
>I saw that 3.9/7 specify that such operation on incomplete type is
>ill-formed but I didn't found sentence that explicitly says that the
>appropriate build-in operator is not viable for overloading and I think that
>there was no intention for this. Therefore I assume that it's merely a "bug"
>in EDG and the clarifying DR is appropriate in this case that was probably
>overlooked.

Well 13.6 para 1 says quote

"As described in 13.3.1.2, after a builtin operator is selected by
overload resolution the expression is subject to the requirements for
the builtin operator given in clause 5, and therefore to any additional
semantic constraints given there."  <end quote>

so you'd expect that the requirement of 5.7 para 1 for a complete type
would be applied after overload resolution and EDG is wrong in this case
as you suggest.

However, I don't understand why all of GCC, Comeau and VC7.1 give an
ambiguity whether the type is complete or otherwise  -  the call to the
user defined operator+ requires a standard conversion  (B* to void*) but
the call to the built in operator + requires a user defined conversion,
so why doesn't the non built in operator+ win here as per the example in
13.3.1.2 para 6.


BTW - since you mentioned partial ordering in your auto_ptr post Rani,
here's another example of Comeau/EDG and GCC disagreeing - GCC and VC7.1
say ambiguity but Comeau calls the second f1 in all cases.  I think this
is affected by a defect report which is supposed to resolve these cases
more clearly then the present standard.

#include <iostream>

template <typename T>
void f1( T v1 )
{
    std::cout << "aaaa";
}

template <typename T>
void f1( const T &v1 )
{
    std::cout << "bbbb";
}

int main()
{
    int a = 23;
    const int b = 24;
    f1(a);
    f1(b);
    f1(25);
}

Graeme

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rani_sharoni@hotmail.com ("Rani Sharoni")
Date: Wed, 10 Dec 2003 20:47:49 +0000 (UTC)
Raw View
Graeme Prentice wrote:
> On Wed, 10 Dec 2003 02:46:58 +0000 (UTC), rani_sharoni@hotmail.com
> ("Rani Sharoni") wrote:
>
>> Hello,
>>
>> Consider the following code:
>>
>> struct A { operator int() const;};
>> int operator+(void*, A);
>>
>> struct B; // incomplete
>>
>> void f(B* p, A a)
>> {
>>   int i = p + a; // ill-formed ???
>> }
>>
>> I was surprise to find out that EDG and BCC compiled the code while
>> VC and GCC rejected it due to an ambiguity.
>>
>> In case that EDG is right then this pathologic behavior can be
>> exploited to detect incomplete type (which IMO is dubious trait in
>> ODR perspective).
>>
>> I saw that 3.9/7 specify that such operation on incomplete type is
>> ill-formed but I didn't found sentence that explicitly says that the
>> appropriate build-in operator is not viable for overloading and I
>> think that there was no intention for this. Therefore I assume that
>> it's merely a "bug" in EDG and the clarifying DR is appropriate in
>> this case that was probably overlooked.
>
> Well 13.6 para 1 says quote
>
> "As described in 13.3.1.2, after a builtin operator is selected by
> overload resolution the expression is subject to the requirements for
> the builtin operator given in clause 5, and therefore to any
> additional semantic constraints given there."  <end quote>
>
> so you'd expect that the requirement of 5.7 para 1 for a complete type
> would be applied after overload resolution and EDG is wrong in this
> case
> as you suggest.
That's makes the suspicions that EDG is wrong almost certain but I wish that
someone from EDG will approve that suspicious.

> However, I don't understand why all of GCC, Comeau and VC7.1 give an
> ambiguity whether the type is complete or otherwise  -  the call to
> the user defined operator+ requires a standard conversion  (B* to void*)
> but  the call to the built in operator + requires a user defined
> conversion,  so why doesn't the non built in operator+ win here as per the
example
> in  13.3.1.2 para 6.
The ambiguity is deliberate. There are two candidates in this case:
int operator+(void*, A); // user-defined
B* operator+(B*, ptrdiff_t); // build-in

The operands types are B* and A which makes both operators candidate with
exact match and conversion for the *opposite* arguments and therefore there
is no best match according to 13.3.3/1 that states that the best viable
function should the as good for each arguments and better in at least one
(BTW - this is fundumantal different from overloading in java which is more
strict).

 > BTW - since you mentioned partial ordering in your auto_ptr post Rani,
> here's another example of Comeau/EDG and GCC disagreeing - GCC and
> VC7.1 say ambiguity but Comeau calls the second f1 in all cases.  I think
> this is affected by a defect report which is supposed to resolve these
> cases more clearly then the present standard.


template <typename T> long* f1( T ); // #1
template <typename T> char* f1( const T &); // #2

According to my humble knowledge about partial ordering the functions are
not ordered since #1 is not more specialized than #2. AFAIK DR #271 tries to
make them order and if it does then I'll be forced to revise my partial
ordering knowledge.

char arr[10];
char* x = f1(arr); // selects #2 with exact match

EDG selected #2 while GCC and VC found ambiguity. What a shame.

Lets take a good look at the candidates:
long* f1<char*>(char*);
char* f1<char[10]>(const char(&)[10]);

According to my intuitive capture of partial ordering - in case that the
functions are not ordered for one type (array type) then they are not
ordered at all.

Rani



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Thu, 11 Dec 2003 10:15:00 +0000 (UTC)
Raw View
On Wed, 10 Dec 2003 20:47:49 +0000 (UTC), rani_sharoni@hotmail.com
("Rani Sharoni") wrote:

[snip]

>That's makes the suspicions that EDG is wrong almost certain but I wish that
>someone from EDG will approve that suspicious.

I guess someone should report it to them  - it's probably not a big deal
but they do aim for meticulous compliance.


>
>The operands types are B* and A which makes both operators candidate with
>exact match and conversion for the *opposite* arguments and therefore there
>is no best match according to 13.3.3/1 that states that the best viable
>function should the as good for each arguments and better in at least one
>(BTW - this is fundumantal different from overloading in java which is more
>strict).

Thanks, I forgot that.

>
>template <typename T> long* f1( T ); // #1
>template <typename T> char* f1( const T &); // #2
>
>According to my humble knowledge about partial ordering the functions are
>not ordered since #1 is not more specialized than #2. AFAIK DR #271 tries to
>make them order and if it does then I'll be forced to revise my partial
>ordering knowledge.

I asked a question about this on here a while ago but no-one responded.
AFAICS, DR #214 drops references in P and A, after which it drops top
level CV qualifiers as well so should produce no ordering for the above
case  - but I could be wrong.


>
>char arr[10];
>char* x = f1(arr); // selects #2 with exact match
>
>EDG selected #2 while GCC and VC found ambiguity. What a shame.
>
>Lets take a good look at the candidates:
>long* f1<char*>(char*);
>char* f1<char[10]>(const char(&)[10]);
>
>According to my intuitive capture of partial ordering - in case that the
>functions are not ordered for one type (array type) then they are not
>ordered at all.

You've lost me slightly.  Argument deduction succeeds for both and
produces the specializations you list - the reference case "deduced A"
is allowed to be more CV qualified than A.  Overload resolution then
finds an identity conversion for the reference (the array argument binds
directly to the reference) and array to pointer conversion for the
other, which rank equally.  Partial ordering is then applied to #1 and
#2 and the partial ordering doesn't involve arrays  - so I'm unsure why
you say "the functions are not ordered for one type (array type)".
Partial ordering of a pair of template functions always gets the same
answer and doesn't involve any types from an actual call to the function
- I guess you know this, so I'm unsure what you mean.

Graeme

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rani_sharoni@hotmail.com ("Rani Sharoni")
Date: Fri, 12 Dec 2003 02:22:56 +0000 (UTC)
Raw View
Graeme Prentice wrote:
> On Wed, 10 Dec 2003 20:47:49 +0000 (UTC), rani_sharoni@hotmail.com
> ("Rani Sharoni") wrote:
>>
>> template <typename T> long* f1( T ); // #1
>> template <typename T> char* f1( const T &); // #2
>>
>> According to my humble knowledge about partial ordering the
>> functions are not ordered since #1 is not more specialized than #2.
>> AFAIK DR #271 tries to make them order and if it does then I'll be
>> forced to revise my partial ordering knowledge.
>
> I asked a question about this on here a while ago but no-one
> responded. AFAICS, DR #214 drops references in P and A, after which
> it drops top
> level CV qualifiers as well so should produce no ordering for the
> above
> case  - but I could be wrong.
>>
>> char arr[10];
>> char* x = f1(arr); // selects #2 with exact match
>>
>> EDG selected #2 while GCC and VC found ambiguity. What a shame.
>>
>> Lets take a good look at the candidates:
>> long* f1<char*>(char*);
>> char* f1<char[10]>(const char(&)[10]);
>>
>> According to my intuitive capture of partial ordering - in case that
>> the functions are not ordered for one type (array type) then they
>> are not ordered at all.

You are right, I forgot the fact that array to pointer conversions is also
an *exact match* and I verified that EDG rejects the following case:
char* f(char*); // #1
long* f(char(&)[10]); // #2
int*   f(char const(&)[10]); // #3

char arr[10];

long* p = f(arr); // more than one instance of overloaded (#1 and #2).

For some reason I had temporary feeling that identity match is better than
array to pointer conversion but I probably overlooked the historical reasons
for such behavior.
The above case is also vicious since when #1 is removed the ambiguity is
gone while when #2 is removed then #3 and #1 become ambiguous. From my
knowledge in mathematics that's "bad" ordering since its not transitive (#1
== #2 and #1 == #3 but #2 < #3) but historical (C arrays) reasons are
probably much stronger than my own personal intuition.

> You've lost me slightly.  Argument deduction succeeds for both and
> produces the specializations you list - the reference case "deduced A"
> is allowed to be more CV qualified than A.  Overload resolution then
> finds an identity conversion for the reference (the array argument
> binds directly to the reference) and array to pointer conversion for
> the
> other, which rank equally.  Partial ordering is then applied to #1 and
> #2 and the partial ordering doesn't involve arrays  - so I'm unsure
> why
> you say "the functions are not ordered for one type (array type)".
> Partial ordering of a pair of template functions always gets the same
> answer and doesn't involve any types from an actual call to the
> function
> - I guess you know this, so I'm unsure what you mean.

In this case EDG, VC and GCC are consistent regarding the ordering of the
functions templates that you showed.

Perhaps I'm blinded by the common example:
template<typename T> void f(T&);
template<typename T> void f(T const&);

Where for each operand X of type T for the second function specialization
will be void f<T>(const T&) there exists type U for which f<U>(U&)
specialization procedure the same argument type and indeed U="T const" is
such type. That's sub set, of types, ordering which is partial ordering.

Thanks for the clarifications, I'll revise my knowledge in partial ordering
of function templates.

Rani


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]