Weird diagnostic about non-type template argument

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

Weird diagnostic about non-type template argument

Abramo Bagnara-2

The following typescript show the issue:

$ cat t.cc

template <int *ptr>
struct S1 { };

template <bool b>
struct S2 { };

int v1;

S1<(&v1)> x;
S2<(2>2)> y;
$ clang -c t.cc
t.cc:10:4: error: non-type template argument cannot be surrounded by
parentheses
S1<(&v1)> x;
   ^~~~~
1 error generated.

My notes:

1) in my opinion the diagnostic is due to a needless too strong
interpretation of the standard:

- comeau and intel does not mark this as an error

- gcc seems to mark this as an error due to some bug (the diagnostic  is
very weird)

2) also if there is disagreement about 1 I don't see the reason to
generate an error instead of a warning

3) that apart the diagnostic message is misleading: non-type template
argument might (and sometimes should, see the following line in source)
be surrounded by parentheses

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

Re: Weird diagnostic about non-type template argument

Chandler Carruth
On Mon, Aug 16, 2010 at 12:31 AM, Abramo Bagnara <[hidden email]> wrote:

The following typescript show the issue:

$ cat t.cc

template <int *ptr>
struct S1 { };

template <bool b>
struct S2 { };

int v1;

S1<(&v1)> x;
S2<(2>2)> y;
$ clang -c t.cc
t.cc:10:4: error: non-type template argument cannot be surrounded by
parentheses
S1<(&v1)> x;
  ^~~~~
1 error generated.

My notes:

1) in my opinion the diagnostic is due to a needless too strong
interpretation of the standard:

- comeau and intel does not mark this as an error

- gcc seems to mark this as an error due to some bug (the diagnostic  is
very weird)

The standard seems really really clear here -- the argument is *not* an expression, it's an address. You're only provided one mechanism for writing an address in this context: '& id-expression', with the '&' being optional in certain cases. You can't even write '0' here. I think it's actually useful to preclude parentheses as they make this look like an expression, which it simply is not. You can't write '(&foo + sizeof(int))' to advance past one element of an int array either.

2) also if there is disagreement about 1 I don't see the reason to
generate an error instead of a warning

A ExtWarn seems not implausible here, but I'm not sure why supporting this is important.
 
3) that apart the diagnostic message is misleading: non-type template
argument might (and sometimes should, see the following line in source)
be surrounded by parentheses

The second line is a completely different non-type template argument: an integral constant-expression. There are no parentheses around the template argument, there are parentheses as part of the constant-expression, which allows parentheses among many other constructs. It is certainly unfortunate that there is no way to write a '>' in an ICE without parentheses, but I don't think that artifact necessarily warrants allowing parentheses for all template arguments, or even for all non-type template arguments...

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

Re: Weird diagnostic about non-type template argument

Abramo Bagnara-2
Il 16/08/2010 10:22, Chandler Carruth ha scritto:

> On Mon, Aug 16, 2010 at 12:31 AM, Abramo Bagnara
> <[hidden email] <mailto:[hidden email]>> wrote:
>
>
>     The following typescript show the issue:
>
>     $ cat t.cc
>
>     template <int *ptr>
>     struct S1 { };
>
>     template <bool b>
>     struct S2 { };
>
>     int v1;
>
>     S1<(&v1)> x;
>     S2<(2>2)> y;
>     $ clang -c t.cc
>     t.cc:10:4: error: non-type template argument cannot be surrounded by
>     parentheses
>     S1<(&v1)> x;
>       ^~~~~
>     1 error generated.
>
>     My notes:
>
>     1) in my opinion the diagnostic is due to a needless too strong
>     interpretation of the standard:
>
>     - comeau and intel does not mark this as an error
>
>     - gcc seems to mark this as an error due to some bug (the diagnostic  is
>     very weird)
>
>
> The standard seems really really clear here -- the argument is *not* an
> expression, it's an address. You're only provided one mechanism for
> writing an address in this context: '& id-expression', with the '&'
> being optional in certain cases. You can't even write '0' here. I think
> it's actually useful to preclude parentheses as they make this look like
> an expression, which it simply is not. You can't write '(&foo +
> sizeof(int))' to advance past one element of an int array either.
>

