re PR c++/40139 (ICE on invalid use of destructor)
authorJason Merrill <jason@redhat.com>
Sun, 17 May 2009 18:01:33 +0000 (14:01 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 17 May 2009 18:01:33 +0000 (14:01 -0400)
PR c++/40139
* pt.c (tsubst_qualified_id): Retain the type if we aren't dealing
with a dependent type.  Actually look up the destructor.
* semantics.c (finish_id_expression): Fix logic.
(finish_qualified_id_expr): Don't try to use 'this' if we aren't in
a function.
* typeck.c (build_x_unary_op): Diagnose taking the address of a
constructor or destructor.
* tree.c (get_first_fn): Handle OFFSET_REF.

From-SVN: r147638

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/dtor6.C [new file with mode: 0644]

index bffec90..af4b69c 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-16  Jason Merrill  <jason@redhat.com>
+
+       PR c++/40139
+       * pt.c (tsubst_qualified_id): Retain the type if we aren't dealing
+       with a dependent type.  Actually look up the destructor.
+       * semantics.c (finish_id_expression): Fix logic.
+       (finish_qualified_id_expr): Don't try to use 'this' if we aren't in
+       a function.
+       * typeck.c (build_x_unary_op): Diagnose taking the address of a
+       constructor or destructor.
+       * tree.c (get_first_fn): Handle OFFSET_REF.
+
 2009-05-17  Joseph Myers  <joseph@codesourcery.com>
 
        * tree.c (cxx_printable_name_internal): Allow consecutive
index e100d6b..2ca28d6 100644 (file)
@@ -9930,16 +9930,29 @@ tsubst_qualified_id (tree qualified_id, tree args,
     expr = name;
 
   if (dependent_type_p (scope))
-    return build_qualified_name (/*type=*/NULL_TREE,
-                                scope, expr,
-                                QUALIFIED_NAME_IS_TEMPLATE (qualified_id));
+    {
+      tree type = NULL_TREE;
+      if (DECL_P (expr) && !dependent_scope_p (scope))
+       type = TREE_TYPE (expr);
+      return build_qualified_name (type, scope, expr,
+                                  QUALIFIED_NAME_IS_TEMPLATE (qualified_id));
+    }
 
   if (!BASELINK_P (name) && !DECL_P (expr))
     {
       if (TREE_CODE (expr) == BIT_NOT_EXPR)
-       /* If this were actually a destructor call, it would have been
-          parsed as such by the parser.  */
-       expr = error_mark_node;
+       {
+         /* A BIT_NOT_EXPR is used to represent a destructor.  */
+         if (!check_dtor_name (scope, TREE_OPERAND (expr, 0)))
+           {
+             error ("qualifying type %qT does not match destructor name ~%qT",
+                    scope, TREE_OPERAND (expr, 0));
+             expr = error_mark_node;
+           }
+         else
+           expr = lookup_qualified_name (scope, complete_dtor_identifier,
+                                         /*is_type_p=*/0, false);
+       }
       else
        expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0, false);
       if (TREE_CODE (TREE_CODE (expr) == TEMPLATE_DECL
index 8c0a1e5..18aa051 100644 (file)
@@ -1664,11 +1664,10 @@ finish_qualified_id_expr (tree qualifying_class,
       fns = BASELINK_FUNCTIONS (expr);
       if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
        fns = TREE_OPERAND (fns, 0);
-      /* If so, the expression may be relative to the current
-        class.  */
+      /* If so, the expression may be relative to 'this'.  */
       if (!shared_member_p (fns)
-         && current_class_type
-         && DERIVED_FROM_P (qualifying_class, current_class_type))
+         && current_class_ref
+         && DERIVED_FROM_P (qualifying_class, TREE_TYPE (current_class_ref)))
        expr = (build_class_member_access_expr
                (maybe_dummy_object (qualifying_class, NULL),
                 expr,
@@ -2871,16 +2870,16 @@ finish_id_expression (tree id_expression,
                                                     done, address_p,
                                                     template_p,
                                                     template_arg_p);
-                 else if (dependent_scope_p (scope))
-                   decl = build_qualified_name (/*type=*/NULL_TREE,
-                                                scope,
-                                                id_expression,
-                                                template_p);
-                 else if (DECL_P (decl))
-                   decl = build_qualified_name (TREE_TYPE (decl),
-                                                scope,
-                                                id_expression,
-                                                template_p);
+                 else
+                   {
+                     tree type = NULL_TREE;
+                     if (DECL_P (decl) && !dependent_scope_p (scope))
+                       type = TREE_TYPE (decl);
+                     decl = build_qualified_name (type,
+                                                  scope,
+                                                  id_expression,
+                                                  template_p);
+                   }
                }
              if (TREE_TYPE (decl))
                decl = convert_from_reference (decl);
index 219cb39..f1868f5 100644 (file)
@@ -1200,7 +1200,8 @@ get_first_fn (tree from)
 {
   gcc_assert (is_overloaded_fn (from));
   /* A baselink is also considered an overloaded function.  */
-  if (TREE_CODE (from) == COMPONENT_REF)
+  if (TREE_CODE (from) == OFFSET_REF
+      || TREE_CODE (from) == COMPONENT_REF)
     from = TREE_OPERAND (from, 1);
   if (BASELINK_P (from))
     from = BASELINK_FUNCTIONS (from);
index 4486b90..069a057 100644 (file)
@@ -4141,8 +4141,20 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
                        /*overloaded_p=*/NULL, complain);
   if (!exp && code == ADDR_EXPR)
     {
-      /*  A pointer to member-function can be formed only by saying
-         &X::mf.  */
+      if (is_overloaded_fn (xarg))
+       {
+         tree fn = get_first_fn (xarg);
+         if (DECL_CONSTRUCTOR_P (fn) || DECL_DESTRUCTOR_P (fn))
+           {
+             const char *type =
+               (DECL_CONSTRUCTOR_P (fn) ? "constructor" : "destructor");
+             error ("taking address of %s %qE", type, xarg);
+             return error_mark_node;
+           }
+       }
+
+      /* A pointer to member-function can be formed only by saying
+        &X::mf.  */
       if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
          && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
        {
index 2f0e185..1494ae9 100644 (file)
@@ -1,3 +1,8 @@
+2009-05-17  Jason Merrill  <jason@redhat.com>
+
+       PR c++/40139
+       * g++.dg/template/dtor6.C: New.
+
 2009-05-17  Joseph Myers  <joseph@codesourcery.com>
 
        * g++.dg/warn/translate-ice-1.C: New test.
diff --git a/gcc/testsuite/g++.dg/template/dtor6.C b/gcc/testsuite/g++.dg/template/dtor6.C
new file mode 100644 (file)
index 0000000..c44b780
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/40139
+
+template<int> struct A
+{
+  static int i;
+};
+
+template<int N> int A<N>::i = { A::~A }; // { dg-error "non-static member function" }
+
+template class A<0>;
+
+struct X { };
+
+int i1 = X::~X;                        // { dg-error "non-static member function" }
+int i2 = &X::~X;               // { dg-error "address of destructor" }
+int i3 = &A<0>::~A;            // { dg-error "address of destructor" }