Three code snippets accepted by clang and rejected by g++

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Three code snippets accepted by clang and rejected by g++

Nicola Gigante
Hello.

While testing a recently written piece of code to see if it worked on linux
I found three differences between clang and g++ that make the first
to compile the code and the second to reject it. I'm talking about the
clang shipped with Xcode 5.1.1, I don't have a working trunk and my
machine is slow to compile, sorry.

Below the three issues:

1) transitive-friend.cpp
class A {
  friend class B;
  int v;
};

struct B {
  A a;
  friend int f(B b) {
     return b.a.v;
  }
};

Clang accept this code because
I access the private field of A in the scope of B
and B is a friend. g++ rejects it:

$ g++-4.9 -std=c++11 -fsyntax-only differences.cpp
differences.cpp: In function 'int f(B)':
differences.cpp:3:7: error: 'int A::v' is private
   int v;
       ^
differences.cpp:9:17: error: within this context
      return b.a.v;
                 ^

2) templatebase.cpp
template<typename T>
struct A {
   template<typename U>
   struct B {

   };

   struct C;
};

template<typename T>
struct A<T>::C : public A<T>::B<int> // public A<T>::template B<int>
{

};

Is the template keyword needed here? Note that if you move out
struct C so that it isn't a member of A anymore, clang correctly
says that I need the template keyword. g++ wants the keyword
in both cases:

$ g++-4.9 -std=c++11 -fsyntax-only templatebase.cpp
templatebase.cpp:12:36: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                                    ^
templatebase.cpp:12:31: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                               ^
templatebase.cpp:12:38: error: expected class-name before '{' token
 struct A<T>::C : public A<T>::B<int> {
                                      ^
3) tupleconstructor.cpp
#include <tuple>

std::tuple<int, int, int>
func() {
   return { 0, 1, 2 };
}

I don't know how to phrase the situation in standardese terms (is it list-initialization?).
It seems to me that clang picks the forwarding constructor, g++ the explicit initializer-list constructor.

$ g++-4.9 -std=c++11 -fsyntax-only tupleconstructor.cpp
tupleconstructor.cpp: In function 'std::tuple<int, int, int> func()':
tupleconstructor.cpp:5:21: error: converting to 'std::tuple<int, int, int>' from initializer list would use explicit constructor 'constexpr std::tuple< <template-parameter-1-1> >::tuple(_UElements&& ...) [with _UElements = {int, int, int}; <template-parameter-2-2> = void; _Elements = {int, int, int}]'
    return { 0, 1, 2 };
                     ^

In all these three cases, who is right? Are these bugs in clang?
In this case, should I make a separate bug report for each case, right? I've attached the single test cases

Greetings,
Nicola






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

templatebase.cpp (208 bytes) Download Attachment
transitive-friend.cpp (118 bytes) Download Attachment
tupleconstructor.cpp (84 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Nikola Smiljanic
I'd say the first one is a clang bug. Friends are not transitive, the problem is in the implementation of class.protected restriction inside CheckAccess function.

  EffectiveContext EC(S.CurContext);

Current context here is class B and that doesn't seem right, added John as he's the author.


On Mon, Aug 11, 2014 at 12:10 AM, Nicola Gigante <[hidden email]> wrote:
Hello.

While testing a recently written piece of code to see if it worked on linux
I found three differences between clang and g++ that make the first
to compile the code and the second to reject it. I'm talking about the
clang shipped with Xcode 5.1.1, I don't have a working trunk and my
machine is slow to compile, sorry.

Below the three issues:

1) transitive-friend.cpp
class A {
  friend class B;
  int v;
};

struct B {
  A a;
  friend int f(B b) {
     return b.a.v;
  }
};

Clang accept this code because
I access the private field of A in the scope of B
and B is a friend. g++ rejects it:

$ g++-4.9 -std=c++11 -fsyntax-only differences.cpp
differences.cpp: In function 'int f(B)':
differences.cpp:3:7: error: 'int A::v' is private
   int v;
       ^
differences.cpp:9:17: error: within this context
      return b.a.v;
                 ^

2) templatebase.cpp
template<typename T>
struct A {
   template<typename U>
   struct B {

   };

   struct C;
};

template<typename T>
struct A<T>::C : public A<T>::B<int> // public A<T>::template B<int>
{

};

Is the template keyword needed here? Note that if you move out
struct C so that it isn't a member of A anymore, clang correctly
says that I need the template keyword. g++ wants the keyword
in both cases:

$ g++-4.9 -std=c++11 -fsyntax-only templatebase.cpp
templatebase.cpp:12:36: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                                    ^
templatebase.cpp:12:31: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                               ^
templatebase.cpp:12:38: error: expected class-name before '{' token
 struct A<T>::C : public A<T>::B<int> {
                                      ^
3) tupleconstructor.cpp
#include <tuple>

std::tuple<int, int, int>
func() {
   return { 0, 1, 2 };
}

I don't know how to phrase the situation in standardese terms (is it list-initialization?).
It seems to me that clang picks the forwarding constructor, g++ the explicit initializer-list constructor.