Hmmm... perhaps not so clear...

If you look at standard grammar, you read this:

template-argument:
  constant-expression
  type-id
  id-expression

Of course S1<v1> is in the 'id-expression' case, but both S1<&v1> and
S1<(&v1)> are in 'constant-expression' case.

Don't you think that if the intention was to inhibit parenthesis use the
standard would have been written as:

template-argument:
  constant-expression
  type-id
  '&'opt id-expression

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

Re: Weird diagnostic about non-type template argument

Chandler Carruth
On Mon, Aug 16, 2010 at 1:42 AM, Abramo Bagnara <[hidden email]> wrote:
Il 16/08/2010 10:22, Chandler Carruth ha scritto:
> On Mon, Aug 16, 2010 at 12:31 AM, Abramo Bagnara
> <[hidden email] <mailto:[hidden email]>> wrote:
>
>
>     The following typescript show the issue:
>
>     $ cat t.cc
>
>     template <int *ptr>
>     struct S1 { };
>
>     template <bool b>
>     struct S2 { };
>
>     int v1;
>
>     S1<(&v1)> x;
>     S2<(2>2)> y;
>     $ clang -c t.cc
>     t.cc:10:4: error: non-type template argument cannot be surrounded by
>     parentheses
>     S1<(&v1)> x;
>       ^~~~~
>     1 error generated.
>
>     My notes:
>
>     1) in my opinion the diagnostic is due to a needless too strong
>     interpretation of the standard:
>
>     - comeau and intel does not mark this as an error
>
>     - gcc seems to mark this as an error due to some bug (the diagnostic  is
>     very weird)
>
>
> The standard seems really really clear here -- the argument is *not* an
> expression, it's an address. You're only provided one mechanism for
> writing an address in this context: '& id-expression', with the '&'
> being optional in certain cases. You can't even write '0' here. I think
> it's actually useful to preclude parentheses as they make this look like
> an expression, which it simply is not. You can't write '(&foo +
> sizeof(int))' to advance past one element of an int array either.
>

Hmmm... perhaps not so clear...

If you look at standard grammar, you read this:

template-argument:
 constant-expression
 type-id
 id-expression

Of course S1<v1> is in the 'id-expression' case, but both S1<&v1> and
S1<(&v1)> are in 'constant-expression' case.

Don't you think that if the intention was to inhibit parenthesis use the
standard would have been written as:

template-argument:
 constant-expression
 type-id
 '&'opt id-expression

?

No, because the general grammar is not meant to be normative. You can't read one piece of grammar and know what is or is not a valid program. In this case, you're citing text from 14.2 (C++0x rather than '03, but I'll stick with '0x for now -- if anything '03 is *more* restrictive here!), but the detail of what goes into a template argument is more fully explained by 14.3.2 [template.arg.nontype]. Here, it clearly lists what constant-expression arguments are allowed:
— an integral constant expression (including a constant expression of literal class type that can be used as an integral constant expression as described in 5.19); or
— a constant expression that evaluates to a null pointer value (4.10); or
— a constant expression that evaluates to a null member pointer value (4.11); or

That's it. The only way you get an address of an actual object is:
— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference

This is very clear that it is *restricting* the syntax allowed to represent the address of an object. It seems to specifically preclude pointer arithmetic and other expressions on the address.


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

Re: Weird diagnostic about non-type template argument

