summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-09-12 23:28:08 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-09-12 23:28:08 +0000
commit1fff95c7023d343bee9f0e633169c91452ec5368 (patch)
treea116b518447dd2185b0bac01c78fb71fcce82f1b /clang/test
parent6b3e6d54871f02cdaca323a80051f2d744b39b76 (diff)
downloadbcm5719-llvm-1fff95c7023d343bee9f0e633169c91452ec5368.tar.gz
bcm5719-llvm-1fff95c7023d343bee9f0e633169c91452ec5368.zip
PR13657 (and duplicates):
When a comma occurs in a default argument or default initializer within a class, disambiguate whether it is part of the initializer or whether it ends the initializer. The way this works (which I will be proposing for standardization) is to treat the comma as ending the default argument or default initializer if the following token sequence matches the syntactic constraints of a parameter-declaration-clause or init-declarator-list (respectively). This is both consistent with the disambiguation rules elsewhere (where entities are treated as declarations if they can be), and should have no regressions over our old behavior. I think it might also disambiguate all cases correctly, but I don't have a proof of that. There is an annoyance here: because we're performing a tentative parse in a situation where we may not have seen declarations of all relevant entities (if the comma is part of the initializer, lookup may find entites declared later in the class), we need to turn off typo-correction and diagnostics during the tentative parse, and in the rare case that we decide the comma is part of the initializer, we need to revert all token annotations we performed while disambiguating. Any diagnostics that occur outside of the immediate context of the tentative parse (for instance, if we trigger the implicit instantiation of a class template) are *not* suppressed, mirroring the usual rules for a SFINAE context. llvm-svn: 190639
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/Parser/cxx-ambig-init-templ.cpp171
-rw-r--r--clang/test/Parser/cxx-default-args.cpp17
-rw-r--r--clang/test/Parser/cxx0x-member-initializers.cpp10
3 files changed, 198 insertions, 0 deletions
diff --git a/clang/test/Parser/cxx-ambig-init-templ.cpp b/clang/test/Parser/cxx-ambig-init-templ.cpp
new file mode 100644
index 00000000000..88ab61c3ab6
--- /dev/null
+++ b/clang/test/Parser/cxx-ambig-init-templ.cpp
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int> struct c { c(int) = delete; typedef void val; operator int() const; };
+
+int val;
+int foobar;
+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-error {{extra qualification}}
+ int k6 = T2 < b, &S::operator= >::val;
+ int k7 = T1 < b, &S::operator>(int); // expected-error {{extra qualification}}
+ int k8 = T2 < b, &S::operator> >::val;
+ int k9 = T3 < a < b, c >> (d), e5 = 1 > (e4);
+ int k10 = 0 < T3 < a < b, c >> (d
+ ) // expected-error {{expected ';' at end of declaration}}
+ , a > (e4);
+ int k11 = 0 < 1, c<3>::*ptr;
+ int k12 = e < 0, int a<b<c>::* >(), e11;
+
+ void f1(
+ int k1 = a < b < c, d > ::val,
+ int k2 = b < a < c, d > ::val,
+ int k3 = b < c, int x = 0 > ::val,
+ int k4 = a < b, T3 < int > >(), // expected-error {{must be an expression}}
+ int k5 = a < b, c < d > ::val,
+ int k6 = a < b, c < d > (n) // expected-error {{undeclared identifier 'n'}}
+ );
+
+ void f2a(
+ // T3<int> here is a parameter type, so must be declared before it is used.
+ int k1 = c < b, T3 < int > x = 0 // expected-error {{unexpected end of default argument expression}}
+ );
+
+ template<typename, int=0> struct T3 { T3(int); operator int(); };
+
+ void f2b(
+ int k1 = c < b, T3 < int > x = 0 // ok
+ );
+
+ // This is a one-parameter function. Ensure we don't typo-correct it to
+ // int = a < b, c < foobar > ()
+ // ... which would be a function with two parameters.
+ int f3(int = a < b, c < goobar > ());
+ static constexpr int (S::*f3_test)(int) = &S::f3;
+
+ void f4(
+ int k1 = a<1,2>::val,
+ int missing_default // expected-error {{missing default argument on parameter}}
+ );
+
+ void f5(
+ int k1 = b < c,
+ int missing_default // expected-error {{missing default argument on parameter}}
+ );
+
+ void f6(
+ int k = b < c,
+ unsigned int (missing_default) // expected-error {{missing default argument on parameter}}
+ );
+
+ template<int, int=0> struct a { static const int val = 0; operator int(); }; // expected-note {{here}}
+ static const int b = 0, c = 1, d = 2, goobar = 3;
+ template<int, typename> struct e { operator int(); };
+
+ int mp1 = 0 < 1,
+ a<b<c,b<c>::*mp2,
+ mp3 = 0 > a<b<c>::val,
+ a<b<c,b<c>::*mp4 = 0,
+ a<b<c,b<c>::*mp5 {0},
+ a<b<c,b<c>::*mp6;
+
+ int np1 = e<0, int a<b<c,b<c>::*>();
+
+ static const int T1 = 4;
+ template<int, int &(S::*)(int)> struct T2 { static const int val = 0; };
+};
+
+namespace NoAnnotationTokens {
+ template<bool> struct Bool { Bool(int); };
+ static const bool in_class = false;
+
+ struct Test {
+ // Check we don't keep around a Bool<false> annotation token here.
+ int f(Bool<true> = X<Y, Bool<in_class> >(0));
+
+ // But it's OK if we do here.
+ int g(Bool<true> = Z<Y, Bool<in_class> = Bool<false>(0));
+
+ static const bool in_class = true;
+ template<int, typename U> using X = U;
+ static const int Y = 0, Z = 0;
+ };
+}
+
+namespace ImplicitInstantiation {
+ template<typename T> struct HasError { typename T::error error; }; // expected-error {{has no members}}
+
+ struct S {
+ // This triggers the instantiation of the outer HasError<int> during
+ // disambiguation, even though it uses the inner HasError<int>.
+ void f(int a = X<Y, HasError<int>::Z >()); // expected-note {{in instantiation of}}
+
+ template<typename, typename> struct X { operator int(); };
+ typedef int Y;
+ template<typename> struct HasError { typedef int Z; };
+ };
+
+ HasError<int> hei;
+}
+
+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);
+ };
+}
+
+namespace Operators {
+ struct Y {};
+ constexpr int operator,(const Y&, const Y&) { return 8; }
+ constexpr int operator>(const Y&, const Y&) { return 8; }
+ constexpr int operator<(const Y&, const Y&) { return 8; }
+ constexpr int operator>>(const Y&, const Y&) { return 8; }
+
+ struct X {
+ typedef int (*Fn)(const Y&, const Y&);
+
+ Fn a = operator,, b = operator<, c = operator>;
+ void f(Fn a = operator,, Fn b = operator<, Fn c = operator>);
+
+ int k1 = T1<0, operator<, operator>, operator<>::val, l1;
+ int k2 = T1<0, operator>, operator,, operator,>::val, l2;
+ int k3 = T2<0, operator,(Y{}, Y{}), operator<(Y{}, Y{})>::val, l3;
+ int k4 = T2<0, operator>(Y{}, Y{}), operator,(Y{}, Y{})>::val, l4;
+ int k5 = T3<0, operator>>>::val, l5;
+ int k6 = T4<0, T3<0, operator>>>>::val, l6;
+
+ template<int, Fn, Fn, Fn> struct T1 { enum { val }; };
+ template<int, int, int> struct T2 { enum { val }; };
+ template<int, Fn> struct T3 { enum { val }; };
+ template<int, typename T> struct T4 : T {};
+ };
+}
+
+namespace ElaboratedTypeSpecifiers {
+ struct S {
+ int f(int x = T<a, struct S>());
+ int g(int x = T<a, class __declspec() C>());
+ int h(int x = T<a, union __attribute__(()) U>());
+ int i(int x = T<a, enum E>());
+ int j(int x = T<a, struct S::template T<0, enum E>>());
+ template <int, typename> struct T { operator int(); };
+ static const int a = 0;
+ enum E {};
+ };
+}
diff --git a/clang/test/Parser/cxx-default-args.cpp b/clang/test/Parser/cxx-default-args.cpp
index 7fe8474142b..36abf0d8cb3 100644
--- a/clang/test/Parser/cxx-default-args.cpp
+++ b/clang/test/Parser/cxx-default-args.cpp
@@ -14,3 +14,20 @@ typedef struct Inst {
struct X {
void f(int x = 1:); // expected-error {{unexpected end of default argument expression}}
};
+
+// PR13657
+struct T {
+ template <typename A, typename B> struct T1 { enum {V};};
+ template <int A, int B> struct T2 { enum {V}; };
+ template <int, int> static int func(int);
+
+
+ void f1(T1<int, int> = T1<int, int>());
+ void f2(T1<int, double> = T1<int, double>(), T2<0, 5> = T2<0, 5>());
+ void f3(int a = T2<0, (T1<int, int>::V > 10) ? 5 : 6>::V, bool b = 4<5 );
+ void f4(bool a = 1 < 0, bool b = 2 > 0 );
+ void f5(bool a = 1 > T2<0, 0>::V, bool b = T1<int,int>::V < 3, int c = 0);
+ void f6(bool a = T2<0,3>::V < 4, bool b = 4 > T2<0,3>::V);
+ void f7(bool a = T1<int, bool>::V < 3);
+ void f8(int = func<0,1<2>(0), int = 1<0, T1<int,int>(int) = 0);
+};
diff --git a/clang/test/Parser/cxx0x-member-initializers.cpp b/clang/test/Parser/cxx0x-member-initializers.cpp
index a324f974bca..43e99b13364 100644
--- a/clang/test/Parser/cxx0x-member-initializers.cpp
+++ b/clang/test/Parser/cxx0x-member-initializers.cpp
@@ -27,3 +27,13 @@ struct V1 {
int a, b;
V1() : a(), b{} {}
};
+
+template <typename, typename> struct T1 { enum {V};};
+template <int, int> struct T2 { enum {V};};
+struct A {
+ T1<int, int> a1 = T1<int, int>(), *a2 = new T1<int,int>;
+ T2<0,0> b1 = T2<0,0>(), b2 = T2<0,0>(), b3;
+ bool c1 = 1 < 2, c2 = 2 < 1, c3 = false;
+ bool d1 = T1<int, T1<int, int>>::V < 3, d2;
+ T1<int, int()> e = T1<int, int()>();
+};
OpenPOWER on IntegriCloud