On Fri, Apr 29, 2016 at 11:55 AM, Patrick Palka <patr...@parcs.ath.cx> wrote: > The problem here is that some code paths are not prepared to handle a > non-dependent PAREN_EXPR, which my fix for PR c++/70106 introduced. In > particular lvalue_kind() returns clk_none for a PAREN_EXPR which makes > build_x_unary_op() emit a bogus error for an expression like &(A::b). > (If the PAREN_EXPR were dependent then lvalue_kind() wouldn't get called > in the first place, build_x_unary_op() would exit early.) > > This patch replaces the 70106 fix. Instead of wrapping a SCOPE_REF in a > PAREN_EXPR, this patch overloads the REF_PARENTHESIZED_P to apply to > SCOPE_REFs too. This makes sense to me because the two tree codes are > closely related (e.g. a SCOPE_REF before instantiation may become a > COMPONENT_REF after instantiation) so they should be treated similarly > by force_paren_expr(). > > There are two rather simpler ways to fix this PR. One is to make > lvalue_kind() recurse into PAREN_EXPRs (although other parts of the FE > may be mishandling non-dependent PAREN_EXPRs as well), and the other is > to make force_paren_expr() never return a non-dependent PAREN_EXPR, > which can be achieved by building the PAREN_EXPR with build_nt(). I am > not sure which approach is best for GCC 7 and for GCC 6. > > Somewhat unrelated the fix: I couldn't find an existing test that > checked that force_paren_expr handles SCOPE_REFs properly wrt auto > deduction so I added one. > > Bootstrap and regtesting in progress on x86_64-pc-linux-gnu. > > gcc/cp/ChangeLog: > > PR c++/70822 > PR c++/70106 > * cp-tree.h (REF_PARENTHESIZED_P): Make this flag apply to > SCOPE_REFs too. > * pt.c (tsubst_qualified_id): If REF_PARENTHESIZED_P is set > on the qualified_id then propagate it to the resulting > expression. > (do_auto_deduction): Check REF_PARENTHESIZED_P on SCOPE_REFs > too. > * semantics.c (force_paren_expr): If given a SCOPE_REF, just set > its REF_PARENTHESIZED_P flag. > > gcc/testsuite/ChangeLog: > > PR c++/70822 > PR c++/70106 > * g++.dg/cpp1y/auto-fn31.C: New test. > * g++.dg/cpp1y/paren4.C: New test. > --- > gcc/cp/cp-tree.h | 4 ++-- > gcc/cp/pt.c | 15 +++++++++++---- > gcc/cp/semantics.c | 13 +++---------- > gcc/testsuite/g++.dg/cpp1y/auto-fn31.C | 33 +++++++++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/cpp1y/paren4.C | 14 ++++++++++++++ > 5 files changed, 63 insertions(+), 16 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn31.C > create mode 100644 gcc/testsuite/g++.dg/cpp1y/paren4.C > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 2caf7ce..0df5953 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -170,7 +170,7 @@ operator == (const cp_expr &lhs, tree rhs) > TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) > FNDECL_USED_AUTO (in FUNCTION_DECL) > DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) > - REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF) > + REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF) > AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) > CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) > 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). > @@ -3403,7 +3403,7 @@ extern void decl_shadowed_for_var_insert (tree, tree); > some of the time in C++14 mode. */ > > #define REF_PARENTHESIZED_P(NODE) \ > - TREE_LANG_FLAG_2 (TREE_CHECK2 ((NODE), COMPONENT_REF, INDIRECT_REF)) > + TREE_LANG_FLAG_2 (TREE_CHECK3 ((NODE), COMPONENT_REF, INDIRECT_REF, > SCOPE_REF)) > > /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a > constructor call, rather than an ordinary function call. */ > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index e7ec629..7adf308 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -13741,8 +13741,10 @@ tsubst_qualified_id (tree qualified_id, tree args, > { > if (is_template) > expr = build_min_nt_loc (loc, TEMPLATE_ID_EXPR, expr, template_args); > - return build_qualified_name (NULL_TREE, scope, expr, > - QUALIFIED_NAME_IS_TEMPLATE (qualified_id)); > + tree r = build_qualified_name (NULL_TREE, scope, expr, > + QUALIFIED_NAME_IS_TEMPLATE > (qualified_id)); > + REF_PARENTHESIZED_P (r) = REF_PARENTHESIZED_P (qualified_id); > + return r; > } > > if (!BASELINK_P (name) && !DECL_P (expr)) > @@ -13822,6 +13824,9 @@ tsubst_qualified_id (tree qualified_id, tree args, > && TREE_CODE (expr) != OFFSET_REF) > expr = convert_from_reference (expr); > > + if (REF_PARENTHESIZED_P (qualified_id)) > + expr = force_paren_expr (expr); > + > return expr; > } > > @@ -23966,8 +23971,10 @@ do_auto_deduction (tree type, tree init, tree > auto_node, > > if (AUTO_IS_DECLTYPE (auto_node)) > { > - bool id = (DECL_P (init) || (TREE_CODE (init) == COMPONENT_REF > - && !REF_PARENTHESIZED_P (init))); > + bool id = (DECL_P (init) > + || ((TREE_CODE (init) == COMPONENT_REF > + || TREE_CODE (init) == SCOPE_REF) > + && !REF_PARENTHESIZED_P (init))); > targs = make_tree_vec (1); > TREE_VEC_ELT (targs, 0) > = finish_decltype_type (init, id, tf_warning_or_error); > diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c > index bb13fad..89da773 100644 > --- a/gcc/cp/semantics.c > +++ b/gcc/cp/semantics.c > @@ -1647,17 +1647,10 @@ force_paren_expr (tree expr) > && TREE_CODE (expr) != SCOPE_REF) > return expr; > > - if (TREE_CODE (expr) == COMPONENT_REF) > + if (TREE_CODE (expr) == COMPONENT_REF > + || TREE_CODE (expr) == SCOPE_REF) > REF_PARENTHESIZED_P (expr) = true; > - else if (type_dependent_expression_p (expr) > - /* When processing_template_decl, a SCOPE_REF may actually be > - referring to a non-static data member of the current class, in > - which case its TREE_TYPE may not be properly cv-qualified (the > - cv-qualifiers of the implicit *this object haven't yet been > taken > - into account) so we have to delay building a static_cast until > - instantiation. */ > - || (processing_template_decl > - && TREE_CODE (expr) == SCOPE_REF)) > + else if (type_dependent_expression_p (expr)) > expr = build1 (PAREN_EXPR, TREE_TYPE (expr), expr); > else if (VAR_P (expr) && DECL_HARD_REGISTER (expr)) > /* We can't bind a hard register variable to a reference. */; > diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn31.C > b/gcc/testsuite/g++.dg/cpp1y/auto-fn31.C > new file mode 100644 > index 0000000..0a5dafc > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn31.C > @@ -0,0 +1,33 @@ > +// { dg-do compile { target c++14 } } > + > +template<class,class> struct same_type; > +template<class T> struct same_type<T,T> {}; > + > +struct A > +{ > + static int b; > + int c; > + > + template <int> > + decltype(auto) f() { return A::c; } > + > + template <int> > + decltype(auto) g() { return (A::c); } > +}; > + > +A a; > + > +template <int> > +decltype(auto) f() { return A::b; } > + > +template <int> > +decltype(auto) g() { return (A::b); } > + > +int main() > +{ > + same_type<decltype(f<0>()), int>(); > + same_type<decltype(g<0>()), int&>(); > + > + same_type<decltype(a.f<0>()), int>(); > + same_type<decltype(a.g<0>()), int&>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp1y/paren4.C > b/gcc/testsuite/g++.dg/cpp1y/paren4.C > new file mode 100644 > index 0000000..71abe84 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1y/paren4.C > @@ -0,0 +1,14 @@ > +// PR c++/70822 > +// { dg-do compile { target c++14 } } > + > +struct a > +{ > + static int b; > +}; > + > +template <typename> > +void > +foo () > +{ > + &(a::b); > +} > -- > 2.8.1.361.g2fbef4c >
Ping.