diff options
author | paolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-31 08:51:20 +0000 |
---|---|---|
committer | paolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-31 08:51:20 +0000 |
commit | 0fad30001313c1678619bd2e24f51f0d6b5cb87a (patch) | |
tree | 1f3efe38c71709e695cad44c3bb889094a2382e5 | |
parent | e07c49ac05f5f7a29884d80ca8524229020f495f (diff) |
/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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@211102 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/decl.c | 13 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 17 | ||||
-rw-r--r-- | gcc/cp/parser.c | 2 | ||||
-rw-r--r-- | gcc/cp/pt.c | 58 | ||||
-rw-r--r-- | gcc/cp/tree.c | 2 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/decltype59.C | 41 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr57543-1.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr57543-2.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr57543-3.C | 20 |
13 files changed, 215 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 34287b534d7..e8a25f3b9b9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7d29c2c78ba..3e4ec3d72d9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 350244716ff..e5eecb27378 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index de3499904d3..602a0c55759 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c4440af2314..2591ae545a8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0d22fae0e6b..c0e0646704d 100644 --- a/gcc/cp/pt.c +++ b/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; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 21c9a82bbda..587ae80bcc1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 255deafdac4..aa96fb49318 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b566a2c81d8..425ebf8bbe9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 00000000000..93208df95cb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype59.C @@ -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 index 00000000000..d77d71e8bdb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr57543-1.C @@ -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 index 00000000000..7afa7fe491b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr57543-2.C @@ -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 index 00000000000..b77fefc8c11 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr57543-3.C @@ -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" } |