]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
DR 1227 PR c++/57543
authorPaolo Carlini <paolo.carlini@oracle.com>
Sat, 31 May 2014 08:51:20 +0000 (08:51 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Sat, 31 May 2014 08:51:20 +0000 (08:51 +0000)
/cp
2014-05-31  Paolo Carlini  <paolo.carlini@oracle.com>

DR 1227
PR c++/57543
* cp-tree.h (TYPE_HAS_LATE_RETURN_TYPE): Add.
* pt.c (tsubst_function_type): Inject the this parameter; do the
substitutions in the order mandated by the DR.
(copy_default_args_to_explicit_spec): Copy TYPE_HAS_LATE_RETURN_TYPE.
* decl.c (grokdeclarator): Maybe set TYPE_HAS_LATE_RETURN_TYPE.
(static_fn_type): Copy it.
* decl2.c (build_memfn_type, change_return_type,
cp_reconstruct_complex_type): Likewise.
* parser.c (cp_parser_lambda_declarator_opt): Likewise.
* tree.c (strip_typedefs): Likewise.
* typeck.c (merge_types): Likewise.

/testsuite
2014-05-31  Paolo Carlini  <paolo.carlini@oracle.com>

DR 1227
PR c++/57543
* g++.dg/cpp0x/pr57543-1.C: New.
* g++.dg/cpp0x/pr57543-2.C: Likewise.
* g++.dg/cpp0x/pr57543-3.C: Likewise.
* g++.dg/cpp0x/decltype59.C: Likewise.

From-SVN: r211102

13 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/decltype59.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr57543-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr57543-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr57543-3.C [new file with mode: 0644]

index 34287b534d7aa5b8be595ad62252492033c7c811..e8a25f3b9b912763fef4f17e3daaac827117731a 100644 (file)
@@ -1,3 +1,19 @@
+2014-05-31  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       DR 1227
+       PR c++/57543
+       * cp-tree.h (TYPE_HAS_LATE_RETURN_TYPE): Add.
+       * pt.c (tsubst_function_type): Inject the this parameter; do the
+       substitutions in the order mandated by the DR.
+       (copy_default_args_to_explicit_spec): Copy TYPE_HAS_LATE_RETURN_TYPE.
+       * decl.c (grokdeclarator): Maybe set TYPE_HAS_LATE_RETURN_TYPE.
+       (static_fn_type): Copy it.
+       * decl2.c (build_memfn_type, change_return_type,
+       cp_reconstruct_complex_type): Likewise.
+       * parser.c (cp_parser_lambda_declarator_opt): Likewise.
+       * tree.c (strip_typedefs): Likewise.
+       * typeck.c (merge_types): Likewise.
+
 2014-05-30  Jason Merrill  <jason@redhat.com>
 
        PR c++/56947
index 7d29c2c78ba77ff56afa09266e0f195b24984e51..3e4ec3d72d9d25f5f98ae5fff351cbb50f79a21d 100644 (file)
@@ -125,7 +125,7 @@ c-common.h, not after.
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
    1: TYPE_HAS_USER_CONSTRUCTOR.
-   2: unused
+   2: TYPE_HAS_LATE_RETURN_TYPE (in FUNCTION_TYPE, METHOD_TYPE)
    3: TYPE_FOR_JAVA.
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
@@ -3404,6 +3404,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    user-declared constructor.  */
 #define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
 
+/* Nonzero means that the FUNCTION_TYPE or METHOD_TYPE has a
+   late-specified return type.  */
+#define TYPE_HAS_LATE_RETURN_TYPE(NODE) \
+  (TYPE_LANG_FLAG_2 (FUNC_OR_METHOD_CHECK (NODE)))
+
 /* When appearing in an INDIRECT_REF, it means that the tree structure
    underneath is actually a call to a constructor.  This is needed
    when the constructor must initialize local storage (which can
index 350244716ff70d6c2a17af00cf887bb83930e49a..e5eecb273789904c03f2d632b7d186600d5d2eb2 100644 (file)
@@ -8817,6 +8817,7 @@ grokdeclarator (const cp_declarator *declarator,
   bool template_parm_flag = false;
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
+  bool late_return_type_p = false;
   source_location saved_loc = input_location;
   const char *errmsg;
 
@@ -9660,6 +9661,9 @@ grokdeclarator (const cp_declarator *declarator,
            if (type == error_mark_node)
              return error_mark_node;
 
+           if (declarator->u.function.late_return_type)
+             late_return_type_p = true;
+
            if (ctype == NULL_TREE
                && decl_context == FIELD
                && funcdecl_p
@@ -10590,6 +10594,10 @@ grokdeclarator (const cp_declarator *declarator,
              decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
            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,
@@ -10814,6 +10822,9 @@ 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,
                           virtualp, flags, memfn_quals, rqual, raises,
                           1, friendp,
@@ -14421,6 +14432,8 @@ static_fn_type (tree memfntype)
            (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;
   return fntype;
 }
 
index de3499904d38bafbee99f4a3aaa98b37a3b73d20..602a0c557597562c3304f4988e6b13f1c331c822 100644 (file)
@@ -119,6 +119,7 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
   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;
@@ -130,6 +131,7 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
   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))
@@ -140,6 +142,8 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
     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;
 }
@@ -154,6 +158,7 @@ change_return_type (tree new_ret, tree fntype)
   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;
@@ -175,6 +180,8 @@ change_return_type (tree new_ret, tree fntype)
     newtype = build_exception_variant (newtype, raises);
   if (attrs)
     newtype = cp_build_type_attribute_variant (newtype, attrs);
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (newtype) = 1;
 
   return newtype;
 }
@@ -1276,6 +1283,7 @@ tree
 cp_reconstruct_complex_type (tree type, tree bottom)
 {
   tree inner, outer;
+  bool late_return_type_p = false;
 
   if (TYPE_PTR_P (type))
     {
@@ -1301,6 +1309,7 @@ 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,
@@ -1309,6 +1318,7 @@ cp_reconstruct_complex_type (tree type, tree bottom)
     }
   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.  */
@@ -1327,7 +1337,12 @@ cp_reconstruct_complex_type (tree type, tree bottom)
 
   if (TYPE_ATTRIBUTES (type))
     outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type));
