Hi again,

On 05/29/2014 03:34 PM, Jason Merrill wrote:
On 05/28/2014 01:06 PM, Paolo Carlini wrote:
Now, I got this "insane" idea: would it make sense to simply invert the
substitutions (args and return) unconditionally?

If we're going to change the order, I want to do it in a more correct, rather than differently wrong, way. DR 1227 clarified that substitution should proceed in lexical order.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1227
So, here is another iteration, sorry about the ping-pong. I put together the below which already passes testing. How does it look?

Thanks again for your patience,
Paolo.

/////////////////////
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h        (revision 211052)
+++ cp/cp-tree.h        (working copy)
@@ -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_a
    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: cp/decl.c
===================================================================
--- cp/decl.c   (revision 211052)
+++ cp/decl.c   (working copy)
@@ -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,
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 211052)
+++ cp/pt.c     (working copy)
@@ -11322,8 +11322,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 && !dependent_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 +11378,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 +11421,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: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C (revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C (working copy)
@@ -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>>();
+}
Index: testsuite/g++.dg/cpp0x/pr57543.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543.C    (revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543.C    (working copy)
@@ -0,0 +1,13 @@
+// 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" }
+}

Reply via email to