Message ID | alpine.DEB.2.20.9.1602231053180.1231@idea |
---|---|
State | New |
Headers | show |
On Tue, 23 Feb 2016, Patrick Palka wrote: > On Tue, 23 Feb 2016, Marek Polacek wrote: > >> On Tue, Feb 23, 2016 at 09:58:41AM -0500, Patrick Palka wrote: >>> finish_call_expr thinks that a call to a function which has been >>> obfuscated by force_paren_expr is a call to an unknown function. This >>> eventually leads us to not make use of the function's default arguments >>> when processing the argument list. So a function call like f() may >>> compile and yet (f)() may not, if f has defaulted arguments. >>> >>> This patch fixes this inconsistency by making finish_call_expr undo the >>> obfuscation performed by force_paren_expr. >> >> Thanks for the fix. >> >>> new file mode 100644 >>> index 0000000..12462be >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/cpp1y/paren2.C >>> @@ -0,0 +1,25 @@ >>> +// PR c++/69736 >>> + >> >> I'd expect >> // { dg-do compile { target c++14 } } >> here. > > Okay. > >> >>> +void fn1(bool = true) >>> +{ >>> + (fn1)(); >>> +} >>> + >>> +template <typename> >>> +void fn2() >>> +{ >>> + (fn1)(); >>> +} >> >> The test seems to fail here though because of >> testsuite/g++.dg/cpp1y/paren2.C:11:9: error: too few arguments to function >> Why's that? > > Oops... The call to maybe_undo_parenthesized_ref managed to mysteriously > move itself to the wrong place. It should be called before the > processing_template_decl logic, before FN gets wrapped in a > NON_DEPENDENT_EXPR. > > Here's the updated patch, which I'm going to retest just in case. > Actually, this patch is also wrong since we later reject the function call (fn1)() when we attempt to instantiate the enclosing template function fn2<>. Example: template <typename T> void fn2(T a) { (fn1)(); } void foo () { fn2<bool> (true); } This happens because when processing_template_decl, in finish_call_expr we build a non-dependent CALL_EXPR using the obfuscated orig_fn. Then during instantiation, when tsubst_copy_and_build rebuilds this INDIRECT_REF (which is the orig_fn) it does not copy the REF_PARENTHESIZED_P flag to the newly built INDIRECT_REF. So in the subsequent call to finish_call_expr FN is no longer considered to be a parenthesized ref so maybe_undo_parenthesized_ref becomes a no-op. So this can be fixed either by 1. making tsubst_copy_and_build retain the REF_PARENTHESIZED_P flag when processing an INDIRECT_REF, or by 2. moving the call to maybe_undo_parenthesized_ref in finish_call_expr before the assignment of orig_fn so that orig_fn will be un-obfuscated as well, or by 3. making tsubst_copy_and_build call maybe_undo_parenthesized_ref when processing a CALL_EXPR. I don't know which solution is better.
On 02/23/2016 11:24 AM, Patrick Palka wrote: > 1. making tsubst_copy_and_build retain the REF_PARENTHESIZED_P flag when > processing an INDIRECT_REF, or by This should happen in any case. > 2. moving the call to maybe_undo_parenthesized_ref in finish_call_expr before > the assignment of orig_fn so that orig_fn will be un-obfuscated as well, or by This would also be OK; at this point we know the expression isn't the operand of decltype. Jason
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3c23a83a..88c6367 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3393,7 +3393,7 @@ extern void decl_shadowed_for_var_insert (tree, tree); TREE_LANG_FLAG_0 (STRING_CST_CHECK (NODE)) /* Indicates whether a COMPONENT_REF has been parenthesized, or an - INDIRECT_REF comes from parenthesizing a VAR_DECL. Currently only set + INDIRECT_REF comes from parenthesizing a _DECL. Currently only set some of the time in C++14 mode. */ #define REF_PARENTHESIZED_P(NODE) \ @@ -6361,6 +6361,7 @@ extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern cp_expr finish_parenthesized_expr (cp_expr); extern tree force_paren_expr (tree); +extern tree maybe_undo_parenthesized_ref (tree); extern tree finish_non_static_data_member (tree, tree, tree); extern tree begin_stmt_expr (void); extern tree finish_stmt_expr_expr (tree, tree); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 38c7516..e5ecf48 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1673,6 +1673,30 @@ force_paren_expr (tree expr) return expr; } +/* If T is an id-expression obfuscated by force_paren_expr, undo the + obfuscation and return the underlying id-expression. Otherwise + return T. */ + +tree +maybe_undo_parenthesized_ref (tree t) +{ + if (cxx_dialect >= cxx14 + && INDIRECT_REF_P (t) + && REF_PARENTHESIZED_P (t)) + { + t = TREE_OPERAND (t, 0); + while (TREE_CODE (t) == NON_LVALUE_EXPR + || TREE_CODE (t) == NOP_EXPR) + t = TREE_OPERAND (t, 0); + + gcc_assert (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == STATIC_CAST_EXPR); + t = TREE_OPERAND (t, 0); + } + + return t; +} + /* Finish a parenthesized expression EXPR. */ cp_expr @@ -2265,6 +2289,10 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, orig_fn = fn; + /* If FN is a FUNCTION_DECL obfuscated by force_paren_expr, undo + it so that we can tell this is a call to a known function. */ + fn = maybe_undo_parenthesized_ref (fn); + if (processing_template_decl) { /* If the call expression is dependent, build a CALL_EXPR node diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d7ce327..3da6ea1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -8929,17 +8929,7 @@ check_return_expr (tree retval, bool *no_warning) /* If we had an id-expression obfuscated by force_paren_expr, we need to undo it so we can try to treat it as an rvalue below. */ - if (cxx_dialect >= cxx14 - && INDIRECT_REF_P (retval) - && REF_PARENTHESIZED_P (retval)) - { - retval = TREE_OPERAND (retval, 0); - while (TREE_CODE (retval) == NON_LVALUE_EXPR - || TREE_CODE (retval) == NOP_EXPR) - retval = TREE_OPERAND (retval, 0); - gcc_assert (TREE_CODE (retval) == ADDR_EXPR); - retval = TREE_OPERAND (retval, 0); - } + retval = maybe_undo_parenthesized_ref (retval); /* Under C++11 [12.8/32 class.copy], a returned lvalue is sometimes treated as an rvalue for the purposes of overload resolution to diff --git a/gcc/testsuite/g++.dg/cpp1y/paren2.C b/gcc/testsuite/g++.dg/cpp1y/paren2.C new file mode 100644 index 0000000..56736b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/paren2.C @@ -0,0 +1,26 @@ +// PR c++/69736 +// { dg-do compile { target c++14 } } + +void fn1(bool = true) +{ + (fn1)(); +} + +template <typename> +void fn2() +{ + (fn1)(); +} + +struct X +{ + static void fn3(bool = true) + { + (X::fn3)(); + } + + void fn4(bool = true) + { + (X::fn4)(); + } +};