Chandler Carruth
On Mon, Aug 16, 2010 at 1:55 AM, Chandler Carruth <[hidden email]> wrote:
On Mon, Aug 16, 2010 at 1:42 AM, Abramo Bagnara <[hidden email]> wrote:
Il 16/08/2010 10:22, Chandler Carruth ha scritto:
> On Mon, Aug 16, 2010 at 12:31 AM, Abramo Bagnara
> <[hidden email] <mailto:[hidden email]>> wrote:
>
>
>     The following typescript show the issue:
>
>     $ cat t.cc
>
>     template <int *ptr>
>     struct S1 { };
>
>     template <bool b>
>     struct S2 { };
>
>     int v1;
>
>     S1<(&v1)> x;
>     S2<(2>2)> y;
>     $ clang -c t.cc
>     t.cc:10:4: error: non-type template argument cannot be surrounded by
>     parentheses
>     S1<(&v1)> x;
>       ^~~~~
>     1 error generated.
>
>     My notes:
>
>     1) in my opinion the diagnostic is due to a needless too strong
>     interpretation of the standard:
>
>     - comeau and intel does not mark this as an error
>
>     - gcc seems to mark this as an error due to some bug (the diagnostic  is
>     very weird)
>
>
> The standard seems really really clear here -- the argument is *not* an
> expression, it's an address. You're only provided one mechanism for
> writing an address in this context: '& id-expression', with the '&'
> being optional in certain cases. You can't even write '0' here. I think
> it's actually useful to preclude parentheses as they make this look like
> an expression, which it simply is not. You can't write '(&foo +
> sizeof(int))' to advance past one element of an int array either.
>

Hmmm... perhaps not so clear...

If you look at standard grammar, you read this:

template-argument:
 constant-expression
 type-id
 id-expression

Of course S1<v1> is in the 'id-expression' case, but both S1<&v1> and
S1<(&v1)> are in 'constant-expression' case.

Don't you think that if the intention was to inhibit parenthesis use the
standard would have been written as:

template-argument:
 constant-expression
 type-id
 '&'opt id-expression

?

No, because the general grammar is not meant to be normative. You can't read one piece of grammar and know what is or is not a valid program. In this case, you're citing text from 14.2 (C++0x rather than '03, but I'll stick with '0x for now -- if anything '03 is *more* restrictive here!), but the detail of what goes into a template argument is more fully explained by 14.3.2 [template.arg.nontype]. Here, it clearly lists what constant-expression arguments are allowed:
— an integral constant expression (including a constant expression of literal class type that can be used as an integral constant expression as described in 5.19); or
— a constant expression that evaluates to a null pointer value (4.10); or
— a constant expression that evaluates to a null member pointer value (4.11); or

For reference, these two are what are missing in C++03. In '03 you can't even write '0' as a template argument for a pointer non-type template argument. In '0x, you can, you can even write a complex const-expr to do so. But you can't make it evaluate to any other pointer value, for that you have to use the rule below.
 

That's it. The only way you get an address of an actual object is:
— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference

This is very clear that it is *restricting* the syntax allowed to represent the address of an object. It seems to specifically preclude pointer arithmetic and other expressions on the address.



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

Re: Weird diagnostic about non-type template argument

Enea Zaffanella
In reply to this post by Chandler Carruth
Chandler Carruth wrote:
> On Mon, Aug 16, 2010 at 12:31 AM, Abramo Bagnara
> <[hidden email] <mailto:[hidden email]>> wrote:

[... snip ...]

>     3) that apart the diagnostic message is misleading: non-type template
>     argument might (and sometimes should, see the following line in source)
>     be surrounded by parentheses
>
>
> The second line is a completely different non-type template argument: an
> integral constant-expression. There are no parentheses around the
> template argument, there are parentheses as part of the
> constant-expression, which allows parentheses among many other
> constructs. It is certainly unfortunate that there is no way to write a
> '>' in an ICE without parentheses, but I don't think that artifact
> necessarily warrants allowing parentheses for all template arguments, or
> even for all non-type template arguments...

I think that, in point 3, Abramo was just referring to the wording of
the diagnostic, which maybe could be improved.

I don't think that usual C++ programmers can easily tell the difference
(if any) from a non-type template argument and the constant expression
that denotes a non-type template argument. So, it might be appropriate
to change the message wording to something like:

non-type template argument having pointer type cannot be surrounded by
paretheses
    or
pointer-type expression used as non-type template argument cannot be ...

or something similar.

Cheers,
Enea.

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

Re: Weird diagnostic about non-type template argument

Chandler Carruth
On Mon, Aug 16, 2010 at 2:24 AM, Enea Zaffanella <[hidden email]> wrote:
I think that, in point 3, Abramo was just referring to the wording of the diagnostic, which maybe could be improved.