$ g++-4.9 -std=c++11 -fsyntax-only tupleconstructor.cpp
tupleconstructor.cpp: In function 'std::tuple<int, int, int> func()':
tupleconstructor.cpp:5:21: error: converting to 'std::tuple<int, int, int>' from initializer list would use explicit constructor 'constexpr std::tuple< <template-parameter-1-1> >::tuple(_UElements&& ...) [with _UElements = {int, int, int}; <template-parameter-2-2> = void; _Elements = {int, int, int}]'
    return { 0, 1, 2 };
                     ^

In all these three cases, who is right? Are these bugs in clang?
In this case, should I make a separate bug report for each case, right? I've attached the single test cases

Greetings,
Nicola






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

John McCall
On Aug 10, 2014, at 5:26 PM, Nikola Smiljanic <[hidden email]> wrote:
> I'd say the first one is a clang bug.

I agree.  This is poor language design — access should really be granted to all lexically nested code, not just members — but it’s what we’ve got.

> Friends are not transitive, the problem is in the implementation of class.protected restriction inside CheckAccess function.
>
>   EffectiveContext EC(S.CurContext);
>
> Current context here is class B and that doesn't seem right, added John as he's the author.

That seems wrong.  Are you just speculating?  The current context should be the declaration of ‘int f(B)’ that’s nested within the class.

I believe the correct fix is to change the special case for friend functions in the EffectiveContext constructor, probably by walking to the semantic context instead of the lexical context.  That is, removing the special case completely.  However, presumably that special case was added for a reason.

John.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Ismail Pazarbasi
On Mon, Aug 11, 2014 at 10:31 PM, John McCall <[hidden email]> wrote:

> On Aug 10, 2014, at 5:26 PM, Nikola Smiljanic <[hidden email]> wrote:
>> I'd say the first one is a clang bug.
>
> I agree.  This is poor language design — access should really be granted to all lexically nested code, not just members — but it’s what we’ve got.
>
>> Friends are not transitive, the problem is in the implementation of class.protected restriction inside CheckAccess function.
>>
>>   EffectiveContext EC(S.CurContext);
>>
>> Current context here is class B and that doesn't seem right, added John as he's the author.
>
> That seems wrong.  Are you just speculating?  The current context should be the declaration of ‘int f(B)’ that’s nested within the class.
>
> I believe the correct fix is to change the special case for friend functions in the EffectiveContext constructor, probably by walking to the semantic context instead of the lexical context.  That is, removing the special case completely.  However, presumably that special case was added for a reason.
>
> John.
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

I've submitted a patch before, but it needed work, and I forgot about
it (after summer vacation).
Discussion: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130603/080940.html

Ismail

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Richard Smith
In reply to this post by Nicola Gigante
On Sun, Aug 10, 2014 at 7:10 AM, Nicola Gigante <[hidden email]> wrote:
Hello.

While testing a recently written piece of code to see if it worked on linux
I found three differences between clang and g++ that make the first
to compile the code and the second to reject it. I'm talking about the
clang shipped with Xcode 5.1.1, I don't have a working trunk and my
machine is slow to compile, sorry.

Below the three issues:

1) transitive-friend.cpp
class A {
  friend class B;
  int v;
};

struct B {
  A a;
  friend int f(B b) {
     return b.a.v;
  }
};

Clang accept this code because
I access the private field of A in the scope of B
and B is a friend. g++ rejects it:

$ g++-4.9 -std=c++11 -fsyntax-only differences.cpp
differences.cpp: In function 'int f(B)':
differences.cpp:3:7: error: 'int A::v' is private
   int v;
       ^
differences.cpp:9:17: error: within this context
      return b.a.v;
                 ^

Clang's behavior reflects the current intent of the C++ core working group. This is core issue 1699, and the current resolution to that is to treat everything that is lexically within a befriended entity as being befriended. GCC does not yet implement the resolution to core issue 1699 (which is reasonable, since it's not yet even resolved).

2) templatebase.cpp
template<typename T>
struct A {
   template<typename U>
   struct B {

   };

   struct C;
};

template<typename T>
struct A<T>::C : public A<T>::B<int> // public A<T>::template B<int>
{

};

Is the template keyword needed here?

Clang's behavior reflects the current intent of the C++ core working group. This is core issue 1710 (which Clang only partially follows); the template keyword is optional in this context.
 
Note that if you move out
struct C so that it isn't a member of A anymore, clang correctly
says that I need the template keyword. g++ wants the keyword
in both cases:

