C++ PATCH for c++/52596 (C++11 ICE with qualified-id in template)

Message ID 4F7EED1A.4040807@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 6, 2012, 1:18 p.m.
Since in C++11 the things you can do with an lvalue are no longer a 
superset of the things you can do with an rvalue (specifically, you 
can't bind one to an rvalue reference) we can't just conservatively 
assume that an expression is an lvalue in a template and then get a 
better answer later.  So we've started looking into NON_DEPENDENT_EXPR 
in lvalue_kind.  But that breaks on this testcase; when we encounter a 
qualified-id in a template we build up a SCOPE_REF for it even though we 
know what it refers to so that we can do access control at instantiation 
time, and lvalue_kind didn't know how to deal with that.

For 4.8 I'm fixing this by changing the second operand of the SCOPE_REF 
to be the decl found by lookup, as the instantiation code already knows 
what to do with that.  For 4.7 I'm just conservatively assuming it's a 
regular lvalue; it has to be an lvalue because it's something with a 
name, and if it's a field it's a member of *this, which is an lvalue. 
It might be a bit-field, but bit-field semantics are a strict subset of 
normal lvalue semantics, so this is OK.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.7.


commit 078e78553f6e1a3727dedf10ab2825c96552e86d
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Apr 5 14:41:25 2012 -0400

    	PR c++/52596
    	* tree.c (lvalue_kind): Treat a deferred access control SCOPE_REF
    	as an lvalue.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2bb2801..9129a7e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -150,8 +150,14 @@  lvalue_kind (const_tree ref)
       /* A scope ref in a template, left as SCOPE_REF to support later
 	 access checking.  */
     case SCOPE_REF:
-      gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE(ref)));
-      return lvalue_kind (TREE_OPERAND (ref, 1));
+      {
+	tree op = TREE_OPERAND (ref, 1);
+	/* The member must be an lvalue; assume it isn't a bit-field.  */
+	  return clk_ordinary;
+	gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref)));
+	return lvalue_kind (op);
+      }
     case MAX_EXPR:
     case MIN_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/qualified-id5.C b/gcc/testsuite/g++.dg/template/qualified-id5.C
new file mode 100644
index 0000000..3126d33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/qualified-id5.C
@@ -0,0 +1,17 @@ 
+// PR c++/52596
+struct msgpack_zone_finalizer_array {
+    int* tail;
+struct msgpack_zone {
+    msgpack_zone_finalizer_array finalizer_array;
+struct zone : public msgpack_zone {
+    template <typename T> T* allocate();
+template <typename T>
+T* zone::allocate()
+  --msgpack_zone::finalizer_array.tail;