]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/19787 (Internal compiler error with ambiguous conversion functions)
authorMark Mitchell <mark@codesourcery.com>
Thu, 10 Feb 2005 00:34:46 +0000 (00:34 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 10 Feb 2005 00:34:46 +0000 (00:34 +0000)
PR c++/19787
* call.c (initialize_reference): Robustify.

PR ++/19732
* decl.c (grokdeclarator): Check for invalid use of destructor
names.

PR c++/19762
* parser.c (cp_parser_unqualified_id): Avoid creating destructor
names with invalid types.

PR c++/19826
* parser.c (cp_parser_direct_declarator): Allow type-dependent
expressions as array bounds.

PR c++/19739
* parser.c (cp_parser_attributes_list): Allow empty lists.

PR c++/19787
* g++.dg/conversion/ambig1.C: New test.

PR c++/19739
* g++.dg/ext/attrib19.C: New test.

PR c++/19732
* g++.dg/parse/dtor5.C: New test.

PR c++/19762
* g++.dg/template/dtor3.C: New test.

PR c++/19826
* g++.dg/template/static11.C: New test.
* g++.dg/template/crash2.C: Remove dg-error marker.

From-SVN: r94788

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/decl.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/conversion/ambig1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attrib19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/dtor5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/crash2.C
gcc/testsuite/g++.dg/template/dtor3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/static11.C [new file with mode: 0644]

index dc5609f1a731e0bdef2a4ad50f7c235f7350d1c0..01d7f75dbd810f76f9dd036c24cad7df4c352d71 100644 (file)
@@ -1,3 +1,23 @@
+2005-02-09  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/19787
+       * call.c (initialize_reference): Robustify.
+
+       PR ++/19732
+       * decl.c (grokdeclarator): Check for invalid use of destructor
+       names.
+
+       PR c++/19762
+       * parser.c (cp_parser_unqualified_id): Avoid creating destructor
+       names with invalid types.
+
+       PR c++/19826
+       * parser.c (cp_parser_direct_declarator): Allow type-dependent
+       expressions as array bounds.
+
+       PR c++/19739
+       * parser.c (cp_parser_attributes_list): Allow empty lists.
+
 2005-02-08  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/19733
index 599aecfa84aaf917d795abca9efe8fd7a0f8e354..5d931c8b6e30026f64f7c60829f3c7c362ef0750 100644 (file)
@@ -6534,81 +6534,86 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
                                /*inner=*/-1,
                                /*issue_conversion_warnings=*/true,
                                /*c_cast_p=*/false);