-  return cp_build_qualified_type (outer, cp_type_quals (type));
+  outer = cp_build_qualified_type (outer, cp_type_quals (type));
+
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (outer) = 1;
+
+  return outer;
 }
 
 /* Replaces any constexpr expression that may be into the attributes
index c4440af2314ea34aa0e60d0dc9cdae01e80b22ab..2591ae545a86e62b1684b0468665347097eca5f0 100644 (file)
@@ -9152,6 +9152,8 @@ 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 (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
+         TYPE_HAS_LATE_RETURN_TYPE (TREE_TYPE (fco)) = 1;
       }
     if (template_param_list)
       {
index 0d22fae0e6b7c42277a38c5f2e96ae5fdd03a401..c0e0646704ddb0cbf199ed96b77e891e842d08ab 100644 (file)
@@ -2256,6 +2256,10 @@ copy_default_args_to_explicit_spec (tree decl)
                                              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;
+
   TREE_TYPE (decl) = new_type;
 }
 
@@ -11322,8 +11326,42 @@ tsubst_function_type (tree t,
   /* The TYPE_CONTEXT is not used for function/method types.  */
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
-  /* Substitute the return type.  */
-  return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+  /* DR 1227: Mixing immediate and non-immediate contexts in deduction
+     failure.  */
+  bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t);
+
+  if (late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+                                   complain, in_decl);
+      if (arg_types == error_mark_node)
+       return error_mark_node;
+
+      tree save_ccp = current_class_ptr;
+      tree save_ccr = current_class_ref;
+      tree this_type = (TREE_CODE (t) == METHOD_TYPE
+                       ? TREE_TYPE (TREE_VALUE (arg_types)) : NULL_TREE);
+      bool do_inject = this_type && CLASS_TYPE_P (this_type);
+      if (do_inject)
+       {
+         /* DR 1207: 'this' is in scope in the trailing return type.  */
+         inject_this_parameter (this_type, cp_type_quals (this_type));
+       }
+
+      /* Substitute the return type.  */
+      return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+      if (do_inject)
+       {
+         current_class_ptr = save_ccp;
+         current_class_ref = save_ccr;
+       }
+    }
+  else
+    /* Substitute the return type.  */
+    return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -11344,11 +11382,14 @@ tsubst_function_type (tree t,
   if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
-  /* Substitute the argument types.  */
-  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
-                               complain, in_decl);
-  if (arg_types == error_mark_node)
-    return error_mark_node;
+  if (!late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+                                   complain, in_decl);
+      if (arg_types == error_mark_node)
+       return error_mark_node;
+    }
 
   /* Construct a new type node and return it.  */
   if (TREE_CODE (t) == FUNCTION_TYPE)
