On Feb 8, 2019, Jason Merrill <ja...@redhat.com> wrote: > On 2/8/19 4:07 AM, Alexandre Oliva wrote: >> On Feb 7, 2019, Jason Merrill <ja...@redhat.com> wrote: >> >>> In protected_accessible_p and shared_member_p, if we're left with a >>> USING_DECL after strip_using_decl, we can't give a meaningful answer, >>> and should probably abort; we shouldn't get here with a dependent >>> expression. >> >> In g++.dg/lookup/using39.C, shared_member_p is called by >> cp_parser_primary_expression -> finish_id_expression -> >> finish_id_expression_1 -> finish_qualified_id_expr when parsing 'using >> A<T>::f' in B<T>.
> Then I think finish_qualified_id_expr should check > type_dependent_expression_p first. That works, as long as we take dependent as non-shared, which, no surprise, is what the previous code would accidentally do. Doing otherwise regresses cpp1y/lambda-generic-this1a.C, and I have test results that prove it ;-) (I wonder if that won't malfunction if the name ends up resolving to a static member, or even to a type... Shall I give that a try myself, or do you know we have tests in place for that already?) Anyway, here's the patch that passed regstrapping without regressions on x86_64- and i686-linux-gnu. Ok to install? [PR86379] do not use TREE_TYPE for USING_DECL_SCOPE From: Alexandre Oliva <aol...@redhat.com> It's too risky to reuse the type field for USING_DECL_SCOPE. Language-independent parts of the compiler, such as location and non-lvalue wrappers, happily take the TREE_TYPE of a USING_DECL as if it was a type rather than an unrelated scope. For better or worse, USING_DECLs use the non-common struct so we can use the otherwise unused result field. Adjust fallout, from uses of TREE_TYPE that were supposed to be USING_DECL_SCOPE, to other accidental uses of TREE_TYPE of a USING_DECL. for gcc/cp/ChangeLog PR c++/86379 * cp-tree.h (USING_DECL_SCOPE): Use result rather than type. * name-lookup.c (strip_using_decl): Use USING_DECL_SCOPE. * search.c (protected_accessible_p): Follow USING_DECL_DECLS. (shared_member_p): Likewise. (lookup_member): Likewise. * decl.c (grok_special_member_properties): Skip USING_DECLs. * semantics.c (finish_omp_declare_simd_methods): Likewise. (finish_qualified_id_expr): Do not call shared_member_p with a dependent expr. for gcc/testsuite/ChangeLog PR c++/86379 * g++.dg/cpp0x/pr86379.C: New. --- gcc/cp/cp-tree.h | 2 gcc/cp/decl.c | 3 gcc/cp/name-lookup.c | 2 gcc/cp/search.c | 19 +++ gcc/cp/semantics.c | 6 + gcc/testsuite/g++.dg/cpp0x/pr86379.C | 207 ++++++++++++++++++++++++++++++++++ 6 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr86379.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index dada3a6aa410..44a3620a539f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3293,7 +3293,7 @@ struct GTY(()) lang_decl { #define DECL_DEPENDENT_P(NODE) DECL_LANG_FLAG_0 (USING_DECL_CHECK (NODE)) /* The scope named in a using decl. */ -#define USING_DECL_SCOPE(NODE) TREE_TYPE (USING_DECL_CHECK (NODE)) +#define USING_DECL_SCOPE(NODE) DECL_RESULT_FLD (USING_DECL_CHECK (NODE)) /* The decls named by a using decl. */ #define USING_DECL_DECLS(NODE) DECL_INITIAL (USING_DECL_CHECK (NODE)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 65ba812deb67..373b79b844dc 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13297,7 +13297,8 @@ grok_special_member_properties (tree decl) { tree class_type; - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + if (TREE_CODE (decl) == USING_DECL + || !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) return; class_type = DECL_CONTEXT (decl); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index d7b9029b0a3a..959f43b02384 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2100,7 +2100,7 @@ strip_using_decl (tree decl) using typename :: [opt] nested-name-specifier unqualified-id ; */ - decl = make_typename_type (TREE_TYPE (decl), + decl = make_typename_type (USING_DECL_SCOPE (decl), DECL_NAME (decl), typename_type, tf_error); if (decl != error_mark_node) diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 0367e4952138..4c3fffda717c 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -623,6 +623,11 @@ protected_accessible_p (tree decl, tree derived, tree type, tree otype) if (!DERIVED_FROM_P (type, derived)) return 0; + /* DECL_NONSTATIC_MEMBER_P won't work for USING_DECLs. */ + decl = strip_using_decl (decl); + /* We don't expect or support dependent decls. */ + gcc_assert (TREE_CODE (decl) != USING_DECL); + /* [class.protected] When a friend or a member function of a derived class references @@ -928,8 +933,13 @@ shared_member_p (tree t) if (is_overloaded_fn (t)) { for (ovl_iterator iter (get_fns (t)); iter; ++iter) - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (*iter)) - return 0; + { + tree decl = strip_using_decl (*iter); + /* We don't expect or support dependent decls. */ + gcc_assert (TREE_CODE (decl) != USING_DECL); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + return 0; + } return 1; } return 0; @@ -1177,7 +1187,10 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, && !really_overloaded_fn (rval)) { tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval; - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + decl = strip_using_decl (decl); + /* A dependent USING_DECL will be checked after tsubsting. */ + if (TREE_CODE (decl) != USING_DECL + && !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) && !perform_or_defer_access_check (basetype_path, decl, decl, complain, afi)) rval = error_mark_node; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 786f18ab0c8b..89ea438ebeef 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2096,7 +2096,8 @@ finish_qualified_id_expr (tree qualifying_class, { /* See if any of the functions are non-static members. */ /* If so, the expression may be relative to 'this'. */ - if (!shared_member_p (expr) + if ((type_dependent_expression_p (expr) + || !shared_member_p (expr)) && current_class_ptr && DERIVED_FROM_P (qualifying_class, current_nonlambda_class_type ())) @@ -5867,7 +5868,8 @@ finish_omp_declare_simd_methods (tree t) for (tree x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x)) { - if (TREE_CODE (TREE_TYPE (x)) != METHOD_TYPE) + if (TREE_CODE (x) == USING_DECL + || !DECL_NONSTATIC_MEMBER_FUNCTION_P (x)) continue; tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x)); if (!ods || !TREE_VALUE (ods)) diff --git a/gcc/testsuite/g++.dg/cpp0x/pr86379.C b/gcc/testsuite/g++.dg/cpp0x/pr86379.C new file mode 100644 index 000000000000..82282eae8e52 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr86379.C @@ -0,0 +1,207 @@ +// { dg-do compile { target c++11 } } + +// Reduced from Mozilla SpiderMonkey, licensed under MPL-2.0. + +template<typename T, unsigned N> +class Vector +{ + public: + Vector() {} + unsigned length() const { return 0; } +}; + +class TokenStreamShared +{ +}; + +template<typename CharT, class AnyCharsAccess> +class TokenStreamSpecific; + +class TokenStreamAnyChars + : public TokenStreamShared +{ + public: + TokenStreamAnyChars() {} +}; + +template<typename CharT> +class SourceUnits +{ + public: + SourceUnits() {} + + bool atEnd() const { return true; } + unsigned offset() const { return 0; } + bool matchCodeUnit(CharT c) { return true; } +}; + +class TokenStreamCharsShared +{ + using CharBuffer = Vector<char16_t, 32>; + + protected: + CharBuffer charBuffer; + + protected: + explicit TokenStreamCharsShared() {} +}; + +template<typename CharT> +class TokenStreamCharsBase + : public TokenStreamCharsShared +{ + public: + TokenStreamCharsBase() + : TokenStreamCharsShared(), sourceUnits() + {} + + using SourceUnits = ::SourceUnits<CharT>; + + bool matchCodeUnit(int expect) { return true; } + + protected: + SourceUnits sourceUnits; +}; + +template<typename CharT, class AnyCharsAccess> +class GeneralTokenStreamChars + : public TokenStreamCharsBase<CharT> +{ + using CharsBase = TokenStreamCharsBase<CharT>; + + protected: + using CharsBase::CharsBase; + + TokenStreamAnyChars& anyCharsAccess(); + const TokenStreamAnyChars& anyCharsAccess() const; +}; + +template<typename CharT, class AnyCharsAccess> class TokenStreamChars; + +template<class AnyCharsAccess> +class TokenStreamChars<char16_t, AnyCharsAccess> + : public GeneralTokenStreamChars<char16_t, AnyCharsAccess> +{ + private: + using CharsBase = TokenStreamCharsBase<char16_t>; + using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>; + using Self = TokenStreamChars<char16_t, AnyCharsAccess>; + + protected: + using GeneralCharsBase::anyCharsAccess; + using CharsBase::sourceUnits; + + using typename GeneralCharsBase::SourceUnits; + + protected: + using GeneralCharsBase::GeneralCharsBase; + + bool getFullAsciiCodePoint(int lead, int* codePoint) { + if (lead == '\r') { + bool isAtEnd = sourceUnits.atEnd(); + if (!isAtEnd) + sourceUnits.matchCodeUnit('\n'); + } else if (lead != '\n') { + *codePoint = lead; + return true; + } + + *codePoint = '\n'; + return true; + } +}; + +template<typename CharT, class AnyCharsAccess> +class TokenStreamSpecific + : public TokenStreamChars<CharT, AnyCharsAccess>, + public TokenStreamShared +{ + public: + using CharsBase = TokenStreamCharsBase<CharT>; + using GeneralCharsBase = GeneralTokenStreamChars<CharT, AnyCharsAccess>; + using SpecializedCharsBase = TokenStreamChars<CharT, AnyCharsAccess>; + + public: + using GeneralCharsBase::anyCharsAccess; + + private: + using typename CharsBase::SourceUnits; + + private: + using TokenStreamCharsShared::charBuffer; + using CharsBase::sourceUnits; + + public: + TokenStreamSpecific() + : SpecializedCharsBase() + {} + + public: + bool advance(unsigned position) { + bool t = charBuffer.length() + 1 > 0; + auto offs = sourceUnits.offset(); + return t && offs > 0; + } +}; + +class TokenStreamAnyCharsAccess +{ +}; + +class TokenStream final + : public TokenStreamAnyChars, + public TokenStreamSpecific<char16_t, TokenStreamAnyCharsAccess> +{ + using CharT = char16_t; + + public: + TokenStream() + : TokenStreamAnyChars(), + TokenStreamSpecific<CharT, TokenStreamAnyCharsAccess>() + {} +}; + +class SyntaxParseHandler {}; + +class ParserBase +{ + public: + TokenStreamAnyChars anyChars; +}; + +template<class ParseHandler, typename CharT> class GeneralParser; + +template <class ParseHandler> +class PerHandlerParser : public ParserBase +{ +}; + +template<class Parser> +class ParserAnyCharsAccess +{ +}; + +template <class ParseHandler, typename CharT> +class Parser; + +template <class ParseHandler, typename CharT> +class GeneralParser + : public PerHandlerParser<ParseHandler> +{ + public: + TokenStreamSpecific<CharT, ParserAnyCharsAccess<GeneralParser>> tokenStream; + + public: + GeneralParser(); +}; + + +template class TokenStreamCharsBase<char16_t>; + +template class TokenStreamChars<char16_t, TokenStreamAnyCharsAccess>; + +template class +TokenStreamChars<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>; + +template class +TokenStreamSpecific<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>; -- Alexandre Oliva, freedom fighter https://FSFLA.org/blogs/lxo Be the change, be Free! FSF Latin America board member GNU Toolchain Engineer Free Software Evangelist Hay que enGNUrecerse, pero sin perder la terGNUra jamás-GNUChe