public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Extend SFINAE to all expressions
@ 2007-11-17 18:08 Doug Gregor
  2007-11-18  5:35 ` Gabriel Dos Reis
  0 siblings, 1 reply; 2+ messages in thread
From: Doug Gregor @ 2007-11-17 18:08 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 12880 bytes --]

The attached patch extends SFINAE (Substitution Failure Is Not An
Error) to all expressions, following the proposed resolution of Core
Issue #339:

  http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#339

This issue has languished for a while, but it became more urgent with
the addition of decltype into C++0x (which is supported in our
experimental C++0x mode). Consider the following example from David
Abrahams:

 template <class T,class U>
    decltype((*(T*)0)+(*(U*)0)) add(const T& t,const U& u);

That's a typical use of decltype for return-type deduction, but just
trying to unify this add() function will cause errors when T and U are
not addable (even though an overload of the add() function would have
sufficed). That's part of the motivation for the extension to SFINAE
in #339; other influences include the C++0x constexpr (not in GCC yet)
and the feeling that this is the way SFINAE should have worked. In
truth, the standard doesn't really say anything about expressions in
unification/substitution, so this "extension" is already a reasonable
interpretation of the C++98/03 specification.

The attached patch is very big, very mechanical, and very boring.
Essentially, I just extended the mechanism we already have for dealing
with SFINAE, propagating tsubst_flags_t arguments, throughout much of
the C++ front end. The work flow is tedious: starting at a call from
one of the tsubst* routines in pt.c, add a "tsubst_flags_t complain"
parameter to a function called from tsubst*, then do two things:
  1) Guard warning, error, and pedwarn calls with (complain &
tf_warning) or (complain & tf_error), respectively.
  2) Patch up all of the calls to this function from elsewhere in the
front end to include an appropriate "complain" parameter, either
"complain" (propagated) or "tf_warning_or_error".
  3) Recurse for all of the semantic-analysis functions this function
calls, propagating "complain" down the pipe.

These changes don't propagate into template instantiation (which is
not covered as part of SFINAE) and they do not affect warnings/errors
due to visibility (also not covered as part of SFINAE).

There are only two places where this patch is even remotely interesting:
  1) In a few places, the C and C++ front ends have routines with the
same name and signature that have completely different
implementations. For example, build_binary_op in C++ is quite
different from build_binary_op in C, but the middle-end calls this
routine. When I added SFINAE support into build_binary_op, I renamed
the current routine to cp_build_binary_op and added the tsubst_flags_t
parameter for SFINAE support. Then, I added in a bridge function
build_binary_op (with the same signature as the C version) that merely
forwards to cp_build_binary_op.

  2) pedwarns are somewhat interesting. We use pedwarns where
something that is ill-formed according to the C++ standard, but has
well-defined behavior in GCC. When we're substituting for the purposes
of SFINAE, we must tread pedwarns like errors, because silently
accepting these GCC extensions could mean that we select different
overloads or partial specializations than a more strict compiler. Or,
worse, we select one overload with -pedantic and a different overload
without it! So, we treat pedwarns like errors when substituting for
SFINAE (meaning that they cause substitution failures; no diagnostic
emitted), and do what we always did for non-SFINAE cases.

So, this patch is big but mechanical. Its implementation was trivial
in the sense that only once did the addition of SFINAE support into a
function actually cause any regressions in the GCC testsuite. Weigh
that against the 256k of text in this patch, and you'll see just how
mechanical this patch really is. So, I know this patch is big for
stage 3, but it is relatively simple and will certainly be a boon for
C++ programmers trying out C++0x or digging into some of the more
arcane parts of C++ template argument deduction. Plus, committing it
will save me from my personal torment of keeping such a large patch in
sync with the trunk :)

Tested i686-pc-linux-gnu and i386-apple-darwin-10.4.10; okay for mainline?

  - Doug

2007-11-17  Douglas Gregor  <doug.gregor@gmail.com>

	* typeck.c (composite_pointer_type_r): Add SFINAE support.
	(composite_pointer_type): Ditto.
	(common_type): Fix call to composite_pointer_type.
	(cxx_sizeof_nowarn): New; used to be a macro.
	(cxx_sizeof_expr): Add SFINAE support.
	(cxx_alignof_expr): Ditto.
	(decay_conversion): Fix calls for SFINAE support.
	(rationalize_conditional_expr): Add SFINAE support.
	(build_class_member_access_expr): Ditto.
	(finish_class_member_access_expr): Ditto.
	(build_x_indirect_ref): Ditto.
	(build_indirect_ref): Original version renamed to
	cp_build_indirect_ref; new version provides a bridge from
	c-common.
	(cp_build_indirect_ref): Was build_indirect_ref; added SFINAE
	support.
	(get_member_function_from_ptrfunc): Fix calls for SFINAE support.
	(build_function_call): Original version renamed to
	cp_build_function_call; new version provides a bridge from
	c-common.
	(cp_build_function_call): Was build_function_call; added SFINAE
	support.
	(convert_arguments): Add SFINAE support.
	(build_x_binary_op): Ditto.
	(build_binary_op): Original version renamed to cp_build_binary_op;
	new version provides a bridge from c-common.
	(cp_build_binary_op): Was build_binary_op; added SFINAE support.
	(pointer_diff): Fix calls for SFINAE.
	(build_x_unary_op): Add SFINAE support.
	(condition_conversion): Fix calls for SFINAE.
	(build_unary_op): Original version renamed to cp_build_unary_op;
	new version provides a bridge from c-common.
	(cp_build_unary_op): Was build_unary_op; added SFINAE support.
	(unary_complex_lvalue): Fix calls for SFINAE.
	(build_x_conditional_expr): Add SFINAE support.
	(build_x_compound_expr_from_list): Fix calls for SFINAE.
	(build_x_compound_expr): Add SFINAE support.
	(convert_ptrmem): Fix calls for SFINAE.
	(build_static_cast_1): Add SFINAE support.
	(build_static_cast): Ditto.
	(build_reinterpret_cast_1): Ditto.
	(build_reinterpret_cast): Ditto.
	(build_const_cast_1): Ditto.
	(build_const_cast): Ditto.
	(build_c_cast): Ditto.
	(build_modify_expr): Original version renamed to
	cp_build_modify_expr; new version provides a bridge from c-common.
	(cp_build_modify_expr): Was build_modify_expr; added SFINAE
	support.
	(build_x_modify_expr): Add SFINAE support.
	(build_ptrmemfunc): Fix calls for SFINAE.
	(convert_for_assignment): Add SFINAE support.
	(convert_for_initialization): Ditto.
	(check_return_expr): Fix calls for SFINAE.
	(lvalue_or_else): Add SFINAE support.
	* init.c (perform_member_init): Fix calls for SFINAE.
	(emit_mem_initializers): Ditto.
	(expand_virtual_init): Ditto.
	(expand_cleanup_for_base): Ditto.
	(build_aggr_init): Add SFINAE support.
	(expand_default_init): Ditto.
	(expand_aggr_init_1): Fix calls for SFINAE.
	(build_offset_ref): Ditto.
	(build_new_1): Add SFINAE support.
	(build_new): Ditto.
	(build_vec_delete_1): Fix calls for SFINAE.
	(get_temp_regvar): Ditto.
	(build_vec_init): Add SFINAE support.
	(build_dtor_call): Fix calls for SFINAE.
	(build_delete): Ditto.
	(push_base_cleanups): Ditto.
	(build_vec_delete_1): Ditto.
	* class.c (build_base_path): Fix calls for SFINAE.
	(build_simple_base_path): Ditto.
	(convert_to_base_statically): Ditto.
	(build_vfn_ref): Ditto.
	(resolve_address_of_overloaded_function): Ditto.
	* decl.c (check_initializer): Fix calls for SFINAE.
	(register_dtor_fn): Ditto.
	(compute_array_index_type): Ditto.
	(finish_enum): Ditto.
	(start_preparsed_function): Ditto.
	(cxx_maybe_build_cleanup): Ditto.
	* call.c (convert_like): Add COMPLAIN argument.
	(convert_like_with_context): Ditto.
	(build_this): Fix calls for SFINAE.
	(build_user_type_conversion): Ditto.
	(resolve_args): Ditto.
	(build_new_function_call): Add SFINAE support.
	(build_operator_new_call): Fix calls for SFINAE.
	(build_object_call): Add SFINAE support.
	(build_conditional_expr): Ditto.
	(build_new_op): Ditto.
	(build_op_delete_call): Fix calls for SFINAE.
	(build_temp): Ditto.
	(convert_like_real): Add SFINAE support.
	(build_x_va_arg): Fix calls for SFINAE.
	(convert_default_arg): Ditto.
	(build_over_call): Add SFINAE support.
	(build_java_interface_fn_ref): Fix calls for SFINAE.
	(build_special_member_call): Add SFINAE support.
	(build_new_method_call): Ditto.
	(perform_implicit_conversion): Ditto.
	(perform_direct_initialization_if_possible): Ditto.
	(initialize_reference): Fix calls for SFINAE.
	* method.c (do_build_assign_ref): Fix calls for SFINAE.
	* rtti.c (build_headof): Fix calls for SFINAE.
	(get_tinfo_decl_dynamic): Ditto.
	(get_typeid): Ditto.
	(build_dynamic_cast_1): Add SFINAE support.
	(build_dynamic_cast): Ditto.
	(tinfo_base_init): Fix calls for SFINAE.
	* except.c (do_get_exception_ptr): Fix calls for SFINAE.
	(do_end_catch): Ditto.
	(initialize_handler_parm): Ditto.
	(expand_start_catch_block): Ditto.
	(do_allocate_exception): Ditto.
	(do_free_exception): Ditto.
	(build_throw): Ditto.
	* cvt.c (build_up_reference): Fix calls for SFINAE.
	(convert_to_reference): Ditto.
	(ocp_convert): Ditto.
	(convert_to_void): Add SFINAE support.
	* tree.c (build_dummy_object): Fix calls for SFINAE.
	(stabilize_expr): Ditto.
	* cp-tree.h (build_conditional_expr): Add tsubst_flags_t
	parameter.
	(build_new_method_call): Ditto.
	(build_special_member_call): Ditto.
	(build_new_op): Ditto.
	(perform_implicit_conversion): Ditto.
	(perform_direct_initialization_if_possible): Ditto.
	(convert_to_void): Ditto.
	(build_aggr_init): Ditto.
	(build_new): Ditto.
	(build_vec_init): Ditto.
	(build_dynamic_cast): Ditto.
	(finish_call_expr): Ditto
	(cxx_sizeof_or_alignof_expr): Add COMPLAIN parameter.
	(cxx_sizeof_nowarn): Remove macro; add function declaration.
	(build_class_member_access_expr): Add tsubst_flags_t parameter.
	(finish_class_member_access_expr): Ditto.
	(build_x_indirect_ref): Ditto.
	(cp_build_indirect_ref): New.
	(cp_build_function_call): Add tsubst_flags_t parameter.
	(build_x_unary_op): Ditto.
	(cp_build_unary_op): New.
	(build_x_conditional_expr): Add tsubst_flags_t parameter.
	(build_x_compound_expr): Ditto.
	(build_compound_expr): Ditto.
	(build_static_cast): Ditto.
	(build_reinterpret_cast): Ditto.
	(build_const_cast): Ditto.
	(build_c_cast): Ditto.
	(build_x_modify_expr): Ditto.
	(cp_build_modify_expr): New.
	(convert_for_initialization): Add tsubst_flags_t parameter.
	(cp_build_binary_op): Remove macro; add function declaration.
	(invalid_nonstatic_memfn_p): Add tsubst_flags_t parameter.
	(lvalue_or_else): Ditto.
	(build_functional_cast): Ditto.
	* typeck2.c (digest_init): Fix calls for SFINAE.
	(process_init_constructor_array): Ditto.
	(process_init_constructor_record): Ditto.
	(build_x_arrow): Ditto.
	(build_m_component_ref): Ditto.
	(build_functional_cast): Add SFINAE support.
	* pt.c (tsubst_copy_and_build): Add (more) SFINAE support.
	* semantics.c (simplify_loop_decl_cond): Fix calls for SFINAE.
	(finish_expr_stmt): Ditto.
	(finish_for_expr): Ditto.
	(finish_asm_stmt): Ditto.
	(finish_non_static_data_member): Ditto.
	(finish_qualified_id_expr): Ditto.
	(finish_call_expr): Add SFINAE support.
	(finish_increment_expr): Fix calls for SFINAE.
	(finish_unary_op_expr): Ditto.
	(simplify_aggr_init_expr): Ditto.
	(finish_omp_clauses): Ditto.
	(finish_omp_for): Ditto.
	(finish_omp_barrier): Ditto.
	(finish_omo_flush): Ditto.
	* decl2.c (grok_array_decl): Fix calls or SFINAE.
	(build_anon_union_vars): Ditto.
	(get_guard_cond): Ditto.
	(set_guard): Ditto.
	(one_static_initialization_or_destruction): Ditto.
	(do_static_initialization_or_destruction): Ditto.
	(generate_ctor_or_dtor_function): Ditto.
	(build_offset_ref_call_from_tree): Ditto.
	* parser.c (cp_parser_postfix_expression): Fix calls for SFINAE.
	(cp_parser_postfix_dot_deref_expression): Ditto.
	(cp_parser_unary_expression): Ditto.
	(cp_parser_new_expression): Ditto.
	(cp_parser_cast_expression): Ditto.
	(cp_parser_binary_expression): Ditto.
	(cp_parser_question_colon_clause): Ditto.
	(cp_parser_assignment_expression): Ditto.
	(cp_parser_expression): Ditto.
	(cp_parser_builtin_offsetof): Ditto.
	(cp_parser_template_argument): Ditto.
	(cp_parser_functional_cast): Ditto.

2007-11-17  Douglas Gregor  <doug.gregor@gmail.com>

	* c-common.c (c_sizeof_or_alignof_type): If we're not allowed to
	complain when we hit an error, return ERROR_MARK_NODE.

2007-11-17  Douglas Gregor  <doug.gregor@gmail.com>

	* g++.dg/template/sfinae4.C: New.
	* g++.dg/template/sfinae5.C: New.
	* g++.dg/template/sfinae6.C: New.
	* g++.dg/template/sfinae6_neg.C: New.
	* g++.dg/template/sfinae7.C: New.
	* g++.dg/template/sfinae8.C: New.
	* g++.dg/template/sfinae9.C: New.
	* g++.dg/template/sfinae10.C: New.
	* g++.dg/template/sfinae11.C: New.
	* g++.dg/template/sfinae12.C: New.
	* g++.dg/template/sfinae13.C: New.
	* g++.dg/template/sfinae14C: New.

[-- Attachment #2: sfinae-339.patch.gz --]
[-- Type: application/x-gzip, Size: 52398 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [C++ PATCH] Extend SFINAE to all expressions
  2007-11-17 18:08 [C++ PATCH] Extend SFINAE to all expressions Doug Gregor
@ 2007-11-18  5:35 ` Gabriel Dos Reis
  0 siblings, 0 replies; 2+ messages in thread