@@ -11384,6 +11425,9 @@ tsubst_function_type (tree t,
     }
   fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
 
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
+
   return fntype;
 }
 
index 21c9a82bbdaa4e8a7653e92388df84f019d94772..587ae80bcc1f23b8b8f3dcad27bc6e06bddee9c8 100644 (file)
@@ -1257,6 +1257,8 @@ strip_typedefs (tree t)
        if (TYPE_RAISES_EXCEPTIONS (t))
          result = build_exception_variant (result,
                                            TYPE_RAISES_EXCEPTIONS (t));
+       if (TYPE_HAS_LATE_RETURN_TYPE (t))
+         TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
       }
       break;
     case TYPENAME_TYPE:
index 255deafdac42e8650ee73628c346bfc099863c6c..aa96fb493180c1646098bc7833fc6f4662704521 100644 (file)
@@ -818,6 +818,7 @@ merge_types (tree t1, tree t2)
        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)
@@ -842,6 +843,8 @@ merge_types (tree t1, tree t2)
        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;
        break;
       }
 
@@ -854,6 +857,8 @@ merge_types (tree t1, tree t2)
                                                  TYPE_RAISES_EXCEPTIONS (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
@@ -867,6 +872,10 @@ merge_types (tree t1, tree t2)
                                         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;
        break;
       }
 
index b566a2c81d8da5600b20e423f3fc4701239b8349..425ebf8bbe9e12ba186e6730068b024b8180966f 100644 (file)
@@ -1,3 +1,12 @@
+2014-05-31  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       DR 1227
+       PR c++/57543
+       * g++.dg/cpp0x/pr57543-1.C: New.
+       * g++.dg/cpp0x/pr57543-2.C: Likewise.
+       * g++.dg/cpp0x/pr57543-3.C: Likewise.
+       * g++.dg/cpp0x/decltype59.C: Likewise.
+
 2014-05-31  Tom de Vries  <tom@codesourcery.com>
 
        * gcc.target/i386/sibcall-4.c: Add missing closing brace.
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype59.C b/gcc/testsuite/g++.dg/cpp0x/decltype59.C
new file mode 100644 (file)
index 0000000..93208df
--- /dev/null
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr57543-1.C b/gcc/testsuite/g++.dg/cpp0x/pr57543-1.C
new file mode 100644 (file)
index 0000000..d77d71e
--- /dev/null
@@ -0,0 +1,13 @@
+// DR 1227, PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+template <class T> typename T::X f(typename A<T>::X);
+template <class T> void f(...) { }
+template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+template <class T> void g(...) { }
+
+void h() {
+  f<int>(0);  // OK
+  g<int>(0);  // { dg-message "required" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr57543-2.C b/gcc/testsuite/g++.dg/cpp0x/pr57543-2.C
new file mode 100644 (file)
index 0000000..7afa7fe
--- /dev/null
@@ -0,0 +1,17 @@
+// DR 1227, PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+struct S
+{
+  template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+  template <class T> typename T::X f(typename A<T>::X);
+  template <class T> void f(...) { }
+  template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+  template <class T> void g(...) { }
+
+  void h()
+  {
+    f<int>(0);  // OK
+    g<int>(0);  // { dg-message "required" }
+  }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr57543-3.C b/gcc/testsuite/g++.dg/cpp0x/pr57543-3.C
new file mode 100644 (file)
index 0000000..b77fefc
--- /dev/null
@@ -0,0 +1,20 @@
+// DR 1227, PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+template <class>
+class C
+{
+  template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+  template <class T> typename T::X f(typename A<T>::X);
+  template <class T> void f(...) { }
+  template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+  template <class T> void g(...) { }
+
+  void h()
+  {
+    f<int>(0);  // OK
+    g<int>(0);  // { dg-message "required" }
+  }
+};
+
+template class C<int>;  // { dg-message "required" }