Handle TYPE_HAS_LATE_RETURN_TYPE like ref-qualifier and eh spec.
authorJason Merrill <jason@redhat.com>
Mon, 14 May 2018 20:08:11 +0000 (16:08 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 14 May 2018 20:08:11 +0000 (16:08 -0400)
* tree.c (build_cp_fntype_variant): New.
(build_ref_qualified_type, build_exception_variant)
(strip_typedefs, cxx_copy_lang_qualifiers): Use it.
(cxx_type_hash_eq, cp_check_qualified_type): Check
TYPE_HAS_LATE_RETURN_TYPE.
(cp_build_type_attribute_variant): Check cxx_type_hash_eq.
(cp_build_qualified_type_real): No need to preserve C++ qualifiers.
* class.c (build_clone): Use cxx_copy_lang_qualifiers.
(adjust_clone_args): Likewise.
* decl.c (grokfndecl): Add late_return_type_p parameter.  Use
build_cp_fntype_variant.
(grokdeclarator): Pass late_return_type_p to grokfndecl.
(check_function_type): Use cxx_copy_lang_qualifiers.
(static_fn_type): Use cxx_copy_lang_qualifiers.
* decl2.c (build_memfn_type, maybe_retrofit_in_chrg)
(cp_reconstruct_complex_type, coerce_new_type, coerce_delete_type)
(change_return_type): Use cxx_copy_lang_qualifiers.
* mangle.c (write_type): Use cxx_copy_lang_qualifiers.
* parser.c (cp_parser_lambda_declarator_opt): Represent an explicit
return type on the declarator like a normal trailing return type.
* pt.c (tsubst_function_type): Use build_cp_fntype_variant.
(copy_default_args_to_explicit_spec): Use cxx_copy_lang_qualifiers.
* typeck.c (merge_types): Use build_cp_fntype_variant.

From-SVN: r260238

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c

index c421471..27ff8f3 100644 (file)
@@ -1,3 +1,30 @@
+2018-05-14  Jason Merrill  <jason@redhat.com>
+
+       Handle TYPE_HAS_LATE_RETURN_TYPE like ref-qualifier and eh spec.
+       * tree.c (build_cp_fntype_variant): New.
+       (build_ref_qualified_type, build_exception_variant)
+       (strip_typedefs, cxx_copy_lang_qualifiers): Use it.
+       (cxx_type_hash_eq, cp_check_qualified_type): Check
+       TYPE_HAS_LATE_RETURN_TYPE.
+       (cp_build_type_attribute_variant): Check cxx_type_hash_eq.
+       (cp_build_qualified_type_real): No need to preserve C++ qualifiers.
+       * class.c (build_clone): Use cxx_copy_lang_qualifiers.
+       (adjust_clone_args): Likewise.
+       * decl.c (grokfndecl): Add late_return_type_p parameter.  Use
+       build_cp_fntype_variant.
+       (grokdeclarator): Pass late_return_type_p to grokfndecl.
+       (check_function_type): Use cxx_copy_lang_qualifiers.
+       (static_fn_type): Use cxx_copy_lang_qualifiers.
+       * decl2.c (build_memfn_type, maybe_retrofit_in_chrg)
+       (cp_reconstruct_complex_type, coerce_new_type, coerce_delete_type)
+       (change_return_type): Use cxx_copy_lang_qualifiers.
+       * mangle.c (write_type): Use cxx_copy_lang_qualifiers.
+       * parser.c (cp_parser_lambda_declarator_opt): Represent an explicit
+       return type on the declarator like a normal trailing return type.
+       * pt.c (tsubst_function_type): Use build_cp_fntype_variant.
+       (copy_default_args_to_explicit_spec): Use cxx_copy_lang_qualifiers.
+       * typeck.c (merge_types): Use build_cp_fntype_variant.
+
 2018-05-14  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * cp-tree.h (TYPE_REF_P): New.
index e51946d..306ee29 100644 (file)
@@ -4469,13 +4469,8 @@ build_clone (tree fn, tree name)
      type.  */
   if (DECL_HAS_IN_CHARGE_PARM_P (clone))
     {
-      tree basetype;
-      tree parmtypes;
-      tree exceptions;
-
-      exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
-      basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
-      parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
+      tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
+      tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
       /* Skip the `this' parameter.  */
       parmtypes = TREE_CHAIN (parmtypes);
       /* Skip the in-charge parameter.  */
@@ -4494,12 +4489,11 @@ build_clone (tree fn, tree name)
        = build_method_type_directly (basetype,
                                      TREE_TYPE (TREE_TYPE (clone)),
                                      parmtypes);
-      if (exceptions)
-       TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone),
-                                                    exceptions);
       TREE_TYPE (clone)
        = cp_build_type_attribute_variant (TREE_TYPE (clone),
                                           TYPE_ATTRIBUTES (TREE_TYPE (fn)));
