[PATCH] Fix parsing comma in default arguments.
Richard Smith
richard at metafoo.co.uk
Thu Jun 13 13:52:47 PDT 2013
On Thu, Jun 13, 2013 at 12:47 PM, Olivier Goffart <ogoffart at kde.org> wrote:
> On Wednesday 12 June 2013 14:39:04 Richard Smith wrote:
>> I've had a look at this before. Here are some testcases for you:
>>
>> Index: test/Parser/cxx-ambig-init-templ.cpp
>> ===================================================================
>> --- test/Parser/cxx-ambig-init-templ.cpp (revision 0)
>> +++ test/Parser/cxx-ambig-init-templ.cpp (revision 0)
>> @@ -0,0 +1,57 @@
>> +// RUN: %clang_cc1 -std=c++11 -verify %s
>> +
>> +template<int> struct c { c(int) = delete; typedef void val; };
>> +
>> +int val;
>> +struct S {
>> + int k1 = a < b < c, d > ::val, e1;
>> + int k2 = a < b, c < d > ::val, e2;
>> + int k3 = b < a < c, d > ::val, e3;
>> + int k4 = b < c, x, y = d > ::val, e4;
>> + int k5 = T1 < b, &S::operator=(int); // expected-warning
>> {{qualification}}
>
> that is an error instead of a warning for me, so i removed the extra
> qualification
Yes, this test case was written a while ago (and is incomplete and not
entirely correct). You can demote this to a warning with
-fms-extensions.
>> + int k6 = T2 < b, &S::operator= >::val;
>> + int k7 = T1 < b, &S::operator>(int); // expected-warning
>> {{qualification}}
>
> Same here.
>
>> + int k8 = T2 < b, &S::operator> >::val;
>> + int k9 = T3 < a < b, c >> (d), e5 = 1 > (e4);
>> +
>> + void f(
>> + int k1 = a < b < c, d > ::val,
>> + int k3 = b < a < c, d > ::val,
>> + int k4 = b < c, int x = 0 > ::val,
>> + int k5 = a < b, T3 < int > >(),
>
> T3<int> is not int, and a is not an int
T3 has a conversion to int (which should be marked constexpr but
isn't), and 'a' should also have one.
>> + int k6 = c < b, T3 < int > x,
>
> 'x is a duplicate argument, missing a default value, and T3 must be declared
> before
Sure.
>> +
>> + int k2 = a < b, c < d > ::val, // 'a' must be a template
>> (otherwise we're missing a default arg)
>> + int k7 = a < b, c < d > (n) // 'a' must be a template (otherwise
>> we're missing a default arg)
>
> there is no 'n' and 'a' don't convert to int
>
>> + );
>> +
>> + template<int, int=0> struct a { static const int val = 0; };
>> + static const int b = 0, c = 1, d = 2;
>> +
>> + static const int T1 = 4;
>> + template<int, int &(S::*)(int)> struct T2 { static const int val = 0; };
>> +
>> + template<typename> struct T3 { T3(int); operator int(); };
>> +};
>> +
>> +namespace CWG325 {
>> +
>> + template <int A, typename B> struct T { static int i; operator int(); };
>> + class C {
>> + int Foo (int i = T<1, int>::i);
>> + };
>> +
>> + class D {
>> + int Foo (int i = T<1, int>::i);
>> + template <int A, typename B> struct T {static int i;};
>> + };
>> +
>> + const int a = 0;
>> + typedef int b;
>> + T<a,b> c;
>> + struct E {
>> + int n = T<a,b>(c);
>> + };
>> +
>> +}
>>
>> I don't see any handling of "operator<", "operator>", "operator,",
>> "operator=" in your patch, so I assume it doesn't handle those cases
>> properly. (That should be straightforward to fix.)
>
> Right, I have forgotten that.
>
>> Essentially, there are two different tricks we need in order to fully
>> disambiguate these cases with no name lookup:
>>
>> 1) For an in-class function declaration, if we are in a default
>> argument, every parameter after the current parameter must also have a
>> default argument, and a template argument cannot contain a top-level
>> '='. So if we see a '=', we know we're back to a parameter, and can
>> back up to the comma at the start of that parameter.
>
> This was basically what i implemented before
>
>> 2) For an in-class default initializer for a data member, any '=' must
>> be part of a new data member, and otherwise any '<' or '>' must be
>> part of the same initializer (because a declarator cannot contain a
>> '<' or '>').
>
> Yes, the previous patch did not really work well with NSDMI.
>
> Too be honnest I was mostly focussed on getting the default argument working
> since it was the problem i had on the project I was working with.
>
> Now it is implemented using a similar way.
>
> I can still think about some broken cases, but I think they are corner case
> and they do not deserve to be fixed:
That's not really acceptable, if it can lead to rejecting valid code
that we accept now (such as your next example).
> int i = 0 < 1, vector<string>::*j;
Yuck. But that is still unambiguous.
> Also a template argument can contains = for example in this case:
> struct S {constexpr S(){}; constexpr int operator=(int) const {return 5;}};
> template <int> struct A {};
> constexpr S s;
> A<s=4> a;
This is ill-formed.
> But, while GCC accept this code, clang currently reject it. But that's
> another bug
That's a GCC bug. A non-type template argument has to be a
constant-expression, which is a conditional-expression, and thus
cannot be an assignment-expression.
More information about the cfe-commits
mailing list