-      if (!real_lvalue_p (expr))
+      if (error_operand_p (expr))
+       expr = error_mark_node;
+      else
        {
-         tree init;
-         tree type;
-
-         /* Create the temporary variable.  */
-         type = TREE_TYPE (expr);
-         var = make_temporary_var_for_ref_to_temp (decl, type);
-         layout_decl (var, 0);
-         /* If the rvalue is the result of a function call it will be
-            a TARGET_EXPR.  If it is some other construct (such as a
-            member access expression where the underlying object is
-            itself the result of a function call), turn it into a
-            TARGET_EXPR here.  It is important that EXPR be a
-            TARGET_EXPR below since otherwise the INIT_EXPR will
-            attempt to make a bitwise copy of EXPR to initialize
-            VAR.  */
-         if (TREE_CODE (expr) != TARGET_EXPR)
-           expr = get_target_expr (expr);
-         /* Create the INIT_EXPR that will initialize the temporary
-            variable.  */
-         init = build2 (INIT_EXPR, type, var, expr);
-         if (at_function_scope_p ())
+         if (!real_lvalue_p (expr))
            {
-             add_decl_expr (var);
-             *cleanup = cxx_maybe_build_cleanup (var);
-
-             /* We must be careful to destroy the temporary only
-                after its initialization has taken place.  If the
-                initialization throws an exception, then the
-                destructor should not be run.  We cannot simply
-                transform INIT into something like:
-            
-                    (INIT, ({ CLEANUP_STMT; }))
-
-                because emit_local_var always treats the
-                initializer as a full-expression.  Thus, the
-                destructor would run too early; it would run at the
-                end of initializing the reference variable, rather
-                than at the end of the block enclosing the
-                reference variable.
-
-                The solution is to pass back a cleanup expression
-                which the caller is responsible for attaching to
-                the statement tree.  */
+             tree init;
+             tree type;
+
+             /* Create the temporary variable.  */
+             type = TREE_TYPE (expr);
+             var = make_temporary_var_for_ref_to_temp (decl, type);
+             layout_decl (var, 0);
+             /* If the rvalue is the result of a function call it will be
+                a TARGET_EXPR.  If it is some other construct (such as a
+                member access expression where the underlying object is
+                itself the result of a function call), turn it into a
+                TARGET_EXPR here.  It is important that EXPR be a
+                TARGET_EXPR below since otherwise the INIT_EXPR will
+                attempt to make a bitwise copy of EXPR to initialize
+                VAR.  */
+             if (TREE_CODE (expr) != TARGET_EXPR)
+               expr = get_target_expr (expr);
+             /* Create the INIT_EXPR that will initialize the temporary
+                variable.  */
+             init = build2 (INIT_EXPR, type, var, expr);
+             if (at_function_scope_p ())
+               {
+                 add_decl_expr (var);
+                 *cleanup = cxx_maybe_build_cleanup (var);
+
+                 /* We must be careful to destroy the temporary only
+                    after its initialization has taken place.  If the
+                    initialization throws an exception, then the
+                    destructor should not be run.  We cannot simply
+                    transform INIT into something like:
+
+                        (INIT, ({ CLEANUP_STMT; }))
+
+                    because emit_local_var always treats the
+                    initializer as a full-expression.  Thus, the
+                    destructor would run too early; it would run at the
+                    end of initializing the reference variable, rather
+                    than at the end of the block enclosing the
+                    reference variable.
+
+                    The solution is to pass back a cleanup expression
+                    which the caller is responsible for attaching to
+                    the statement tree.  */
+               }
+             else
+               {
+                 rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
+                 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+                   static_aggregates = tree_cons (NULL_TREE, var,
+                                                  static_aggregates);
+               }
+             /* Use its address to initialize the reference variable.  */
+             expr = build_address (var);
+             if (base_conv_type)
+               expr = convert_to_base (expr, 
+                                       build_pointer_type (base_conv_type),
+                                       /*check_access=*/true,
+                                       /*nonnull=*/true);
+             expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
            }
          else
-           {
-             rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
-             if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-               static_aggregates = tree_cons (NULL_TREE, var,
-                                              static_aggregates);
-           }
-         /* Use its address to initialize the reference variable.  */
-         expr = build_address (var);
+           /* Take the address of EXPR.  */
+           expr = build_unary_op (ADDR_EXPR, expr, 0);
+         /* If a BASE_CONV was required, perform it now.  */
          if (base_conv_type)
-           expr = convert_to_base (expr, 
-                                   build_pointer_type (base_conv_type),
-                                   /*check_access=*/true,
-                                   /*nonnull=*/true);
-         expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
+           expr = (perform_implicit_conversion 
+                   (build_pointer_type (base_conv_type), expr));
+         expr = build_nop (type, expr);
        }
-      else
-       /* Take the address of EXPR.  */
-       expr = build_unary_op (ADDR_EXPR, expr, 0);
-      /* If a BASE_CONV was required, perform it now.  */
-      if (base_conv_type)
-       expr = (perform_implicit_conversion 
-               (build_pointer_type (base_conv_type), expr));
-      expr = build_nop (type, expr);
     }
   else
     /* Perform the conversion.  */
     expr = convert_like (conv, expr);
-  
+
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
 
index 4d8059fc46adda4dadb9c99791f2f349ecdadfa9..05918f553f97fb880afe5c255ef50799a0d27f21 100644 (file)
@@ -6553,9 +6553,22 @@ grokdeclarator (const cp_declarator *declarator,
              {
              case BIT_NOT_EXPR:
                {
-                 tree type = TREE_OPERAND (decl, 0);
-                 type = constructor_name (type);
-                 name = IDENTIFIER_POINTER (type);
+                 tree type;
+
+                 if (innermost_code != cdk_function)
+                   {
+                     error ("declaration of %qD as non-function", decl);
+                     return error_mark_node;
+                   }
+                 else if (!qualifying_scope 
+                          && !(current_class_type && at_class_scope_p ()))
+                   {
+                     error ("declaration of %qD as non-member", decl);
+                     return error_mark_node;
+                   }
+                 
+                 type = TREE_OPERAND (decl, 0);
+                 name = IDENTIFIER_POINTER (constructor_name (type));
                }
                break;
 
@@ -7803,15 +7816,6 @@ grokdeclarator (const cp_declarator *declarator,
            int publicp = 0;
            tree function_context;
 
-           /* We catch the others as conflicts with the builtin
-              typedefs.  */
-           if (friendp && unqualified_id == ridpointers[(int) RID_SIGNED])
-             {
-               error ("function %qD cannot be declared friend",
-                      unqualified_id);
-               friendp = 0;
-             }
-
            if (friendp == 0)
              {
                if (ctype == NULL_TREE)
@@ -7849,6 +7853,18 @@ grokdeclarator (const cp_declarator *declarator,
                                                     TYPE_ARG_TYPES (type));
              }
 
+           /* Check that the name used for a destructor makes sense.  */
+           if (sfk == sfk_destructor
+               && !same_type_p (TREE_OPERAND 
+                                (id_declarator->u.id.unqualified_name, 0),
+                                ctype))
+             {
+               error ("declaration of %qD as member of %qT", 
+                      id_declarator->u.id.unqualified_name,
+                      ctype);
+               return error_mark_node;
+             }
+
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
            function_context = (ctype != NULL_TREE) ?
              decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
index 6e797532153bc79e5e5e7638a8c1ba012549a144..f4e8ea28cc1669f42f3fd5ca301ea2fc8aa92006 100644 (file)
@@ -3173,6 +3173,7 @@ cp_parser_unqualified_id (cp_parser* parser,
        tree qualifying_scope;
        tree object_scope;
        tree scope;
+       bool done;
 
        /* Consume the `~' token.  */
        cp_lexer_consume_token (parser->lexer);
@@ -3229,6 +3230,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 
        /* If there was an explicit qualification (S::~T), first look
           in the scope given by the qualification (i.e., S).  */
+       done = false;
        if (scope)
          {
            cp_parser_parse_tentatively (parser);
@@ -3240,10 +3242,10 @@ cp_parser_unqualified_id (cp_parser* parser,
                                              /*class_head_p=*/false,
                                              declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* In "N::S::~S", look in "N" as well.  */
-       if (scope && qualifying_scope)
+       if (!done && scope && qualifying_scope)
          {
            cp_parser_parse_tentatively (parser);
            parser->scope = qualifying_scope;
@@ -3258,10 +3260,10 @@ cp_parser_unqualified_id (cp_parser* parser,
                                      /*class_head_p=*/false,
                                      declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* In "p->S::~T", look in the scope given by "*p" as well.  */
-       else if (object_scope)
+       else if (!done && object_scope)
          {
            cp_parser_parse_tentatively (parser);
            parser->scope = object_scope;
@@ -3276,20 +3278,23 @@ cp_parser_unqualified_id (cp_parser* parser,
                                      /*class_head_p=*/false,
                                      declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* Look in the surrounding context.  */
-       parser->scope = NULL_TREE;
-       parser->object_scope = NULL_TREE;
-       parser->qualifying_scope = NULL_TREE;
-       type_decl
-         = cp_parser_class_name (parser,
-                                 /*typename_keyword_p=*/false,
-                                 /*template_keyword_p=*/false,
-                                 none_type,
-                                 /*check_dependency=*/false,
-                                 /*class_head_p=*/false,
-                                 declarator_p);
+       if (!done)
+         {
+           parser->scope = NULL_TREE;
+           parser->object_scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           type_decl
+             = cp_parser_class_name (parser,
+                                     /*typename_keyword_p=*/false,
+                                     /*template_keyword_p=*/false,
+                                     none_type,
+                                     /*check_dependency=*/false,
+                                     /*class_head_p=*/false,
+                                     declarator_p);
+         }
        /* If an error occurred, assume that the name of the
           destructor is the same as the name of the qualifying
           class.  That allows us to keep parsing after running
@@ -11099,7 +11104,17 @@ cp_parser_direct_declarator (cp_parser* parser,
                                                 &non_constant_p);
              if (!non_constant_p)
                bounds = fold_non_dependent_expr (bounds);
-             else if (!at_function_scope_p ())
+             /* Normally, the array bound must be an integral constant
+                expression.  However, as an extension, we allow VLAs
+                in function scopes.  And, we allow type-dependent
+                expressions in templates; sometimes we don't know for
+                sure whether or not something is a valid integral
+                constant expression until instantiation time.  (It
+                doesn't make sense to check for value-dependency, as
+                an expression is only value-dependent when it is a
+                constant expression.)  */  
+             else if (!type_dependent_expression_p (bounds)
+                      && !at_function_scope_p ())
                {
                  error ("array bound is not an integer constant");
                  bounds = error_mark_node;
@@ -14042,10 +14057,10 @@ cp_parser_attributes_opt (cp_parser* parser)
      identifier ( identifier , expression-list )
      identifier ( expression-list )
 
-   Returns a TREE_LIST.  Each node corresponds to an attribute.  THe
-   TREE_PURPOSE of each node is the identifier indicating which
-   attribute is in use.  The TREE_VALUE represents the arguments, if
-   any.  */
+   Returns a TREE_LIST, or NULL_TREE on error.  Each node corresponds
+   to an attribute.  The TREE_PURPOSE of each node is the identifier
+   indicating which attribute is in use.  The TREE_VALUE represents
+   the arguments, if any.  */
 
 static tree
 cp_parser_attribute_list (cp_parser* parser)
@@ -14063,37 +14078,39 @@ cp_parser_attribute_list (cp_parser* parser)
       /* Look for the identifier.  We also allow keywords here; for
         example `__attribute__ ((const))' is legal.  */
       token = cp_lexer_peek_token (parser->lexer);
-      if (token->type != CPP_NAME
-         && token->type != CPP_KEYWORD)
-       return error_mark_node;
-      /* Consume the token.  */
-      token = cp_lexer_consume_token (parser->lexer);
+      if (token->type == CPP_NAME
+         || token->type == CPP_KEYWORD)
+       {
+         /* Consume the token.  */
+         token = cp_lexer_consume_token (parser->lexer);
 
-      /* Save away the identifier that indicates which attribute this is.  */
-      identifier = token->value;
-      attribute = build_tree_list (identifier, NULL_TREE);
+         /* Save away the identifier that indicates which attribute
+            this is.  */ 
+         identifier = token->value;
+         attribute = build_tree_list (identifier, NULL_TREE);
 
-      /* Peek at the next token.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      /* If it's an `(', then parse the attribute arguments.  */
-      if (token->type == CPP_OPEN_PAREN)
-       {
-         tree arguments;
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_token (parser->lexer);
+         /* If it's an `(', then parse the attribute arguments.  */
+         if (token->type == CPP_OPEN_PAREN)
+           {
+             tree arguments;
 
-         arguments = (cp_parser_parenthesized_expression_list
-                      (parser, true, /*cast_p=*/false, 
-                       /*non_constant_p=*/NULL));
-         /* Save the identifier and arguments away.  */
-         TREE_VALUE (attribute) = arguments;
-       }
+             arguments = (cp_parser_parenthesized_expression_list
+                          (parser, true, /*cast_p=*/false, 
+                           /*non_constant_p=*/NULL));
+             /* Save the identifier and arguments away.  */
+             TREE_VALUE (attribute) = arguments;
+           }
 
-      /* Add this attribute to the list.  */
-      TREE_CHAIN (attribute) = attribute_list;
-      attribute_list = attribute;
+         /* Add this attribute to the list.  */
+         TREE_CHAIN (attribute) = attribute_list;
+         attribute_list = attribute;
 
-      /* Now, look for more attributes.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      /* If the next token isn't a `,', we're done.  */
+         token = cp_lexer_peek_token (parser->lexer);
+       }
+      /* Now, look for more attributes.  If the next token isn't a
+        `,', we're done.  */
       if (token->type != CPP_COMMA)
        break;
 
index 0fda16e56bfc20249888c0a3706db55746712bf2..ace4d02e9b8658daf674a4c8d8e125b8fbc0206b 100644 (file)
@@ -1,3 +1,21 @@
+2005-02-09  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/19787
+       * g++.dg/conversion/ambig1.C: New test.
+
+       PR c++/19739
+       * g++.dg/ext/attrib19.C: New test.
+
+       PR c++/19732
+       * g++.dg/parse/dtor5.C: New test.
+
+       PR c++/19762
+       * g++.dg/template/dtor3.C: New test.
+
+       PR c++/19826
+       * g++.dg/template/static11.C: New test.
+       * g++.dg/template/crash2.C: Remove dg-error marker.
+
 2005-02-09  Janis Johnson  <janis187@us.ibm.com>
 
        PR C++/18491
diff --git a/gcc/testsuite/g++.dg/conversion/ambig1.C b/gcc/testsuite/g++.dg/conversion/ambig1.C
new file mode 100644 (file)
index 0000000..42ac403
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/19787
+
+struct H {
+  operator char(); // { dg-error "" }
+  operator short(); // { dg-error "" }
+};
+
+int const& ref = H(); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/ext/attrib19.C b/gcc/testsuite/g++.dg/ext/attrib19.C
new file mode 100644 (file)
index 0000000..f1362c3
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/19739
+
+void Dummy() __attribute__(( , ));
+void Dummy() {}
+
+int main (int argc, char **argv)
+{
+    Dummy();
+    return 0;
+}
diff --git a/gcc/testsuite/g++.dg/parse/dtor5.C b/gcc/testsuite/g++.dg/parse/dtor5.C
new file mode 100644 (file)
index 0000000..297a0e7
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/19732
+
+struct A;
+typedef int ~A; // { dg-error "non-function" }
+struct B { 
+  ~A(); // { dg-error "" }
+  typedef int ~A; // { dg-error "non-function" }
+  void f() {
+    extern ~B(); // { dg-error "non-member" }
+  }
+};
+void ~A(); // { dg-error "non-member" }
index 8bf7b450df256673e4b1217defe3b8da845acd1a..a02787a46fa0b8db20a7187677bb27b2c0fbf263 100644 (file)
@@ -5,7 +5,7 @@ class A
 {
 public:
   static const EnumType size = max; // { dg-error "" }
-  int table[size]; // { dg-error "" }
+  int table[size];
 };
 template <class EnumType>
 const EnumType A<EnumType>::size;
diff --git a/gcc/testsuite/g++.dg/template/dtor3.C b/gcc/testsuite/g++.dg/template/dtor3.C
new file mode 100644 (file)
index 0000000..7f40998
--- /dev/null
@@ -0,0 +1,4 @@
+// PR c++/19762
+
+template<int> struct A { ~A(){} }; // { dg-error "" }
+template A<>::~A(); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/static11.C b/gcc/testsuite/g++.dg/template/static11.C
new file mode 100644 (file)
index 0000000..3e489ea
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/19826
+
+template<typename T> struct A
+{
+  static const T i = 1;
+  char a[i];
+};
+