g++ rejects, clang++ accepts: foo(x)("bar")("baz"); - c++

Somebody had asked the other day why something compiles with clang, but not with gcc. I intuitively understood what was happening and was able to help the person, but it got me wondering -- according to the standard, which compiler was correct? Here is a boiled down version of the code:
#include <iostream>
#include <string>
class foo
{
public:
foo(const std::string& x):
name(x)
{ }
foo& operator()(const std::string& x)
{
std::cout << name << ": " << x << std::endl;
return (*this);
}
std::string name;
};
int main()
{
std::string x = "foo";
foo(x)("bar")("baz");
return 0;
}
This compiles fine with clang++, but g++ gives the following error:
runme.cpp: In function ‘int main()’:
runme.cpp:21:11: error: conflicting declaration ‘foo x’
foo(x)("bar")("baz");
^
runme.cpp:20:17: error: ‘x’ has a previous declaration as ‘std::string x’
std::string x = "foo";
If I add a pair of parentheses in line 21, g++ is happy:
(foo(x))("bar")("baz");
In other words, g++ interprets this line as:
foo x ("bar")("baz");
Methinks itsa bug in g++, but again, I wanted to ask the standard experts, which compiler got it wrong?
PS: gcc-4.8.3, clang-3.5.1

As far as I can tell this is covered in the draft C++ standard section 6.8 Ambiguity resolution which says that there can be an ambiguity between expression statements and declarations and says:
There is an ambiguity in the grammar involving expression-statements
and declarations: An expression statement with a function-style
explicit type conversion (5.2.3) as its leftmost subexpression can be
indistinguishable from a declaration where the first declarator starts
with a (. In those cases the statement is a declaration. [ Note: To
disambiguate, the whole statement might have to be examined to
determine if it is an expression-statement or a declaration. This
disambiguates many examples. [ Example: assuming T is a
simple-type-specifier (7.1.6),
and gives the following examples:
T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration
and then says:
The remaining cases are declarations. [ Example:
class T {
// ...
public:
T();
T(int);
T(int, int);
};
T(a); // declaration
T(*b)(); // declaration
T(c)=7; // declaration
T(d),e,f=3; // declaration
extern int h;
T(g)(h,2); // declaration
—end example ] —end note ]
It seems like this case falls into the declaration examples in particular the last example seems to make the case in the OP, so gcc would be correct then.
Relevant section mentioned above 5.2.3 Explicit type conversion (functional notation) says:
[...] If the type specified is a class type, the class type shall be complete. If the expression
list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1),
and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some
invented temporary variable t, with the result being the value of t as a prvalue.
and 8.3 Meaning of declarators which says:
In a declaration T D where D has the form
( D1 )
the type of the contained declarator-id is the same as that of the
contained declarator-id in the declaration
T D1
Parentheses do not alter the type of the embedded declarator-id, but
they can alter the binding of complex declarators.
Update
I was originally using N337 but if we look at N4296 section 6.8 was updated an it now includes the following note:
If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not
apply.
which means that gcc is incorrect since:
foo x ("bar")("baz");
can not be a valid declaration, I originally interpreted paragraph 2 as saying if you case begins with any of the following then it is declaration, which is perhaps how the gcc implementor interpreted as well.
I should have been more suspicious of paragraph 2 since the only normative part of paragraph 2 really said nothing with respect to paragraph 1 and seems to place a requirement on an example which is not normative. We can see that that statement form paragraph 2 is now actually a note which makes much more sense.
As T.C. noted below, paragraph 2 was actually never normative, it just appeared that way and he linked to the change that fixed it.

If we remove the line
std::string x = "foo";
then g++ complains about:
foo(x)("bar")("baz");
with the syntax error:
foo.cc:20:18: error: expected ',' or ';' before '(' token
foo(x)("bar")("baz");
I do not see how foo (x)("bar")("baz"); could be a valid declaration, and apparently g++ can't either. The line foo x("bar")("baz"); is rejected with the same error.
The "ambiguity resolution" mentioned in Shafik's post only kicks in when the expression-statement is syntactically indistinguishable from a declaration. However in this case it is not a valid declaration syntax so there is no ambiguity, it must be an expression-statement.
g++ fails to process the line as an expression-statement so it is a g++ bug.
This is eerily similar to this g++ bug recently discussed on SO; it seems that g++ is perhaps deciding too soon in processing that the line must be a declaration .

Related

Is `auto(expr)` treated as cast at the beginning of the expression statement?

I have a simple code snippet shown below (https://godbolt.org/z/cPT3PhYdj):
int main() {
int x = 1;
auto(1); // ok in GCC, error in Clang
auto{1}; // ok in GCC, error in Clang
static_cast<void>(auto(x)); // ok
auto{x}; // ok in GCC, error in Clang
auto(x); // both error in GCC an Clang
}
Where both GCC and Clang emit an error showing:
// by GCC Trunk [-std=c++23]
<source>: In function 'int main()':
<source>:7:3: error: declaration of 'auto x' has no initializer
7 | auto(x); // why
| ^~~~
Compiler returned: 1
// by Clang Trunk [-std=c++2b]
<source>:3:8: error: expected unqualified-id
auto(1); // why
^
<source>:3:8: error: expected ')'
<source>:3:7: note: to match this '('
auto(1); // why
^
<source>:4:7: error: expected unqualified-id
auto{1}; // why
^
<source>:6:7: error: expected unqualified-id
auto{x}; // why
^
<source>:7:8: error: redefinition of 'x'
auto(x); // why
^
<source>:2:7: note: previous definition is here
int x = 1;
^
<source>:7:8: error: declaration of variable 'x' with deduced type 'auto' requires an initializer
auto(x); // why
^
6 errors generated.
Compiler returned: 1
If C++23 is experimental, and will they be able to fix the ambiguity or change the disambiguation since another auto(expr) is introduced, or just leave it be?
Are these expressions supposed to be parsed as explicit type decay conversion auto(expr) or auto{expr} in expression statements or parsed as a declaration?
If there is no ambiguity, then which priority comes first:
auto(identifier) as auto identifier?, or
auto(identifier) as cast expression?
From Explicit cast conversion:
auto ( expression ) (8) (since C++23)
auto { expression } (9) (since C++23)
8,9) The auto specifier is replaced with the deduced type of the invented variable x declared with auto x(expression); (which is never interpreted as a function declaration) or auto x{expression}; respectively. The result is always a prvalue of an object type.
So your usage seems to be allowed(in accordance with ) by the above quoted statement.
Here is a working demo of your code. Note in the linked demo, only the usage auto(x) produces an error, all other cases work fine.
Also note that from PR105516:
auto(x); is interpreted as auto x;. Use +auto(x); if you want that to be an expression.
If there is no ambiguity, then which priority comes first:
This is one of the examples showing how C++ is a context sensitive language. A construct cannot always be understood without knowing its wider contexts. Consider the following example:
int main()
{
int x = 0 ;
int k ;
//------vvvvvvv----->here auto(x) is behaves as an expression as it is used as an expression
k = auto(x) ;
auto(p) ; //this a declaration and not an explicit case unlike the above
}
As far as I can tell the paper introducing this feature didn't make any further relevant changes except to allow auto as type specifier in a functional-style explicit cast.
So intuitively auto here should behave the same as any other type specifier would.
For example, replacing auto with int, it is expected that all of these cases work and are functional-style explicit casts, except
int(x); // auto(x);
This one could according to the grammar also be a declaration of a variable named x of type int (or placeholder type) with parentheses around the declarator and without initializer.
As usual, the grammar is disambiguated by preferring the interpretation as declaration (see [stmt.ambig]/1). At least, I don't think that it should be different for auto. A declaration with auto placeholder type requires an initializer, which is not present in this interpretation, but according to [stmt.ambig]/3 the disambiguation is supposed to be done very early and purely syntactic even if it ends up in an ill-formed declaration. I am not completely sure but I guess this should mean that auto(x); should still be disambiguated as a declaration.
I don't know why Clang gives errors for many of the other lines. I suppose the feature is either implemented only partially or these are implementation bugs (it is a very new feature in an unfinished standard revision).
I think auto(x) (where x is literally an identifier) can still have different meanings in different contexts and thus is subject to [dcl.ambig.res] in C++23.
Unfortunately, the ambiguity is unlikely to be fixed. In the following program (well-formed since C++11), auto(x) = Bar{}; is interpreted as a declaration. If auto(x) were "fixed", auto(x) = Bar{}; would become an expression statement, which would change the existing behavior.
#include <cstdio>
struct Bar {
Bar()
{
std::puts("initialization");
}
};
struct Foo {
void operator=(Bar)
{
std::puts("assignment");
}
};
int main()
{
Foo x{};
{
auto(x) = Bar{}; // only prints "initialization"
}
}

Note in §8.2[dcl.ambig.res]/2 in N4140

In §8.2[dcl.ambig.res]/2 we have the following note (emphases is mine):
[ Note: A declaration can be explicitly disambiguated by a
nonfunction-style cast, by an = to indicate initialization or by
removing the redundant parentheses around the parameter name. —end note ]
Shouldn't it be inserting instead of removing above?
Consider the following example:
#include <iostream>
struct S{ int i; S(int j) : i(j) {} };
float f = 1.0f;
S s(int(f)); // function declaration
int main()
{
std::cout << s.i << '\n';
}
The code doesn't compile, as the compiler considers the declaration S s(int(f)); as a function declaration. But if we do insert the parenthesis around the parameter name f, like S s((int(f))); the code compiles and prints 1.
I have to agree with Simple's comment, it is telling you that the parentheses around the parameter name is redundant. This is reinforced by defect report 340: Unclear wording in disambiguation section which was closed as Not A Defect and gives the following example:
struct Point
{
Point(int){}
};
struct Lattice
{
Lattice(Point, Point, int){}
};
int main(void)
{
int a, b;
Lattice latt(Point(a), Point(b), 3); /* Line X */
}
and says:
The declaration of latt declares a function with a return value of the
type Lattice and taking three arguments. The type of the first two
arguments is Point and each of these arguments is followed by a
parameter name in redundant parentheses. The type of the third
argument can not be determined, because it is a literal. This will
result in a syntax error.
I agree with Belloc's argument. The Note could have been written with the following change (in bold) to give it a more precise meaning, an in this case the word remove doesn't make sense.
An object declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing inserting the redundant parentheses around the parameter name. —end note

Inline member initializer containing pointer to member

At work, I'm experimenting a bit to bring some reflection into our codebase. Basically what I want to achieve, is to capture a pointer to data-member inside the type of the data-member's initializer:
template<class Class, int Class::*dataMember>
struct Reflect
{
operator int() {return 0;}
};
class Foo
{
public:
int bar = Reflect<Foo, &Foo::bar>{};
};
Although clang 3.4.1 (http://gcc.godbolt.org/) and Intel C++ XE 14.0 are able to compile this piece of code, when using MSVC12 I get the following error message:
error C2065: 'bar' : undeclared identifier
error C2975: 'dataMember' : invalid template argument for 'Reflect', expected compile-time constant expression
Furthermore, gcc 4.9.2 also seems to have trouble with it: http://ideone.com/ZUVOMO.
So my questions are:
Is the above piece of code valid C++11?
If yes, are there any work arounds for the failing compilers?
What VC++ complains about is certainly not a problem; [basic.scope.pdecl]/1,6:
The point of declaration for a name is immediately after its complete
declarator (Clause 8) and before its initializer (if any), except as
noted below.[…]
After the point of declaration of a class member, the member name can
be looked up in the scope of its class.
This implies that the name lookup is fine. However, as pointed out by #hvd in the comments, there are certain ambiguities in the grammar of such constructs.
Presumably GCC parses the above line until the comma:
int bar = Reflect<Foo,
// at this point Reflect < Foo can be a perfectly fine relational-expression.
// stuff after the comma could be a declarator for a second member.
And bails out once the rest is encountered.
A workaround that makes GCC happy is
int bar = decltype( Reflect<Foo, &Foo::bar>{} )();
Demo. This does not help with VC++ though, which apparently confuses the point of declaration as indicated by the error message.
Thus moving the initializer into a constructor will work:
int bar;
Foo() : bar( Reflect<Foo, &Foo::bar>{} ) {}
// (also works for GCC)
... while providing an initializer at the declaration of bar cannot. Demo #2 on rextester.

GCC attribute warning with trailing return type when return type is a class

GCC 4.9.1 does not appear to like function declarations with a trailing return type with attributes when the return type is a class.
Consider this following simplistic testcase:
struct bar
{
int a;
bar (int a) : a(a) {}
};
auto foo() -> bar __attribute__((unused));
auto foo() -> bar { return bar(5); }
int main()
{
return 0;
}
GCC prints a bizarre warning in regards to the attribute:
argh.cpp:2:41: warning: ignoring attributes applied to class type ‘bar’ outside of definition [-Wattributes]
auto foo() -> bar __attribute__((unused)) {return bar(5);}
Merging the declaration with the definition does not silence the warning, and this only happens when the return type is a class-type, it works fine with int. What is going on? Why does GCC not like this particular function declaration?
Seems to be a bug in the attribute parser used by GCC. The GCC manual warns about potential problems with the attribute grammar :
6.31 Attribute Syntax
Because of infelicities in the grammar for attributes, some forms
described here may not be successfully parsed in all cases.
There are some problems with the semantics of attributes in C++. [...] For example, there are no manglings for attributes, although they may affect code generation, so problems may arise when attributed types are used in conjunction with templates or overloading.
A warning about attribute parsing after a trailing return type would be helpful too.
An attribute specifier list may appear immediately before a declarator
[...]
You should try to place the attribute before the prototype :
__attribute__((unused))
auto foo() -> bar ;
auto foo() -> bar { return bar(5); }
and it should be OK without any warning.
An attribute specifier list may appear immediately before the comma, =
or semicolon terminating the declaration of an identifier other than a
function definition. Such attribute specifiers apply to the declared
object or function.
I guess that positioning the function attribute after the function declaration is OK unless there is a trailing return type.
Clang (as usual) gives a better warning in this case:
example.cpp:7:34: warning: 'unused' attribute ignored when parsing type
[-Wignored-attributes]
auto foo() -> bar __attribute__((unused));
^~~~~~
1 warning generated.
Just like GCC is telling you, that attribute is meaningless in the context you're using it. It's conceptually the same as doing something like:
const int f(void) { return 5 };
The const there just doesn't mean anything.
The GCC manual implies that the syntax is not supported at the moment.
An attribute specifier list may, in future, be permitted to appear
after the declarator in a function definition (before any old-style
parameter declarations or the function body).
N3337 describes the grammar of a function definition in [dcl.fct.def]:
function-definition:
attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
...
2 The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause )
cv-qualifier-seqopt
ref-qualifieropt
exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt
As you can see the trailing-return-type is part of the declarator which appears before the function-body. Try changing your code to this:
auto __attribute__((unused)) foo() -> bar;

Global initialization with temporary function object

The following code
#include <random>
std::mt19937 generator((std::random_device())());
compiles just file with clang:
$ clang++ -c -std=c++0x test.cpp
but fails with gcc:
$ g++ -c -std=c++0x test.cpp
test.cpp:3:47: erro: expected primary-expression before ‘)’ token
Is that code valid in C++11? Is it a bug in GCC or a extension/bug of Clang?
gcc is parsing the subexpression (std::random_device())() as a cast to the function type std::random_device(). It helps to look at icc's error output, which is slightly more informative than gcc's:
source.cpp(6): error: cast to type "std::random_device ()" is not allowed
std::mt19937 generator((std::random_device())());
^
source.cpp(6): error: expected an expression
std::mt19937 generator((std::random_device())());
^
The relevant production is 5.4p2:
cast-expression:
unary-expression
( type-id ) cast-expression
Since an empty pair of parentheses () is not a unary-expression, this production is unavailable and the compiler should select the production from 5.2p1:
postfix-expression:
[...]
postfix-expression ( expression-listopt )
[...]
where the postfix-expression is (std::random_device()) and the expression-list is omitted.
I've filed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239 on gcc bugzilla, and it looks like it should be resolved shortly.
Note that if you are supplying arguments to the operator() then the compiler is required by 8.2p2 to parse the expression as a cast, even though it is illegal to cast to a function type (if there are multiple arguments, the argument list is parsed as an expression using the comma operator:
(std::less<int>())(1, 2);
^~~~~~~~~~~~~~~~~~ illegal C-style cast
^~~~~~~~~~~~~~~~ type-id of function type std::less<int>()
^~~~~~ argument of C-style cast
^ comma operator
The correct way to write this (other than using C++11 universal initializer syntax) is to add another layer of parentheses, since a type-id cannot contain outer parentheses:
((std::less<int>()))(1, 2);
Seems like there is problem with the way GCC handles function declarations. Take this example:
struct A
{
bool operator () () { return true; }
};
struct B
{
B(bool) { }
};
B b(( // This cannot be parsed as a function declaration,
A()() // and yet GCC 4.7.2 interprets it as such:
)); // "error: 'type name' declared as function returning
// a function B b((A()()));"
int main() { }
Due to the presence of additional parentheses around A()(), the syntactic form B b(( A()() )); cannot be parsed as a declaration of a function.
The declaration in your question's example is slightly different:
B b(
(A())()
);
Even in this case, though, (A())() cannot be interpreted as the type of a function which returns a function that returns A (always in an attempt to consider b as a function declaration with an unnamed parameter). So the question is: can it be interpreted as anything else? If so, and if its meaningful in this context, then the compiler should consider to parse the whole expression as the construction of object b.
This is probably the fundamental point where GCC and Clang disagree:
int main()
{
(A())(); // OK for Clang, ERROR for GCC
}
I do not see how the above could be interpreted as anything else than an attempt to construct a temporary of type A and invoke its call operator. It cannot be a function declaration, because if A is interpreted as the return type, then the name is missing (and vice versa).
On the other hand, (A()) is a valid expression for creating a temporary of type A, and that temporary supports the call operator (whose return type is the same as the type accepted by B's constructor). Thus, (A())() should be a valid expression of type bool.
For this reasons, I believe that GCC's parsing is wrong.