DR 1227 PR c++/57543
/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
This commit is contained in:
parent
f5fb306951
commit
cab421f485
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
58
gcc/cp/pt.c
58
gcc/cp/pt.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
41
gcc/testsuite/g++.dg/cpp0x/decltype59.C
Normal file
41
gcc/testsuite/g++.dg/cpp0x/decltype59.C
Normal file
@ -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>>();
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp0x/pr57543-1.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/pr57543-1.C
Normal file
@ -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" }
|
||||
}
|
17
gcc/testsuite/g++.dg/cpp0x/pr57543-2.C
Normal file
17
gcc/testsuite/g++.dg/cpp0x/pr57543-2.C
Normal file
@ -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" }
|
||||
}
|
||||
};
|
20
gcc/testsuite/g++.dg/cpp0x/pr57543-3.C
Normal file
20
gcc/testsuite/g++.dg/cpp0x/pr57543-3.C
Normal file
@ -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" }
|
Loading…
Reference in New Issue
Block a user