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 8710fe66438bef24c30444eec07c7a82222d6661
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Apr 5 14:41:25 2012 -0400

    	PR c++/52596
    	* semantics.c (finish_non_static_data_member): In templates, pass
    	the decl to build_qualified_name.
    	* tree.c (lvalue_kind) [SCOPE_REF]: Handle FIELD_DECL.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 65b771f..9bdd2ee 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1590,7 +1590,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
   else if (processing_template_decl)
     return build_qualified_name (TREE_TYPE (decl),
 				 qualifying_scope,
-				 DECL_NAME (decl),
+				 decl,
 				 /*template_p=*/false);
   else
     {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 992c22a..b5a360f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -151,8 +151,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));
+      gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref)));
+      {
+	tree op = TREE_OPERAND (ref, 1);
+	if (TREE_CODE (op) == FIELD_DECL)
+	  return (DECL_C_BIT_FIELD (op) ? clk_bitfield : clk_ordinary);
+	else
+	  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;
+}
commit 078e78553f6e1a3727dedf10ab2825c96552e86d
Author: Jason Merrill <ja...@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.  */
+	if (TREE_CODE (op) == IDENTIFIER_NODE)
+	  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;
+}

Reply via email to