+      TREE_TYPE (clone)
+       = cxx_copy_lang_qualifiers (TREE_TYPE (clone), TREE_TYPE (fn));
     }
 
   /* Copy the function parameters.  */
@@ -4687,11 +4681,6 @@ adjust_clone_args (tree decl)
            {
              /* A default parameter has been added. Adjust the
                 clone's parameters.  */
-             tree exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
-             tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (clone));
-             tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
-             tree type;
-
              clone_parms = orig_decl_parms;
 
              if (DECL_HAS_VTT_PARM_P (clone))
@@ -4701,13 +4690,15 @@ adjust_clone_args (tree decl)
                                           clone_parms);
                  TREE_TYPE (clone_parms) = TREE_TYPE (orig_clone_parms);
                }
-             type = build_method_type_directly (basetype,
-                                                TREE_TYPE (TREE_TYPE (clone)),
-                                                clone_parms);
-             if (exceptions)
-               type = build_exception_variant (type, exceptions);
-             if (attrs)
+
+             tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
+             tree type
+               = build_method_type_directly (basetype,
+                                             TREE_TYPE (TREE_TYPE (clone)),
+                                             clone_parms);
+             if (tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (clone)))
                type = cp_build_type_attribute_variant (type, attrs);
+             type = cxx_copy_lang_qualifiers (type, TREE_TYPE (clone));
              TREE_TYPE (clone) = type;
 
              clone_parms = NULL_TREE;
index 4b4f882..398f7ad 100644 (file)
@@ -7103,6 +7103,7 @@ extern tree ovl_scope                             (tree);
 extern const char *cxx_printable_name          (tree, int);
 extern const char *cxx_printable_name_translate        (tree, int);
 extern tree canonical_eh_spec                  (tree);
+extern tree build_cp_fntype_variant            (tree, cp_ref_qualifier, tree, bool);
 extern tree build_exception_variant            (tree, tree);
 extern tree bind_template_template_parm                (tree, tree);
 extern tree array_type_nelts_total             (tree);
