Hi,
On 05/30/2014 04:41 PM, Jason Merrill wrote:
On 05/30/2014 10:21 AM, Paolo Carlini wrote:
You also need to propagate the flag in a bunch of other places:
everywhere we call build_method_type_directly ought to cover it.
Agreed, I spotted a few places. What about build_function_type? I think
it's the same issue, right?
Right, I was just thinking that the relevant uses of
build_function_type will be near calls to build_method_type_directly. :)
Indeed. Thus I have the below, which passes testing. Most of the changes
are quite obvious, some maybe redundant but safe, I think. Exceptions:
1- I'm not sure cp_reconstruct_complex_type needs the changes, but
probably cannot hurt.
2- Likewise change_return_type, for different reasons.
3- I understand Core/1227 as including the case of the late return type
vs the parameters of generic lambdas, thus the rather heavy handed tweak
to cp_parser_lambda_declarator_opt, which appears to work under the
debugger (in the sense that for testcases like
cpp1y/lambda-generic-cfun.C I checked that the on flag is still there in
the eventual tsubst_function_type), but I need help about the conversion
operator: should I do something in maybe_add_lambda_conv_op, thus
propagate somehow from TREE_TYPE (callop)?!? In case, it would be easy,
but I need help about the actual semantics we want (this isn't really
about our impl, more about the specs of generic lambdas, sorry).
Finally, about !dependent_scope_p vs CLASS_TYPE_P, just wanted to
mention, in case isn't obvious already, that build_this_parm has
CLASS_TYPE_P which we badly want to be true if we want to avoid
immediate ICEs in type_of_this_parm. Thus, it seems in fact the minimal
check to use in tsusbt_function_type.
Thanks!
Paolo.
////////////////////////
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 211072)
+++ 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 211072)
+++ 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,
@@ -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: cp/decl2.c
===================================================================
--- cp/decl2.c (revision 211072)
+++ cp/decl2.c (working copy)
@@ -119,6 +119,7 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_q
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_q
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_q
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 botto
}
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 botto
}
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 botto
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: cp/parser.c
===================================================================
--- cp/parser.c (revision 211072)
+++ cp/parser.c (working copy)
@@ -9152,6 +9152,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser
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: cp/pt.c
===================================================================
--- cp/pt.c (revision 211072)
+++ cp/pt.c (working copy)
@@ -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: cp/tree.c
===================================================================
--- cp/tree.c (revision 211072)
+++ cp/tree.c (working copy)
@@ -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: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 211072)
+++ cp/typeck.c (working copy)
@@ -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,7 @@ merge_types (tree t1, tree t2)
TYPE_RAISES_EXCEPTIONS (t2));
cp_ref_qualifier rqual = type_memfn_rqual (t1);
tree t3;
+ bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
/* If this was a member function type, get back to the
original type of type member function (i.e., without
@@ -867,6 +871,8 @@ 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_p)
+ TYPE_HAS_LATE_RETURN_TYPE (t1) = 1;
break;
}
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-1.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-1.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-1.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" }
+}
Index: testsuite/g++.dg/cpp0x/pr57543-2.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-2.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-2.C (working copy)
@@ -0,0 +1,17 @@
+// 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" }
+ }
+};
Index: testsuite/g++.dg/cpp0x/pr57543-3.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-3.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-3.C (working copy)
@@ -0,0 +1,20 @@
+// 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" }