diff mbox

Fix PR c++/60994 gcc does not recognize hidden/shadowed enumeration as valid nested-name-specifier

Message ID 552D2F5C.8010002@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 14, 2015, 3:16 p.m. UTC
On 05/09/2014 08:56 PM, Jason Merrill wrote:
> I don't think we want cp_parser_class_name to find enums; better I think
> to change cp_parser_qualifying_entity to use something other than
> cp_parser_type_name to look for enums.

I had a go at this myself, and it was problematic, so I ended up using a 
variation on your patch instead:
diff mbox

Patch

commit 5edd0f55206e3a2662c371f75d1d53c9c6988444
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Apr 3 15:48:00 2015 -0400

    	PR c++/60994
    	* parser.c (cp_parser_class_name): Add enum_ok parameter.
    	(cp_parser_qualifying_entity): Use it instead of cp_parser_type_name.
    	(cp_parser_diagnose_invalid_type_name): Don't assume a template is
    	a class template.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4d6b479..c457a29 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2193,7 +2193,7 @@  static tree finish_fully_implicit_template
 /* Classes [gram.class] */
 
 static tree cp_parser_class_name
-  (cp_parser *, bool, bool, enum tag_types, bool, bool, bool);
+  (cp_parser *, bool, bool, enum tag_types, bool, bool, bool, bool = false);
 static tree cp_parser_class_specifier
   (cp_parser *);
 static tree cp_parser_class_head
@@ -2957,10 +2957,13 @@  cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
     return;
   /* If the lookup found a template-name, it means that the user forgot
   to specify an argument list. Emit a useful error message.  */
-  if (TREE_CODE (decl) == TEMPLATE_DECL)
-    error_at (location,
-	      "invalid use of template-name %qE without an argument list",
-	      decl);
+  if (DECL_TYPE_TEMPLATE_P (decl))
+    {
+      error_at (location,
+		"invalid use of template-name %qE without an argument list",
+		decl);
+      inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
+    }
   else if (TREE_CODE (id) == BIT_NOT_EXPR)
     error_at (location, "invalid use of destructor %qD as a type", id);
   else if (TREE_CODE (decl) == TYPE_DECL)
@@ -3037,6 +3040,8 @@  cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
 	    error_at (location_of (id),
 		      "%qE in namespace %qE does not name a type",
 		      id, parser->scope);
+	  if (DECL_P (decl))
+	    inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
 	}
       else if (CLASS_TYPE_P (parser->scope)
 	       && constructor_name_p (id, parser->scope))
@@ -3063,6 +3068,8 @@  cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
 	    error_at (location_of (id),
 		      "%qE in %q#T does not name a type",
 		      id, parser->scope);
+	  if (DECL_P (decl))
+	    inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
 	}
       else
 	gcc_unreachable ();
@@ -5710,35 +5717,9 @@  cp_parser_qualifying_entity (cp_parser *parser,
 				type_p ? class_type : none_type,
 				check_dependency_p,
 				/*class_head_p=*/false,
-				is_declaration);
+				is_declaration,
+				/*enum_ok=*/cxx_dialect > cxx98);
   successful_parse_p = only_class_p || cp_parser_parse_definitely (parser);
-  /* If that didn't work and we're in C++0x mode, try for a type-name.  */
-  if (!only_class_p 
-      && cxx_dialect != cxx98
-      && !successful_parse_p)
-    {
-      /* Restore the saved scope.  */
-      parser->scope = saved_scope;
-      parser->qualifying_scope = saved_qualifying_scope;
-      parser->object_scope = saved_object_scope;
-
-      /* Parse tentatively.  */
-      cp_parser_parse_tentatively (parser);
-     
-      /* Parse a type-name  */
-      scope = cp_parser_type_name (parser);
-
-      /* "If the name found does not designate a namespace or a class,
-	 enumeration, or dependent type, the program is ill-formed."
-
-         We cover classes and dependent types above and namespaces below,
-         so this code is only looking for enums.  */
-      if (!scope || TREE_CODE (scope) != TYPE_DECL
-	  || TREE_CODE (TREE_TYPE (scope)) != ENUMERAL_TYPE)
-	cp_parser_simulate_error (parser);
-
-      successful_parse_p = cp_parser_parse_definitely (parser);
-    }
   /* If that didn't work, try for a namespace-name.  */
   if (!only_class_p && !successful_parse_p)
     {
@@ -19608,7 +19589,8 @@  cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
    is a template.  TAG_TYPE indicates the explicit tag given before
    the type name, if any.  If CHECK_DEPENDENCY_P is FALSE, names are
    looked up in dependent scopes.  If CLASS_HEAD_P is TRUE, this class
-   is the class being defined in a class-head.
+   is the class being defined in a class-head.  If ENUM_OK is TRUE,
+   enum-names are also accepted.
 
    Returns the TYPE_DECL representing the class.  */
 
@@ -19619,7 +19601,8 @@  cp_parser_class_name (cp_parser *parser,
 		      enum tag_types tag_type,
 		      bool check_dependency_p,
 		      bool class_head_p,
-		      bool is_declaration)
+		      bool is_declaration,
+		      bool enum_ok)
 {
   tree decl;
   tree scope;
@@ -19747,7 +19730,8 @@  cp_parser_class_name (cp_parser *parser,
     }
   else if (TREE_CODE (decl) != TYPE_DECL
 	   || TREE_TYPE (decl) == error_mark_node
-	   || !MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))
+	   || !(MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))
+		|| (enum_ok && TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE))
 	   /* In Objective-C 2.0, a classname followed by '.' starts a
 	      dot-syntax expression, and it's not a type-name.  */
 	   || (c_dialect_objc ()
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum3.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum3.C
new file mode 100644
index 0000000..67a3d17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum3.C
@@ -0,0 +1,14 @@ 
+// PR c++/60994
+// { dg-do compile { target c++11 } }
+
+enum struct A
+{
+  n = 3
+};
+
+A
+foo()
+{
+  int A;
+  return A::n;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum4.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum4.C
new file mode 100644
index 0000000..80798ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum4.C
@@ -0,0 +1,20 @@ 
+// PR c++/60994
+// { dg-do compile { target c++11 } }
+
+struct B {
+  enum struct A
+  {
+    n = 3
+  };
+};
+
+struct C: B
+{
+  using B::A;
+
+  A foo()
+  {
+    int A;
+    return A::n;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ23.C b/gcc/testsuite/g++.dg/cpp1y/var-templ23.C
index a5b19d2..80d8217 100644
--- a/gcc/testsuite/g++.dg/cpp1y/var-templ23.C
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ23.C
@@ -3,5 +3,7 @@ 
 
 namespace std {
   template <typename T> int declval;
-  typename std::declval<> d;	// { dg-error "not a type" }
+  typename std::declval<> d;	// { dg-error "type" }
 }
+
+// { dg-prune-output "expected" }