Sure. I've no problem improving the diagnostic, but I'm not sure what to make it. Your first is close though, maybe: "a non-type template argument which is the address of an object cannot be surrounded by parentheses". I'm leery of using words like "type" because of the "non-type" category of template arguments we're dealing with. I'm not the best wordsmith though....

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

Re: Weird diagnostic about non-type template argument

Abramo Bagnara-2
Il 16/08/2010 11:48, Chandler Carruth ha scritto:

> On Mon, Aug 16, 2010 at 2:24 AM, Enea Zaffanella <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     I think that, in point 3, Abramo was just referring to the wording
>     of the diagnostic, which maybe could be improved.
>
>
> Sure. I've no problem improving the diagnostic, but I'm not sure what to
> make it. Your first is close though, maybe: "a non-type template
> argument which is the address of an object cannot be surrounded by
> parentheses". I'm leery of using words like "type" because of the
> "non-type" category of template arguments we're dealing with. I'm not
> the best wordsmith though....

Furtherly to exit with a fatal error is a bit overkill for things like
that... do you agree?
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Weird diagnostic about non-type template argument

Chandler Carruth
On Mon, Aug 16, 2010 at 3:21 AM, Abramo Bagnara <[hidden email]> wrote:
Il 16/08/2010 11:48, Chandler Carruth ha scritto:
> On Mon, Aug 16, 2010 at 2:24 AM, Enea Zaffanella <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     I think that, in point 3, Abramo was just referring to the wording
>     of the diagnostic, which maybe could be improved.
>
>
> Sure. I've no problem improving the diagnostic, but I'm not sure what to
> make it. Your first is close though, maybe: "a non-type template
> argument which is the address of an object cannot be surrounded by
> parentheses". I'm leery of using words like "type" because of the
> "non-type" category of template arguments we're dealing with. I'm not
> the best wordsmith though....

Furtherly to exit with a fatal error is a bit overkill for things like
that... do you agree?

As I said in my original post, this being an ExtWarn seems plausible, but I don't personally find it compelling to support this syntax. I think it's actually worthwhile that the standard insists on a differentiated syntax in these two cases for the reason I originally pointed out -- this *isn't* an expression, and it shouldn't be thought of in that context.

Perhaps others disagree, or have some large body of code that uses this extensively (seems rather unlikely to me though...), but either way, the code doesn't conform, and so it should at most be accepted as an extension with appropriate warnings.

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

Re: Weird diagnostic about non-type template argument

Douglas Gregor

On Aug 16, 2010, at 3:33 AM, Chandler Carruth wrote:

On Mon, Aug 16, 2010 at 3:21 AM, Abramo Bagnara <[hidden email]> wrote:
Il 16/08/2010 11:48, Chandler Carruth ha scritto:
> On Mon, Aug 16, 2010 at 2:24 AM, Enea Zaffanella <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     I think that, in point 3, Abramo was just referring to the wording
>     of the diagnostic, which maybe could be improved.
>
>
> Sure. I've no problem improving the diagnostic, but I'm not sure what to
> make it. Your first is close though, maybe: "a non-type template
> argument which is the address of an object cannot be surrounded by
> parentheses". I'm leery of using words like "type" because of the
> "non-type" category of template arguments we're dealing with. I'm not
> the best wordsmith though....

Furtherly to exit with a fatal error is a bit overkill for things like
that... do you agree?

As I said in my original post, this being an ExtWarn seems plausible, but I don't personally find it compelling to support this syntax. I think it's actually worthwhile that the standard insists on a differentiated syntax in these two cases for the reason I originally pointed out -- this *isn't* an expression, and it shouldn't be thought of in that context.

Perhaps others disagree, or have some large body of code that uses this extensively (seems rather unlikely to me though...), but either way, the code doesn't conform, and so it should at most be accepted as an extension with appropriate warnings.

This is core issue 773:


And the committee is favoring allowing the parentheses. I suggest we make it an ExtWarn in C++98/03 mode, with clearer diagnostic text (if we can).

- Doug

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