[PR c++/84789] do not fail to resolve typename into template-independent
authorAlexandre Oliva <aoliva@redhat.com>
Fri, 23 Mar 2018 01:19:14 +0000 (01:19 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Fri, 23 Mar 2018 01:19:14 +0000 (01:19 +0000)
Although resolve_typename_type always takes a template-dependent
type-id, and it usually resolves it to another template-dependent
type-id, it is not correct to require the latter: in declarators,
template-dependent scopes may turn out to name template-independent
types, as in the pr84789-2.C and pr84789-3.C testcases.

The ill-formed testcase pr84789.C trips the same too-strict assert,
and also gets fixed by removing the assertion on the simplified scope.
However, whereas when the dependent type cannot be resolved, we get an
error that suggests 'typename' is missing:

pr84789.C:12:3: error: need ‘typename’ before ‘typename B<T>::A::I::I’
because ‘typename B<T>::A::I’ is a dependent scope
   B<T>::A::I::I i;
   ^~~~

when it can, we got errors that did not point at that possibility,
which may be confusing:

pr84789.C:9:15: error: ‘A::I’ {aka ‘int’} is not a class type
   B<T>::A::I::I i; // { dg-error "typename" }
               ^
pr84789.C:9:15: error: ‘I’ in ‘A::I’ {aka ‘int’} does not name a type

Changing the parser diagnostic code that reports an invalid type name
so that it does not attempt to reparse the name as a declarator gets
us the superior diagnostic of a missing 'typename' keyword.

for  gcc/cp/ChangeLog

PR c++/84789
* pt.c (resolve_typename_type): Drop assert that stopped
simplification to template-independent types.  Add assert to
verify the initial scope is template dependent.
* parser.c (cp_parser_parse_and_diagnose_invalid_type_name):
Reparse the id expression as a type-name, not a declarator.

for  gcc/testsuite/ChangeLog

PR c++/84789
* g++.dg/template/pr84789.C: New.
* g++.dg/template/pr84789-2.C: New.
* g++.dg/template/pr84789-3.C: New.
* g++.dg/parse/dtor11.C: Accept alternate error message.

From-SVN: r258792

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/dtor11.C
gcc/testsuite/g++.dg/template/pr84789-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pr84789-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pr84789.C [new file with mode: 0644]

index 33add697a8648b8756006971f3f5499e1981ab73..08ecf21d9ba18015c5b2a9f829dda83995bc3d66 100644 (file)
@@ -1,5 +1,12 @@
 2018-03-22  Alexandre Oliva <aoliva@redhat.com>
 
+       PR c++/84789
+       * pt.c (resolve_typename_type): Drop assert that stopped
+       simplification to template-independent types.  Add assert to
+       verify the initial scope is template dependent.
+       * parser.c (cp_parser_parse_and_diagnose_invalid_type_name):
+       Reparse the id expression as a type-name, not a declarator.
+
        PR c++/84729
        * init.c (build_vec_init): Error at parenthesized array init.
 
index 34619293120b6e2e3c1dd0a66587c32a89b924c1..fd817024eacfc2b3db58df6eff18e7300955dea7 100644 (file)
@@ -3455,7 +3455,7 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
                                /*template_keyword_p=*/false,
                                /*check_dependency_p=*/true,
                                /*template_p=*/NULL,
-                               /*declarator_p=*/true,
+                               /*declarator_p=*/false,
                                /*optional_p=*/false);
   /* If the next token is a (, this is a function with no explicit return
      type, i.e. constructor, destructor or conversion op.  */
index d7c0c7bec81b11b89bc742de9b24f233f9204bf3..5293c2b5491bc823601bbdbe17a25cf9ec013835 100644 (file)
@@ -25249,6 +25249,9 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
+  /* We shouldn't have built a TYPENAME_TYPE with a non-dependent scope.  */
+  gcc_checking_assert (uses_template_parms (scope));
+
   /* Usually the non-qualified identifier of a TYPENAME_TYPE is
      TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
      a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
@@ -25285,8 +25288,6 @@ resolve_typename_type (tree type, bool only_current_p)
     /* scope is either the template itself or a compatible instantiation
        like X<T>, so look up the name in the original template.  */
     scope = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (scope);
-  /* We shouldn't have built a TYPENAME_TYPE with a non-dependent scope.  */
-  gcc_checking_assert (uses_template_parms (scope));
   /* If scope has no fields, it can't be a current instantiation.  Check this
      before currently_open_class to avoid infinite recursion (71515).  */
   if (!TYPE_FIELDS (scope))
index 07951d99ba9f658426c1c1d04c4993838c766bc7..4875ce45e8d144a4f9e13fca97e91ef638a8a013 100644 (file)
@@ -1,5 +1,11 @@
 2018-03-22  Alexandre Oliva <aoliva@redhat.com>
 
+       PR c++/84789
+       * g++.dg/template/pr84789.C: New.
+       * g++.dg/template/pr84789-2.C: New.
+       * g++.dg/template/pr84789-3.C: New.
+       * g++.dg/parse/dtor11.C: Accept alternate error message.
+
        PR c++/84729
        * g++.dg/pr84729.C: New.
        * g++.old-deja/g++.ext/arrnew2.C: Require error.
index 63ffb60bac107dfe2f8f5d9d138ac4d91de01592..83fd93489f11f14590ef132164abaaf3600757bd 100644 (file)
@@ -8,5 +8,5 @@ struct A
 
 struct B
 {
-  A::~B B();  // { dg-error "as member of" }
+  A::~B B();  // { dg-error "as member of|as a type" }
 };
diff --git a/gcc/testsuite/g++.dg/template/pr84789-2.C b/gcc/testsuite/g++.dg/template/pr84789-2.C
new file mode 100644 (file)
index 0000000..0b42148
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile }
+
+struct K {
+  struct L {
+    static double j;
+  };
+};
+
+template <typename T>
+struct M {
+  struct N {
+    static int i;
+  };
+};
+
+template <typename T>
+struct O {
+  typedef M<T> P;
+  typedef K Q;
+};
+
+template <typename T>
+int O<T>::P::N::i = 42; // This is obfuscated, but apparently ok.
+
+template <typename T>
+double O<T>::Q::L::j = 42.0; // { dg-error "non-template" }
diff --git a/gcc/testsuite/g++.dg/template/pr84789-3.C b/gcc/testsuite/g++.dg/template/pr84789-3.C
new file mode 100644 (file)
index 0000000..bc38c15
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile }
+
+struct A
+{
+  static int i;
+};
+struct B
+{
+  typedef ::A A;
+};
+int B::A::i = 0;
+
+struct K
+{
+  struct L
+  {
+    template <typename T>
+    static void f(T);
+  };
+};
+
+template <typename T>
+struct O
+{
+  typedef K Q;
+};
+
+template <typename T>
+void O<T>::Q::L::f(T)
+{
+}
diff --git a/gcc/testsuite/g++.dg/template/pr84789.C b/gcc/testsuite/g++.dg/template/pr84789.C
new file mode 100644 (file)
index 0000000..bc1567f
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile }
+
+struct A
+{
+  typedef int I;
+};
+
+template<typename> struct B : A {};
+
+template<typename T> struct C : B<T>
+{
+  B<T>::A::I::I i; // { dg-error "typename" }
+};