From: Gabriel Dos Reis @ 2007-11-18  5:35 UTC (permalink / raw)
  To: GCC Patches

"Doug Gregor" <doug.gregor@gmail.com> writes:

[...]

| So, this patch is big but mechanical. Its implementation was trivial
| in the sense that only once did the addition of SFINAE support into a
| function actually cause any regressions in the GCC testsuite. Weigh
| that against the 256k of text in this patch, and you'll see just how
| mechanical this patch really is. So, I know this patch is big for
| stage 3, but it is relatively simple and will certainly be a boon for
| C++ programmers trying out C++0x or digging into some of the more
| arcane parts of C++ template argument deduction. Plus, committing it
| will save me from my personal torment of keeping such a large patch in
| sync with the trunk :)
| 
| Tested i686-pc-linux-gnu and i386-apple-darwin-10.4.10; okay for mainline?

   * the general agreement on getting things in C++0x mode is that
     they must at the very least be in the C++ Workng Draft.  
     This resolution to this very issue (close to my heart) is not.  
     We don't even have a standardese for it yet.
     There still is a debate on where the border line is between hard
     error and sfinae, even if we generally we agreed (CWG+EWG) on the
     general phrase 'all expressions except ...'

   * We're in stage 3; we should come back to this when we are in
     stage 1 and we know what is in thw WD.

-- Gaby

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-11-17 17:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-11-17 18:08 [C++ PATCH] Extend SFINAE to all expressions Doug Gregor
2007-11-18  5:35 ` Gabriel Dos Reis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).