$ g++-4.9 -std=c++11 -fsyntax-only templatebase.cpp
templatebase.cpp:12:36: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                                    ^
templatebase.cpp:12:31: error: 'typename A<T>::B' names 'template<class T> template<class U> struct A<T>::B', which is not a type
 struct A<T>::C : public A<T>::B<int> {
                               ^
templatebase.cpp:12:38: error: expected class-name before '{' token
 struct A<T>::C : public A<T>::B<int> {
                                      ^
3) tupleconstructor.cpp
#include <tuple>

std::tuple<int, int, int>
func() {
   return { 0, 1, 2 };
}

I don't know how to phrase the situation in standardese terms (is it list-initialization?).
It seems to me that clang picks the forwarding constructor, g++ the explicit initializer-list constructor.

Is this a Clang versus GCC issue, or a libc++ versus libstdc++ issue? What does Clang say if you use -stdlib=libstdc++? I would not be surprised if this is a library DR.
 
$ g++-4.9 -std=c++11 -fsyntax-only tupleconstructor.cpp
tupleconstructor.cpp: In function 'std::tuple<int, int, int> func()':
tupleconstructor.cpp:5:21: error: converting to 'std::tuple<int, int, int>' from initializer list would use explicit constructor 'constexpr std::tuple< <template-parameter-1-1> >::tuple(_UElements&& ...) [with _UElements = {int, int, int}; <template-parameter-2-2> = void; _Elements = {int, int, int}]'
    return { 0, 1, 2 };
                     ^

In all these three cases, who is right? Are these bugs in clang?
In this case, should I make a separate bug report for each case, right? I've attached the single test cases

Greetings,
Nicola






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

John McCall
On Aug 11, 2014, at 2:49 PM, Richard Smith <[hidden email]> wrote:
On Sun, Aug 10, 2014 at 7:10 AM, Nicola Gigante <[hidden email]> wrote:
Hello.

While testing a recently written piece of code to see if it worked on linux
I found three differences between clang and g++ that make the first
to compile the code and the second to reject it. I'm talking about the
clang shipped with Xcode 5.1.1, I don't have a working trunk and my
machine is slow to compile, sorry.

Below the three issues:

1) transitive-friend.cpp
class A {
  friend class B;
  int v;
};

struct B {
  A a;
  friend int f(B b) {
     return b.a.v;
  }
};

Clang accept this code because
I access the private field of A in the scope of B
and B is a friend. g++ rejects it:

$ g++-4.9 -std=c++11 -fsyntax-only differences.cpp
differences.cpp: In function 'int f(B)':
differences.cpp:3:7: error: 'int A::v' is private
   int v;
       ^
differences.cpp:9:17: error: within this context
      return b.a.v;
                 ^

Clang's behavior reflects the current intent of the C++ core working group. This is core issue 1699, and the current resolution to that is to treat everything that is lexically within a befriended entity as being befriended. GCC does not yet implement the resolution to core issue 1699 (which is reasonable, since it's not yet even resolved).

Great, this is the best resolution.  There are many unfortunate corner cases not caught by the current wording, including nested classes within inline friend functions.

John.

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Renato Golin Linaro
In reply to this post by Richard Smith
On 11 August 2014 22:49, Richard Smith <[hidden email]> wrote:
> Clang's behavior reflects the current intent of the C++ core working group.
> This is core issue 1699, and the current resolution to that is to treat
> everything that is lexically within a befriended entity as being befriended.
> GCC does not yet implement the resolution to core issue 1699 (which is
> reasonable, since it's not yet even resolved).

Shouldn't Clang only implement core issues with a special "bleeding edge" flag?

cheers,
--renato
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Nicola Gigante

Il giorno 12/ago/2014, alle ore 12:07, Renato Golin <[hidden email]> ha scritto:

> On 11 August 2014 22:49, Richard Smith <[hidden email]> wrote:
>> Clang's behavior reflects the current intent of the C++ core working group.
>> This is core issue 1699, and the current resolution to that is to treat
>> everything that is lexically within a befriended entity as being befriended.
>> GCC does not yet implement the resolution to core issue 1699 (which is
>> reasonable, since it's not yet even resolved).
>
> Shouldn't Clang only implement core issues with a special "bleeding edge" flag?
>

Thanks everybody for your informative replies.
I was writing, just before Renato's message:
what about a set of warnings for compatibility issues that could arise by relying
on core issues being implemented by clang that other compilers could not have
implemented yet?

> cheers,
> --renato

Thanks,
Nicola
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Three code snippets accepted by clang and rejected by g++

Richard Smith
In reply to this post by Renato Golin Linaro
On Tue, Aug 12, 2014 at 3:07 AM, Renato Golin <[hidden email]> wrote:
On 11 August 2014 22:49, Richard Smith <[hidden email]> wrote:
> Clang's behavior reflects the current intent of the C++ core working group.
> This is core issue 1699, and the current resolution to that is to treat
> everything that is lexically within a befriended entity as being befriended.
> GCC does not yet implement the resolution to core issue 1699 (which is
> reasonable, since it's not yet even resolved).

Shouldn't Clang only implement core issues with a special "bleeding edge" flag?

No, I don't think so -- or at least, not as a general policy. These are bug fixes in the language, and it's not reasonable to expect us to maintain two different codepaths with and without the fix. In this particular case, Clang has (to my knowledge) never implemented anything other than the fixed version, long before the committee chose to make the fix.

There are a handful of core issues for which we do maintain old and new versions, controlled by the -std= flag, but those are weird and probably not a good idea. Likewise, there are some cases where we maintain two versions for compatibility with other compilers (notably, there are some of these under -fms-compatibility).

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev