re PR c++/52748 ([C++11] N3276 changes to decltype)
authorJason Merrill <jason@redhat.com>
Sun, 17 Mar 2013 02:37:09 +0000 (22:37 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 17 Mar 2013 02:37:09 +0000 (22:37 -0400)
N3276
PR c++/52748
* cp-tree.h (tsubst_flags): Add tf_decltype.
* call.c (build_cxx_call): Don't build a temporary if it's set.
(build_over_call): Make sure it's only passed to build_cxx_call.
* parser.c (cp_parser_primary_expression): Add decltype_p parm.
(cp_parser_unary_expression): Likewise.
(cp_parser_cast_expression): Likewise.
(cp_parser_binary_expression): Likewise.
(cp_parser_assignment_expression): Likewise.
(cp_parser_postfix_expression): Likewise.  Pass tf_decltype.
(cp_parser_explicit_instantiation): Add decltype_p.  Force a
temporary for a call on the LHS of a comma.
(cp_parser_decltype): Pass true to decltype_p parms.
* pt.c (tsubst) [DECLTYPE_TYPE]: Pass tf_decltype.
(tsubst_copy_and_build): Pass tf_decltype down only for
CALL_EXPR and the RHS of COMPOUND_EXPR.
* tree.c (build_cplus_new): Call complete_type_or_maybe_complain.

From-SVN: r196736

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/cpp0x/decltype-call1.C [new file with mode: 0644]

index b57800e..580208a 100644 (file)
@@ -1,5 +1,24 @@
 2013-03-16  Jason Merrill  <jason@redhat.com>
 
+       N3276
+       PR c++/52748
+       * cp-tree.h (tsubst_flags): Add tf_decltype.
+       * call.c (build_cxx_call): Don't build a temporary if it's set.
+       (build_over_call): Make sure it's only passed to build_cxx_call.
+       * parser.c (cp_parser_primary_expression): Add decltype_p parm.
+       (cp_parser_unary_expression): Likewise.
+       (cp_parser_cast_expression): Likewise.
+       (cp_parser_binary_expression): Likewise.
+       (cp_parser_assignment_expression): Likewise.
+       (cp_parser_postfix_expression): Likewise.  Pass tf_decltype.
+       (cp_parser_explicit_instantiation): Add decltype_p.  Force a
+       temporary for a call on the LHS of a comma.
+       (cp_parser_decltype): Pass true to decltype_p parms.
+       * pt.c (tsubst) [DECLTYPE_TYPE]: Pass tf_decltype.
+       (tsubst_copy_and_build): Pass tf_decltype down only for
+       CALL_EXPR and the RHS of COMPOUND_EXPR.
+       * tree.c (build_cplus_new): Call complete_type_or_maybe_complain.
+
        * cp-tree.h (abstract_class_use): New enum.
        * typeck2.c (pending_abstract_type): Add use field.
        (abstract_virtuals_error_sfinae): Add overloads taking
index e40c45f..8362c75 100644 (file)
@@ -6693,6 +6693,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       /* else continue to get conversion error.  */
     }
 
+  /* N3276 magic doesn't apply to nested calls.  */
+  int decltype_flag = (complain & tf_decltype);
+  complain &= ~tf_decltype;
+
   /* Find maximum size of vector to hold converted arguments.  */
   parmlen = list_length (parm);
   nargs = vec_safe_length (args) + (first_arg != NULL_TREE ? 1 : 0);
@@ -7064,7 +7068,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        return error_mark_node;
     }
 
-  return build_cxx_call (fn, nargs, argarray, complain);
+  return build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
 }
 
 /* Build and return a call to FN, using NARGS arguments in ARGARRAY.
@@ -7106,12 +7110,20 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
   if (VOID_TYPE_P (TREE_TYPE (fn)))
     return fn;
 
-  fn = require_complete_type_sfinae (fn, complain);
-  if (fn == error_mark_node)
-    return error_mark_node;
+  /* 5.2.2/11: If a function call is a prvalue of object type: if the
+     function call is either the operand of a decltype-specifier or the
+     right operand of a comma operator that is the operand of a
+     decltype-specifier, a temporary object is not introduced for the
+     prvalue. The type of the prvalue may be incomplete.  */
+  if (!(complain & tf_decltype))
+    {
+      fn = require_complete_type_sfinae (fn, complain);
+      if (fn == error_mark_node)
+       return error_mark_node;
 
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn)))
-    fn = build_cplus_new (TREE_TYPE (fn), fn, complain);
+      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn)))
+       fn = build_cplus_new (TREE_TYPE (fn), fn, complain);
+    }
   return convert_from_reference (fn);
 }
 
index 53940a6..39fb3df 100644 (file)
@@ -4203,6 +4203,9 @@ enum tsubst_flags {
                                    conversion might be permissible,
                                    not actually performing the
                                    conversion.  */
+  tf_decltype = 1 << 7,          /* We are the operand of decltype.
+                                   Used to implement the special rules
+                                   for calls in decltype (5.2.2/11).  */
   tf_partial = 1 << 8,          /* Doing initial explicit argument
                                    substitution in fn_type_unification.  */
   /* Convenient substitution flags combinations.  */
index f414932..3f56ff1 100644 (file)
@@ -1802,7 +1802,7 @@ static tree cp_parser_nested_name_specifier
 static tree cp_parser_qualifying_entity
   (cp_parser *, bool, bool, bool, bool, bool);
 static tree cp_parser_postfix_expression
-  (cp_parser *, bool, bool, bool, cp_id_kind *);
+  (cp_parser *, bool, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_postfix_open_square_expression
   (cp_parser *, tree, bool);
 static tree cp_parser_postfix_dot_deref_expression
@@ -1832,7 +1832,7 @@ static vec<tree, va_gc> *cp_parser_new_initializer
 static tree cp_parser_delete_expression
   (cp_parser *);
 static tree cp_parser_cast_expression
-  (cp_parser *, bool, bool, cp_id_kind *);
+  (cp_parser *, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_binary_expression
   (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
 static tree cp_parser_question_colon_clause
@@ -1843,6 +1843,8 @@ static enum tree_code cp_parser_assignment_operator_opt
   (cp_parser *);
 static tree cp_parser_expression
   (cp_parser *, bool, cp_id_kind *);
+static tree cp_parser_expression
+  (cp_parser *, bool, bool, cp_id_kind *);
 static tree cp_parser_constant_expression
   (cp_parser *, bool, bool *);
 static tree cp_parser_builtin_offsetof
@@ -3900,6 +3902,7 @@ cp_parser_primary_expression (cp_parser *parser,
                              bool address_p,
                              bool cast_p,
                              bool template_arg_p,
+                             bool decltype_p,
                              cp_id_kind *idk)
 {
   cp_token *token = NULL;
@@ -4051,7 +4054,7 @@ cp_parser_primary_expression (cp_parser *parser,
        else
          {
            /* Parse the parenthesized expression.  */
-           expr = cp_parser_expression (parser, cast_p, idk);
+           expr = cp_parser_expression (parser, cast_p, decltype_p, idk);
            /* Let the front end know that this expression was
               enclosed in parentheses. This matters in case, for
               example, the expression is of the form `A::B', since
@@ -4403,6 +4406,17 @@ cp_parser_primary_expression (cp_parser *parser,
     }
 }
 
+static inline tree
+cp_parser_primary_expression (cp_parser *parser,
+                             bool address_p,
+                             bool cast_p,
+                             bool template_arg_p,
+                             cp_id_kind *idk)
+{
+  return cp_parser_primary_expression (parser, address_p, cast_p, template_arg_p,
+                                      /*decltype*/false, idk);
+}
+
 /* Parse an id-expression.
 
    id-expression:
@@ -5364,7 +5378,7 @@ cp_parser_qualifying_entity (cp_parser *parser,
 
 static tree
 cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
-                              bool member_access_only_p,
+                              bool member_access_only_p, bool decltype_p,
                              cp_id_kind * pidk_return)
 {
   cp_token *token;
@@ -5625,11 +5639,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
        postfix_expression
          = cp_parser_primary_expression (parser, address_p, cast_p,
                                          /*template_arg_p=*/false,
+                                         decltype_p,
                                          &idk);
       }
       break;
     }
 
+  /* Note that we don't need to worry about calling build_cplus_new on a
+     class-valued CALL_EXPR in decltype when it isn't the end of the
+     postfix-expression; unary_complex_lvalue will take care of that for
+     all these cases.  */
+
   /* Keep looping until the postfix-expression is complete.  */
   while (true)
     {
@@ -5668,8 +5688,12 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
            bool is_builtin_constant_p;
            bool saved_integral_constant_expression_p = false;
            bool saved_non_integral_constant_expression_p = false;
+           int complain = tf_warning_or_error;
            vec<tree, va_gc> *args;
 
+           if (decltype_p)
+             complain |= tf_decltype;
+
             is_member_access = false;
 
            is_builtin_constant_p
@@ -5726,7 +5750,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                          postfix_expression
                            = perform_koenig_lookup (postfix_expression, args,
                                                     /*include_std=*/false,
-                                                    tf_warning_or_error);
+                                                    complain);
                      }
                    else
                      postfix_expression
@@ -5752,7 +5776,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                          postfix_expression
                            = perform_koenig_lookup (postfix_expression, args,
                                                     /*include_std=*/false,
-                                                    tf_warning_or_error);
+                                                    complain);
                      }
                  }
              }
@@ -5784,21 +5808,21 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                         ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
                         : LOOKUP_NORMAL),
                        /*fn_p=*/NULL,
-                       tf_warning_or_error));
+                       complain));
                  }
                else
                  postfix_expression
                    = finish_call_expr (postfix_expression, &args,
                                        /*disallow_virtual=*/false,
                                        /*koenig_p=*/false,
-                                       tf_warning_or_error);
+                                       complain);
              }
            else if (TREE_CODE (postfix_expression) == OFFSET_REF
                     || TREE_CODE (postfix_expression) == MEMBER_REF
                     || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
              postfix_expression = (build_offset_ref_call_from_tree
                                    (postfix_expression, &args,
-                                    tf_warning_or_error));
+                                    complain));
            else if (idk == CP_ID_KIND_QUALIFIED)
              /* A call to a static class member, or a namespace-scope
                 function.  */
@@ -5806,14 +5830,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                = finish_call_expr (postfix_expression, &args,
                                    /*disallow_virtual=*/true,
                                    koenig_p,
-                                   tf_warning_or_error);
+                                   complain);
            else
              /* All other function calls.  */
              postfix_expression
                = finish_call_expr (postfix_expression, &args,
                                    /*disallow_virtual=*/false,
                                    koenig_p,
-                                   tf_warning_or_error);
+                                   complain);
 
            /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
            idk = CP_ID_KIND_NONE;
@@ -6414,7 +6438,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser,
 
 static tree
 cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
-                           cp_id_kind * pidk)
+                           bool decltype_p, cp_id_kind * pidk)
 {
   cp_token *token;
   enum tree_code unary_operator;
@@ -6635,7 +6659,9 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
       cast_expression
        = cp_parser_cast_expression (parser,
                                     unary_operator == ADDR_EXPR,
-                                    /*cast_p=*/false, pidk);
+                                    /*cast_p=*/false,
+                                    /*decltype*/false,
+                                    pidk);
       /* Now, build an appropriate representation.  */
       switch (unary_operator)
        {
@@ -6681,9 +6707,18 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
 
   return cp_parser_postfix_expression (parser, address_p, cast_p,
                                        /*member_access_only_p=*/false,
+                                      decltype_p,
                                       pidk);
 }
 
+static inline tree
+cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
+                           cp_id_kind * pidk)
+{
+  return cp_parser_unary_expression (parser, address_p, cast_p,
+                                    /*decltype*/false, pidk);
+}
+
 /* Returns ERROR_MARK if TOKEN is not a unary-operator.  If TOKEN is a
    unary-operator, the corresponding tree code is returned.  */
 
@@ -7162,7 +7197,7 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser)
 
 static tree
 cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
-                          cp_id_kind * pidk)
+                          bool decltype_p, cp_id_kind * pidk)
 {
   /* If it's a `(', then we might be looking at a cast.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
@@ -7236,7 +7271,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
          cp_parser_parse_definitely (parser);
          expr = cp_parser_cast_expression (parser,
                                            /*address_p=*/false,
-                                           /*cast_p=*/true, pidk);
+                                           /*cast_p=*/true,
+                                           /*decltype_p=*/false,
+                                           pidk);
 
          /* Warn about old-style casts, if so requested.  */
          if (warn_old_style_cast
@@ -7262,7 +7299,8 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
 
   /* If we get here, then it's not a cast, so it must be a
      unary-expression.  */
-  return cp_parser_unary_expression (parser, address_p, cast_p, pidk);
+  return cp_parser_unary_expression (parser, address_p, cast_p,
+                                    decltype_p, pidk);
 }
 
 /* Parse a binary expression of the general form:
@@ -7347,6 +7385,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
 static tree
 cp_parser_binary_expression (cp_parser* parser, bool cast_p,
                             bool no_toplevel_fold_p,
+                            bool decltype_p,
                             enum cp_parser_prec prec,
                             cp_id_kind * pidk)
 {
@@ -7361,7 +7400,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 
   /* Parse the first expression.  */
   current.lhs = cp_parser_cast_expression (parser, /*address_p=*/false,
-                                          cast_p, pidk);
+                                          cast_p, decltype_p, pidk);
   current.lhs_type = ERROR_MARK;
   current.prec = prec;
 
@@ -7498,6 +7537,15 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
   return current.lhs;
 }
 
+static tree
+cp_parser_binary_expression (cp_parser* parser, bool cast_p,
+                            bool no_toplevel_fold_p,
+                            enum cp_parser_prec prec,
+                            cp_id_kind * pidk)
+{
+  return cp_parser_binary_expression (parser, cast_p, no_toplevel_fold_p,
+                                     /*decltype*/false, prec, pidk);
+}
 
 /* Parse the `? expression : assignment-expression' part of a
    conditional-expression.  The LOGICAL_OR_EXPR is the
@@ -7567,12 +7615,13 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
      throw-expression
 
    CAST_P is true if this expression is the target of a cast.
+   DECLTYPE_P is true if this expression is the operand of decltype.
 
    Returns a representation for the expression.  */
 
 static tree
 cp_parser_assignment_expression (cp_parser* parser, bool cast_p,
-                                cp_id_kind * pidk)
+                                bool decltype_p, cp_id_kind * pidk)
 {
   tree expr;
 
@@ -7586,6 +7635,7 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p,
     {
       /* Parse the binary expressions (logical-or-expression).  */
       expr = cp_parser_binary_expression (parser, cast_p, false,
+                                         decltype_p,
                                          PREC_NOT_OPERATOR, pidk);
       /* If the next token is a `?' then we're actually looking at a
         conditional-expression.  */
@@ -7631,6 +7681,14 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p,
   return expr;
 }
 
+static tree
+cp_parser_assignment_expression (cp_parser* parser, bool cast_p,
+                                cp_id_kind * pidk)
+{
+  return cp_parser_assignment_expression (parser, cast_p,
+                                         /*decltype*/false, pidk);
+}
+
 /* Parse an (optional) assignment-operator.
 
    assignment-operator: one of
@@ -7722,11 +7780,14 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
      expression , assignment-expression
 
    CAST_P is true if this expression is the target of a cast.
+   DECLTYPE_P is true if this expression is the immediate operand of decltype,
+     except possibly parenthesized or on the RHS of a comma (N3276).
 
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk)
+cp_parser_expression (cp_parser* parser, bool cast_p, bool decltype_p,
+                     cp_id_kind * pidk)
 {
   tree expression = NULL_TREE;
   location_t loc = UNKNOWN_LOCATION;
@@ -7737,7 +7798,19 @@ cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk)
 
       /* Parse the next assignment-expression.  */
       assignment_expression
-       = cp_parser_assignment_expression (parser, cast_p, pidk);
+       = cp_parser_assignment_expression (parser, cast_p, decltype_p, pidk);
+
+      /* We don't create a temporary for a call that is the immediate operand
+        of decltype or on the RHS of a comma.  But when we see a comma, we
+        need to create a temporary for a call on the LHS.  */
+      if (decltype_p && !processing_template_decl
+         && TREE_CODE (assignment_expression) == CALL_EXPR
+         && CLASS_TYPE_P (TREE_TYPE (assignment_expression))
+         && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       assignment_expression
+         = build_cplus_new (TREE_TYPE (assignment_expression),
+                            assignment_expression, tf_warning_or_error);
+
       /* If this is the first assignment-expression, we can just
         save it away.  */
       if (!expression)
@@ -7761,6 +7834,12 @@ cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk)
   return expression;
 }
 
+static inline tree
+cp_parser_expression (cp_parser* parser, bool cast_p, cp_id_kind * pidk)
+{
+  return cp_parser_expression (parser, cast_p, /*decltype*/false, pidk);
+}
+
 /* Parse a constant-expression.
 
    constant-expression:
@@ -11287,7 +11366,7 @@ cp_parser_decltype (cp_parser *parser)
 
       /* Parse a class member access.  */
       expr = cp_parser_postfix_expression (parser, /*address_p=*/false,
-                                           /*cast_p=*/false,
+                                           /*cast_p=*/false, /*decltype*/true,
                                            /*member_access_only_p=*/true, NULL);
 
       if (expr 
@@ -11315,7 +11394,8 @@ cp_parser_decltype (cp_parser *parser)
       parser->greater_than_is_operator_p = true;
 
       /* Parse a full expression.  */
-      expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+      expr = cp_parser_expression (parser, /*cast_p=*/false,
+                                  /*decltype*/true, NULL);
 
       /* The `>' token might be the end of a template-id or
         template-parameter-list now.  */
@@ -22034,7 +22114,7 @@ static tree
 cp_parser_simple_cast_expression (cp_parser *parser)
 {
   return cp_parser_cast_expression (parser, /*address_p=*/false,
-                                   /*cast_p=*/false, NULL);
+                                   /*cast_p=*/false, /*decltype*/false, NULL);
 }
 
 /* Parse a functional cast to TYPE.  Returns an expression
@@ -26831,7 +26911,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl)
       op = (token->type == CPP_PLUS_PLUS
            ? PREINCREMENT_EXPR : PREDECREMENT_EXPR);
       cp_lexer_consume_token (parser->lexer);
-      lhs = cp_parser_cast_expression (parser, false, false, NULL);
+      lhs = cp_parser_simple_cast_expression (parser);
       if (lhs != decl)
        return error_mark_node;
       return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
index edc2d0b..4ffc353 100644 (file)
@@ -11781,7 +11781,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        ++c_inhibit_evaluation_warnings;
 
        type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
-                           complain, in_decl,
+                           complain|tf_decltype, in_decl,
                            /*integral_constant_expression_p=*/false);
 
        --cp_unevaluated_operand;
@@ -13417,6 +13417,12 @@ tsubst_copy_and_build (tree t,
   if (EXPR_HAS_LOCATION (t))
     input_location = EXPR_LOCATION (t);
 
+  /* N3276 decltype magic only applies to calls at the top level or on the
+     right side of a comma.  */
+  if (TREE_CODE (t) != CALL_EXPR
+      && TREE_CODE (t) != COMPOUND_EXPR)
+    complain &= ~tf_decltype;
+
   switch (TREE_CODE (t))
     {
     case USING_DECL:
@@ -13848,10 +13854,16 @@ tsubst_copy_and_build (tree t,
        complain));
 
     case COMPOUND_EXPR:
-      RETURN (build_x_compound_expr (EXPR_LOCATION (t),
-                                   RECUR (TREE_OPERAND (t, 0)),
-                                   RECUR (TREE_OPERAND (t, 1)),
-                                    complain));
+      {
+       tree op0 = tsubst_copy_and_build (TREE_OPERAND (t, 0), args,
+                                         complain & ~tf_decltype, in_decl,
+                                         /*function_p=*/false,
+                                         integral_constant_expression_p);
+       RETURN (build_x_compound_expr (EXPR_LOCATION (t),
+                                      op0,
+                                      RECUR (TREE_OPERAND (t, 1)),
+                                      complain));
+      }
 
     case CALL_EXPR:
       {
@@ -13862,6 +13874,10 @@ tsubst_copy_and_build (tree t,
        bool koenig_p;
        tree ret;
 
+       /* Don't pass tf_decltype down to subexpressions.  */
+       tsubst_flags_t decltype_flag = (complain & tf_decltype);
+       complain &= ~tf_decltype;
+
        function = CALL_EXPR_FN (t);
        /* When we parsed the expression,  we determined whether or
           not Koenig lookup should be performed.  */
@@ -14028,6 +14044,9 @@ tsubst_copy_and_build (tree t,
        if (DECL_P (function))
          mark_used (function);
 
+       /* Put back tf_decltype for the actual call.  */
+       complain |= decltype_flag;
+
        if (TREE_CODE (function) == OFFSET_REF)
          ret = build_offset_ref_call_from_tree (function, &call_args,
                                                 complain);
index 1b484b1..6dc33b9 100644 (file)
@@ -469,6 +469,9 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain)
   tree rval = build_aggr_init_expr (type, init);
   tree slot;
 
+  if (!complete_type_or_maybe_complain (type, init, complain))
+    return error_mark_node;
+
   /* Make sure that we're not trying to create an instance of an
      abstract class.  */
   if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C b/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C
new file mode 100644 (file)
index 0000000..2616bb0
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/52748
+// N3276
+// { dg-do compile { target c++11 } }
+
+struct A;                      // { dg-error "forward declaration" }
+A f();
+
+decltype(f()) g1();             // OK
+decltype(((f()))) g2b();        // OK
+decltype(42,f()) g3();          // OK
+decltype(42,45,f()) g3b();      // OK
+decltype(42,45,(f())) g3c();    // OK
+decltype(42,((45,(f())))) g3c(); // OK
+
+decltype(f(),42) g4();          // { dg-error "" }
+decltype(45,f(),42) g4b();      // { dg-error "" }
+
+class B
+{
+  ~B();                                // { dg-error "private" }
+public:
+  int i;
+  void operator[](int);
+};
+B h();
+
+void i(const B&);
+
+decltype(h()) g5a();           // OK
+decltype(h().i) g5();          // { dg-error "" }
+decltype(h()[0]) g6();         // { dg-error "" }
+decltype(i(h())) g7();         // { dg-error "" }