@@ -7262,7 +7263,8 @@ extern tree build_ptrmemfunc                      (tree, tree, int, bool,
 extern int cp_type_quals                       (const_tree);
 extern int type_memfn_quals                    (const_tree);
 extern cp_ref_qualifier type_memfn_rqual       (const_tree);
-extern tree apply_memfn_quals                  (tree, cp_cv_quals, cp_ref_qualifier);
+extern tree apply_memfn_quals                  (tree, cp_cv_quals,
+                                                cp_ref_qualifier = REF_QUAL_NONE);
 extern bool cp_has_mutable_p                   (const_tree);
 extern bool at_least_as_qualified_p            (const_tree, const_tree);
 extern void cp_apply_type_quals_to_decl                (int, tree);
index 59d6bad..92639a8 100644 (file)
@@ -8592,6 +8592,7 @@ grokfndecl (tree ctype,
            bool deletedp,
            special_function_kind sfk,
            bool funcdef_flag,
+           bool late_return_type_p,
            int template_count,
            tree in_namespace,
            tree* attrlist,
@@ -8611,10 +8612,7 @@ grokfndecl (tree ctype,
       return NULL_TREE;
     }
 
-  if (rqual)
-    type = build_ref_qualified_type (type, rqual);
-  if (raises)
-    type = build_exception_variant (type, raises);
+  type = build_cp_fntype_variant (type, rqual, raises, late_return_type_p);
 
   decl = build_lang_decl (FUNCTION_DECL, declarator, type);
 
@@ -12136,9 +12134,6 @@ grokdeclarator (const cp_declarator *declarator,
            publicp = (! friendp || ! staticp)
              && function_context == NULL_TREE;
 
-           if (late_return_type_p)
-             TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
-
            decl = grokfndecl (ctype, type,
                               TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
                               ? unqualified_id : dname,
@@ -12149,7 +12144,8 @@ grokdeclarator (const cp_declarator *declarator,
                               friendp ? -1 : 0, friendp, publicp,
                                inlinep | (2 * constexpr_p) | (4 * concept_p),
                               initialized == SD_DELETED, sfk,
-                              funcdef_flag, template_count, in_namespace,
+                              funcdef_flag, late_return_type_p,
+                              template_count, in_namespace,
                               attrlist, declarator->id_loc);
             decl = set_virt_specifiers (decl, virt_specifiers);
            if (decl == NULL_TREE)
@@ -12386,9 +12382,6 @@ grokdeclarator (const cp_declarator *declarator,
        publicp = (ctype != NULL_TREE
                   || storage_class != sc_static);
 
-       if (late_return_type_p)
-         TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
-
        decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
                            reqs, virtualp, flags, memfn_quals, rqual, raises,
                           1, friendp,
@@ -12397,6 +12390,7 @@ grokdeclarator (const cp_declarator *declarator,
                           initialized == SD_DELETED,
                            sfk,
                            funcdef_flag,
+                          late_return_type_p,
                           template_count, in_namespace, attrlist,
                           declarator->id_loc);
        if (decl == NULL_TREE)
@@ -14753,11 +14747,9 @@ check_function_type (tree decl, tree current_function_parms)
                                             TREE_CHAIN (args));
       else
        fntype = build_function_type (void_type_node, args);
-      fntype
-       = build_exception_variant (fntype,
-                                  TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)));
       fntype = (cp_build_type_attribute_variant
                (fntype, TYPE_ATTRIBUTES (TREE_TYPE (decl))));
+      fntype = cxx_copy_lang_qualifiers (fntype, TREE_TYPE (decl));
       TREE_TYPE (decl) = fntype;
     }
   else
@@ -16161,15 +16153,11 @@ static_fn_type (tree memfntype)
     return memfntype;
   gcc_assert (TREE_CODE (memfntype) == METHOD_TYPE);
   args = TYPE_ARG_TYPES (memfntype);
-  cp_ref_qualifier rqual = type_memfn_rqual (memfntype);
   fntype = build_function_type (TREE_TYPE (memfntype), TREE_CHAIN (args));
-  fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype), rqual);
+  fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype));
   fntype = (cp_build_type_attribute_variant
            (fntype, TYPE_ATTRIBUTES (memfntype)));
-  fntype = (build_exception_variant
-           (fntype, TYPE_RAISES_EXCEPTIONS (memfntype)));
-  if (TYPE_HAS_LATE_RETURN_TYPE (memfntype))
-    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
+  fntype = cxx_copy_lang_qualifiers (fntype, memfntype);
   return fntype;
 }
 
index 0a6cf91..14a3cdd 100644 (file)
@@ -155,36 +155,27 @@ tree
 build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
                  cp_ref_qualifier rqual)
 {
-  tree raises;
-  tree attrs;
-  int type_quals;
-  bool late_return_type_p;
-
   if (fntype == error_mark_node || ctype == error_mark_node)
     return error_mark_node;
 
   gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
              || TREE_CODE (fntype) == METHOD_TYPE);
 
-  type_quals = quals & ~TYPE_QUAL_RESTRICT;
+  cp_cv_quals type_quals = quals & ~TYPE_QUAL_RESTRICT;
   ctype = cp_build_qualified_type (ctype, type_quals);
-  raises = TYPE_RAISES_EXCEPTIONS (fntype);
-  attrs = TYPE_ATTRIBUTES (fntype);
-  late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (fntype);
-  fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
-                                      (TREE_CODE (fntype) == METHOD_TYPE
-                                       ? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
-                                       : TYPE_ARG_TYPES (fntype)));
-  if (attrs)
-    fntype = cp_build_type_attribute_variant (fntype, attrs);
-  if (rqual)
-    fntype = build_ref_qualified_type (fntype, rqual);
-  if (raises)
-    fntype = build_exception_variant (fntype, raises);
-  if (late_return_type_p)
-    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
-
-  return fntype;
+
+  tree newtype
+    = build_method_type_directly (ctype, TREE_TYPE (fntype),
+                                 (TREE_CODE (fntype) == METHOD_TYPE
+                                  ? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
+                                  : TYPE_ARG_TYPES (fntype)));
+  if (tree attrs = TYPE_ATTRIBUTES (fntype))
+    newtype = cp_build_type_attribute_variant (newtype, attrs);
+  newtype = build_cp_fntype_variant (newtype, rqual,
+                                    TYPE_RAISES_EXCEPTIONS (fntype),
+                                    TYPE_HAS_LATE_RETURN_TYPE (fntype));
+
+  return newtype;
 }
 
 /* Return a variant of FNTYPE, a FUNCTION_TYPE or METHOD_TYPE, with its
@@ -193,36 +184,28 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
 tree
 change_return_type (tree new_ret, tree fntype)
 {
-  tree newtype;
-  tree args = TYPE_ARG_TYPES (fntype);
-  tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
-  tree attrs = TYPE_ATTRIBUTES (fntype);
-  bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (fntype);
-
   if (new_ret == error_mark_node)
     return fntype;
 
   if (same_type_p (new_ret, TREE_TYPE (fntype)))
     return fntype;
 
+  tree newtype;
+  tree args = TYPE_ARG_TYPES (fntype);
+
   if (TREE_CODE (fntype) == FUNCTION_TYPE)
     {
       newtype = build_function_type (new_ret, args);
       newtype = apply_memfn_quals (newtype,
-                                  type_memfn_quals (fntype),
-                                  type_memfn_rqual (fntype));
+                                  type_memfn_quals (fntype));
     }
   else
     newtype = build_method_type_directly
       (class_of_this_parm (fntype), new_ret, TREE_CHAIN (args));
-  if (FUNCTION_REF_QUALIFIED (fntype))
-    newtype = build_ref_qualified_type (newtype, type_memfn_rqual (fntype));
-  if (raises)
-    newtype = build_exception_variant (newtype, raises);
-  if (attrs)
+
+  if (tree attrs = TYPE_ATTRIBUTES (fntype))
     newtype = cp_build_type_attribute_variant (newtype, attrs);
-  if (late_return_type_p)
-    TYPE_HAS_LATE_RETURN_TYPE (newtype) = 1;
+  newtype = cxx_copy_lang_qualifiers (newtype, fntype);
 
   return newtype;
 }
@@ -326,12 +309,10 @@ maybe_retrofit_in_chrg (tree fn)
   /* And rebuild the function type.  */
   fntype = build_method_type_directly (basetype, TREE_TYPE (TREE_TYPE (fn)),
                                       arg_types);
-  if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
-    fntype = build_exception_variant (fntype,
-                                     TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)));
   if (TYPE_ATTRIBUTES (TREE_TYPE (fn)))
     fntype = (cp_build_type_attribute_variant
              (fntype, TYPE_ATTRIBUTES (TREE_TYPE (fn))));
+  fntype = cxx_copy_lang_qualifiers (fntype, TREE_TYPE (fn));
   TREE_TYPE (fn) = fntype;
 
   /* Now we've got the in-charge parameter.  */
@@ -1337,7 +1318,6 @@ tree
 cp_reconstruct_complex_type (tree type, tree bottom)
 {
   tree inner, outer;
-  bool late_return_type_p = false;
 
   if (TYPE_PTR_P (type))
     {
@@ -1363,16 +1343,12 @@ cp_reconstruct_complex_type (tree type, tree bottom)
     }
   else if (TREE_CODE (type) == FUNCTION_TYPE)
     {
-      late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (type);
       inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
       outer = build_function_type (inner, TYPE_ARG_TYPES (type));
-      outer = apply_memfn_quals (outer,
-                                type_memfn_quals (type),
-                                type_memfn_rqual (type));
+      outer = apply_memfn_quals (outer, type_memfn_quals (type));
     }
   else if (TREE_CODE (type) == METHOD_TYPE)
     {
-      late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (type);
       inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
       /* The build_method_type_directly() routine prepends 'this' to argument list,
         so we must compensate by getting rid of it.  */
@@ -1392,9 +1368,7 @@ cp_reconstruct_complex_type (tree type, tree bottom)
   if (TYPE_ATTRIBUTES (type))
     outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type));
   outer = cp_build_qualified_type (outer, cp_type_quals (type));
-
-  if (late_return_type_p)
-    TYPE_HAS_LATE_RETURN_TYPE (outer) = 1;
+  outer = cxx_copy_lang_qualifiers (outer, type);
 
   return outer;
 }
@@ -1748,9 +1722,9 @@ coerce_new_type (tree type)
       args = tree_cons (NULL_TREE, size_type_node, args);
       /* Fall through.  */
     case 1:
-      type = build_exception_variant
+      type = (cxx_copy_lang_qualifiers
              (build_function_type (ptr_type_node, args),
-              TYPE_RAISES_EXCEPTIONS (type));
+              type));
       /* Fall through.  */
     default:;
   }
@@ -1786,9 +1760,9 @@ coerce_delete_type (tree type)
       args = tree_cons (NULL_TREE, ptr_type_node, args);
       /* Fall through.  */
     case 1:
-      type = build_exception_variant
+      type = (cxx_copy_lang_qualifiers
              (build_function_type (void_type_node, args),
-              TYPE_RAISES_EXCEPTIONS (type));
+              type));
       /* Fall through.  */
     default:;
   }
index 58b3311..387990b 100644 (file)
@@ -2155,11 +2155,7 @@ write_type (tree type)
       type = TYPE_MAIN_VARIANT (type);
       if (TREE_CODE (type) == FUNCTION_TYPE
          || TREE_CODE (type) == METHOD_TYPE)
-       {
-         type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
-         type = build_exception_variant (type,
-                                         TYPE_RAISES_EXCEPTIONS (type_orig));
-       }
+       type = cxx_copy_lang_qualifiers (type, type_orig);
 
       /* According to the C++ ABI, some library classes are passed the
         same as the scalar type of their single member and use the same
index a06516b..c005808 100644 (file)
@@ -10563,11 +10563,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
     void *p;
 
     clear_decl_specs (&return_type_specs);
-    if (return_type)
-      return_type_specs.type = return_type;
-    else
-      /* Maybe we will deduce the return type later.  */
-      return_type_specs.type = make_auto ();
+    return_type_specs.type = make_auto ();
 
     if (lambda_specs.locations[ds_constexpr])
       {
@@ -10593,6 +10589,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
                                        /*late_return_type=*/NULL_TREE,
                                        /*requires_clause*/NULL_TREE);
     declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
+    if (return_type)
+      declarator->u.function.late_return_type = return_type;
 
     fco = grokmethod (&return_type_specs,
                      declarator,
@@ -10603,8 +10601,6 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
        DECL_ARTIFICIAL (fco) = 1;
        /* Give the object parameter a different name.  */
        DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
-       if (return_type)
-         TYPE_HAS_LATE_RETURN_TYPE (TREE_TYPE (fco)) = 1;
       }
     if (template_param_list)
       {
index ddfda2e..1e42040 100644 (file)
@@ -2528,11 +2528,7 @@ copy_default_args_to_explicit_spec (tree decl)
                                    new_spec_types);
   new_type = cp_build_type_attribute_variant (new_type,
                                              TYPE_ATTRIBUTES (old_type));
-  new_type = build_exception_variant (new_type,
-                                     TYPE_RAISES_EXCEPTIONS (old_type));
-
-  if (TYPE_HAS_LATE_RETURN_TYPE (old_type))
-    TYPE_HAS_LATE_RETURN_TYPE (new_type) = 1;
+  new_type = cxx_copy_lang_qualifiers (new_type, old_type);
 
   TREE_TYPE (decl) = new_type;
 }
@@ -14020,9 +14016,7 @@ tsubst_function_type (tree t,
   if (TREE_CODE (t) == FUNCTION_TYPE)
     {
       fntype = build_function_type (return_type, arg_types);
-      fntype = apply_memfn_quals (fntype,
-                                 type_memfn_quals (t),
-                                 type_memfn_rqual (t));
+      fntype = apply_memfn_quals (fntype, type_memfn_quals (t));
     }
   else
     {
@@ -14046,12 +14040,13 @@ tsubst_function_type (tree t,
 
       fntype = build_method_type_directly (r, return_type,
                                           TREE_CHAIN (arg_types));
-      fntype = build_ref_qualified_type (fntype, type_memfn_rqual (t));
     }
   fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
 
-  if (late_return_type_p)
-    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
+  /* See comment above.  */
+  tree raises = NULL_TREE;
+  cp_ref_qualifier rqual = type_memfn_rqual (t);
+  fntype = build_cp_fntype_variant (fntype, rqual, raises, late_return_type_p);
 
   return fntype;
 }
index b2efab6..463a06d 100644 (file)
@@ -1299,15 +1299,6 @@ cp_build_qualified_type_real (tree type,
   /* Retrieve (or create) the appropriately qualified variant.  */
   result = build_qualified_type (type, type_quals);
 
-  /* Preserve exception specs and ref-qualifier since build_qualified_type
-     doesn't know about them.  */
-  if (TREE_CODE (result) == FUNCTION_TYPE
-      || TREE_CODE (result) == METHOD_TYPE)
-    {
-      result = build_exception_variant (result, TYPE_RAISES_EXCEPTIONS (type));
-      result = build_ref_qualified_type (result, type_memfn_rqual (type));
-    }
-
   return result;
 }
 
@@ -1535,22 +1526,16 @@ strip_typedefs (tree t, bool *remove_attributes)
            result =
              build_method_type_directly (class_type, type,
                                          TREE_CHAIN (arg_types));
-           result
-             = build_ref_qualified_type (result, type_memfn_rqual (t));
          }
        else
          {
-           result = build_function_type (type,
-                                         arg_types);
-           result = apply_memfn_quals (result,
-                                       type_memfn_quals (t),
-                                       type_memfn_rqual (t));
+           result = build_function_type (type, arg_types);
+           result = apply_memfn_quals (result, type_memfn_quals (t));
          }
 
-       if (canon_spec)
-         result = build_exception_variant (result, canon_spec);
-       if (TYPE_HAS_LATE_RETURN_TYPE (t))
-         TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
+       result = build_cp_fntype_variant (result,
+                                         type_memfn_rqual (t), canon_spec,
+                                         TYPE_HAS_LATE_RETURN_TYPE (t));
       }
       break;
     case TYPENAME_TYPE:
@@ -2093,17 +2078,19 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p)
   return t;
 }
 
-/* Like check_qualified_type, but also check ref-qualifier and exception
-   specification.  */
+/* Like check_qualified_type, but also check ref-qualifier, exception
+   specification, and whether the return type was specified after the
+   parameters.  */
 
 static bool
 cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
-                        cp_ref_qualifier rqual, tree raises)
+                        cp_ref_qualifier rqual, tree raises, bool late)
 {
   return (TYPE_QUALS (cand) == type_quals
          && check_base_type (cand, base)
          && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (cand),
                                ce_exact)
+         && TYPE_HAS_LATE_RETURN_TYPE (cand) == late
          && type_memfn_rqual (cand) == rqual);
 }
 
@@ -2112,46 +2099,9 @@ cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
 tree
 build_ref_qualified_type (tree type, cp_ref_qualifier rqual)
 {
-  tree t;
-
-  if (rqual == type_memfn_rqual (type))
-    return type;
-
-  int type_quals = TYPE_QUALS (type);
   tree raises = TYPE_RAISES_EXCEPTIONS (type);
-  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-    if (cp_check_qualified_type (t, type, type_quals, rqual, raises))
-      return t;
-
-  t = build_variant_type_copy (type);
-  switch (rqual)
-    {
-    case REF_QUAL_RVALUE:
-      FUNCTION_RVALUE_QUALIFIED (t) = 1;
-      FUNCTION_REF_QUALIFIED (t) = 1;
-      break;
-    case REF_QUAL_LVALUE:
-      FUNCTION_RVALUE_QUALIFIED (t) = 0;
-      FUNCTION_REF_QUALIFIED (t) = 1;
-      break;
-    default:
-      FUNCTION_REF_QUALIFIED (t) = 0;
-      break;
-    }
-
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
-    /* Propagate structural equality. */
-    SET_TYPE_STRUCTURAL_EQUALITY (t);
-  else if (TYPE_CANONICAL (type) != type)
-    /* Build the underlying canonical type, since it is different
-       from TYPE. */
-    TYPE_CANONICAL (t) = build_ref_qualified_type (TYPE_CANONICAL (type),
-                                                  rqual);
-  else
-    /* T is its own canonical type. */
-    TYPE_CANONICAL (t) = t;
-
-  return t;
+  bool late = TYPE_HAS_LATE_RETURN_TYPE (type);
+  return build_cp_fntype_variant (type, rqual, raises, late);
 }
 
 /* Cache of free ovl nodes.  Uses OVL_FUNCTION for chaining.  */
@@ -2656,42 +2606,50 @@ canonical_eh_spec (tree raises)
     return NULL_TREE;
 }
 
-/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
-   listed in RAISES.  */
-
 tree
-build_exception_variant (tree type, tree raises)
+build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
+                        tree raises, bool late)
 {
-  tree v;
-  int type_quals;
+  cp_cv_quals type_quals = TYPE_QUALS (type);
 
-  if (comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (type), ce_exact))
+  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
     return type;
 
-  type_quals = TYPE_QUALS (type);
-  cp_ref_qualifier rqual = type_memfn_rqual (type);
-  for (v = TYPE_MAIN_VARIANT (type); v; v = TYPE_NEXT_VARIANT (v))
-    if (cp_check_qualified_type (v, type, type_quals, rqual, raises))
+  tree v = TYPE_MAIN_VARIANT (type);
+  for (; v; v = TYPE_NEXT_VARIANT (v))
+    if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
       return v;
 
   /* Need to build a new variant.  */
   v = build_variant_type_copy (type);
   TYPE_RAISES_EXCEPTIONS (v) = raises;
-
-  if (!flag_noexcept_type)
-    /* The exception-specification is not part of the canonical type.  */
-    return v;
+  TYPE_HAS_LATE_RETURN_TYPE (v) = late;
+  switch (rqual)
+    {
+    case REF_QUAL_RVALUE:
+      FUNCTION_RVALUE_QUALIFIED (v) = 1;
+      FUNCTION_REF_QUALIFIED (v) = 1;
+      break;
+    case REF_QUAL_LVALUE:
+      FUNCTION_RVALUE_QUALIFIED (v) = 0;
+      FUNCTION_REF_QUALIFIED (v) = 1;
+      break;
+    default:
+      FUNCTION_REF_QUALIFIED (v) = 0;
+      break;
+    }
 
   /* Canonicalize the exception specification.  */
-  tree cr = canonical_eh_spec (raises);
+  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
 
   if (TYPE_STRUCTURAL_EQUALITY_P (type))
     /* Propagate structural equality. */
     SET_TYPE_STRUCTURAL_EQUALITY (v);
-  else if (TYPE_CANONICAL (type) != type || cr != raises)
+  else if (TYPE_CANONICAL (type) != type || cr != raises || late)
     /* Build the underlying canonical type, since it is different
        from TYPE. */
-    TYPE_CANONICAL (v) = build_exception_variant (TYPE_CANONICAL (type), cr);
+    TYPE_CANONICAL (v) = build_cp_fntype_variant (TYPE_CANONICAL (type),
+                                                 rqual, cr, false);
   else
     /* T is its own canonical type. */
     TYPE_CANONICAL (v) = v;
@@ -2699,6 +2657,17 @@ build_exception_variant (tree type, tree raises)
   return v;
 }
 
+/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
+   listed in RAISES.  */
+
+tree
+build_exception_variant (tree type, tree raises)
+{
+  cp_ref_qualifier rqual = type_memfn_rqual (type);
+  bool late = TYPE_HAS_LATE_RETURN_TYPE (type);
+  return build_cp_fntype_variant (type, rqual, raises, late);
+}
+
 /* Given a TEMPLATE_TEMPLATE_PARM node T, create a new
    BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template
    arguments.  */
@@ -4736,12 +4705,7 @@ cp_build_type_attribute_variant (tree type, tree attributes)
   new_type = build_type_attribute_variant (type, attributes);
   if (TREE_CODE (new_type) == FUNCTION_TYPE
       || TREE_CODE (new_type) == METHOD_TYPE)
-    {
-      new_type = build_exception_variant (new_type,
-                                         TYPE_RAISES_EXCEPTIONS (type));
-      new_type = build_ref_qualified_type (new_type,
-                                          type_memfn_rqual (type));
-    }
+    gcc_checking_assert (cxx_type_hash_eq (type, new_type));
 
   /* Making a new main variant of a class type is broken.  */
   gcc_assert (!CLASS_TYPE_P (type) || new_type == type);
@@ -4760,6 +4724,8 @@ cxx_type_hash_eq (const_tree typea, const_tree typeb)
 
   if (type_memfn_rqual (typea) != type_memfn_rqual (typeb))
     return false;
+  if (TYPE_HAS_LATE_RETURN_TYPE (typea) != TYPE_HAS_LATE_RETURN_TYPE (typeb))
+    return false;
   return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea),
                            TYPE_RAISES_EXCEPTIONS (typeb), ce_exact);
 }
@@ -4772,10 +4738,9 @@ cxx_copy_lang_qualifiers (const_tree typea, const_tree typeb)
 {
   tree type = CONST_CAST_TREE (typea);
   if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
-    {
-      type = build_exception_variant (type, TYPE_RAISES_EXCEPTIONS (typeb));
-      type = build_ref_qualified_type (type, type_memfn_rqual (typeb));
-    }
+    type = build_cp_fntype_variant (type, type_memfn_rqual (typeb),
+                                   TYPE_RAISES_EXCEPTIONS (typeb),
+                                   TYPE_HAS_LATE_RETURN_TYPE (typeb));
   return type;
 }
 
index e5eb35d..ecb334d 100644 (file)
@@ -830,8 +830,6 @@ merge_types (tree t1, tree t2)
        tree p1 = TYPE_ARG_TYPES (t1);
        tree p2 = TYPE_ARG_TYPES (t2);
        tree parms;
-       tree rval, raises;
-       bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
 
        /* Save space: see if the result is identical to one of the args.  */
        if (valtype == TREE_TYPE (t1) && ! p2)
@@ -847,17 +845,17 @@ merge_types (tree t1, tree t2)
        else
          parms = commonparms (p1, p2);
 
-       rval = build_function_type (valtype, parms);
-       gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
-       gcc_assert (type_memfn_rqual (t1) == type_memfn_rqual (t2));
-       rval = apply_memfn_quals (rval,
-                                 type_memfn_quals (t1),
-                                 type_memfn_rqual (t1));
-       raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-                                            TYPE_RAISES_EXCEPTIONS (t2));
-       t1 = build_exception_variant (rval, raises);
-       if (late_return_type_p)
-         TYPE_HAS_LATE_RETURN_TYPE (t1) = 1;
+       cp_cv_quals quals = type_memfn_quals (t1);
+       cp_ref_qualifier rqual = type_memfn_rqual (t1);
+       gcc_assert (quals == type_memfn_quals (t2));
+       gcc_assert (rqual == type_memfn_rqual (t2));
+
+       tree rval = build_function_type (valtype, parms);
+       rval = apply_memfn_quals (rval, quals);
+       tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
+                                                 TYPE_RAISES_EXCEPTIONS (t2));
+       bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
+       t1 = build_cp_fntype_variant (rval, rqual, raises, late_return_type_p);
        break;
       }
 
@@ -871,7 +869,6 @@ merge_types (tree t1, tree t2)
        cp_ref_qualifier rqual = type_memfn_rqual (t1);
        tree t3;
        bool late_return_type_1_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
-       bool late_return_type_2_p = TYPE_HAS_LATE_RETURN_TYPE (t2);
 
        /* If this was a member function type, get back to the
           original type of type member function (i.e., without
@@ -883,12 +880,7 @@ merge_types (tree t1, tree t2)
        t3 = merge_types (t1, t2);
        t3 = build_method_type_directly (basetype, TREE_TYPE (t3),
                                         TYPE_ARG_TYPES (t3));
-       t1 = build_exception_variant (t3, raises);
-       t1 = build_ref_qualified_type (t1, rqual);
-       if (late_return_type_1_p)
-         TYPE_HAS_LATE_RETURN_TYPE (t1) = 1;
-       if (late_return_type_2_p)
-         TYPE_HAS_LATE_RETURN_TYPE (t2) = 1;
+       t1 = build_cp_fntype_variant (t3, rqual, raises, late_return_type_1_p);
        break;
       }