It's too risk 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.

Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?
(but see the additional patchlet below)


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 (copy_fn_p): Likewise.
        (grok_special_member_properties): Do not test USING_DECL for
        staticness.
        * semantics.c (finish_omp_declare_simd_methods): Likewise.

for  gcc/testsuite/ChangeLog

        PR c++/86379
        * g++.dg/cpp0x/pr86379.C: New.
---
 gcc/cp/cp-tree.h                     |    2 
 gcc/cp/decl.c                        |   10 +-
 gcc/cp/name-lookup.c                 |    2 
 gcc/cp/search.c                      |   23 +++-
 gcc/cp/semantics.c                   |    3 
 gcc/testsuite/g++.dg/cpp0x/pr86379.C |  207 ++++++++++++++++++++++++++++++++++
 6 files changed, 240 insertions(+), 7 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 77e1425b4357b..053ed5ace6d42 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3288,7 +3288,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 79eeac177b64c..86101d3bc3b45 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13174,6 +13174,13 @@ copy_fn_p (const_tree d)
   tree arg_type;
   int result = 1;
 
+  while (TREE_CODE (d) == USING_DECL)
+    {
+      d = USING_DECL_DECLS (d);
+      if (!d)
+       return result;
+    }
+
   gcc_assert (DECL_FUNCTION_MEMBER_P (d));
 
   if (TREE_CODE (d) == TEMPLATE_DECL
@@ -13288,7 +13295,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 d7b9029b0a3a5..959f43b023844 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 0367e49521380..4e0a9b722ea64 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -623,6 +623,14 @@ 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.  */
+  while (TREE_CODE (decl) == USING_DECL)
+    {
+      decl = USING_DECL_DECLS (decl);
+      if (!decl)
+       break;
+    }
+
   /* [class.protected]
 
      When a friend or a member function of a derived class references
@@ -634,7 +642,7 @@ protected_accessible_p (tree decl, tree derived, tree type, 
tree otype)
      derived from that class) (_expr.ref_).  If the access is to form
      a pointer to member, the nested-name-specifier shall name the
      derived class (or any class derived from that class).  */
-  if (DECL_NONSTATIC_MEMBER_P (decl)
+  if (decl && DECL_NONSTATIC_MEMBER_P (decl)
       && !DERIVED_FROM_P (derived, otype))
     return 0;
 
@@ -928,7 +936,10 @@ 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))
+       if (TREE_CODE (*iter) != USING_DECL
+           ? DECL_NONSTATIC_MEMBER_FUNCTION_P (*iter)
+           : (USING_DECL_DECLS (*iter)
+              && !shared_member_p (USING_DECL_DECLS (*iter))))
          return 0;
       return 1;
     }
@@ -1177,7 +1188,13 @@ 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)
+      while (TREE_CODE (decl) == USING_DECL)
+       {
+         decl = USING_DECL_DECLS (decl);
+         if (!decl)
+           break;
+       }
+      if (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 786f18ab0c8b5..2009a10b4e85c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5867,7 +5867,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 0000000000000..82282eae8e52b
--- /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>>>;



Now, here's an experiment I started and haven't completed yet.  It's an
incremental patch based on the one above, that still falls short of
preventing access to TREE_TYPE of USING_DECLs, but that catches accesses
of USING_DECLs in predicates intended for member FUNCTION_DECL (or
TEMPLATE_DECL), and that were possibly misbehaving with the reuse of
USING_DECL's TREE_TYPE to hold the target scope.  It bootstraps
successfully, but there are some two dozens of testsuite regressions.
Is this worth pursuing?

[PR86379] check for function_decl in memfn-testing predicates

---
 gcc/cp/cp-tree.h   |   20 +++++++++++++++-----
 gcc/cp/search.c    |    5 ++++-
 gcc/cp/semantics.c |    2 +-
 gcc/cp/typeck.c    |    3 ++-
 4 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 053ed5ace6d42..371398d85bde9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -568,6 +568,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define VAR_OR_FUNCTION_DECL_CHECK(NODE) \
   TREE_CHECK2(NODE,VAR_DECL,FUNCTION_DECL)
 
+#define FUNCTION_OR_TEMPLATE_DECL_CHECK(NODE) \
+  TREE_CHECK2(NODE,FUNCTION_DECL,TEMPLATE_DECL)
+
 #define TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK(NODE) \
   TREE_CHECK3(NODE,TYPE_DECL,TEMPLATE_DECL,FUNCTION_DECL)
 
@@ -3004,15 +3007,21 @@ struct GTY(()) lang_decl {
 #define DECL_BEFRIENDING_CLASSES(NODE) \
   (LANG_DECL_FN_CHECK (NODE)->befriending_classes)
 
+#define FUNCTION_OR_TEMPLATE_DECL_P(NODE) \
+  (TREE_CODE (NODE) == FUNCTION_DECL     \
+   || TREE_CODE (NODE) == TEMPLATE_DECL)
+
 /* Nonzero for FUNCTION_DECL means that this decl is a static
    member function.  */
 #define DECL_STATIC_FUNCTION_P(NODE) \
-  (LANG_DECL_FN_CHECK (NODE)->static_function)
+  (LANG_DECL_FN_CHECK (FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \
+   ->static_function)
 
 /* Nonzero for FUNCTION_DECL means that this decl is a non-static
    member function.  */
 #define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE) \
-  (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+  (TREE_CODE (TREE_TYPE (FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)))      \
+   == METHOD_TYPE)
 
 /* Nonzero for FUNCTION_DECL means that this decl is a member function
    (static or non-static).  */
@@ -3034,9 +3043,10 @@ struct GTY(()) lang_decl {
                                  (TYPE_ARG_TYPES (TREE_TYPE (NODE))))))
 
 /* Nonzero for a DECL means that this member is a non-static member.  */
-#define DECL_NONSTATIC_MEMBER_P(NODE)          \
-  (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE)     \
-   || TREE_CODE (NODE) == FIELD_DECL)
+#define DECL_NONSTATIC_MEMBER_P(NODE)                  \
+  (TREE_CODE (NODE) == FIELD_DECL                      \
+   || (FUNCTION_OR_TEMPLATE_DECL_P (NODE)              \
+       && DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE)))
 
 /* Nonzero for _DECL means that this member object type
    is mutable.  */
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 4e0a9b722ea64..f6518d52126b1 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1193,8 +1193,11 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
          decl = USING_DECL_DECLS (decl);
          if (!decl)
            break;
+         if (is_overloaded_fn (decl))
+           decl = get_first_fn (decl);
        }
-      if (decl && !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
+      if (decl && (!FUNCTION_OR_TEMPLATE_DECL_P (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 2009a10b4e85c..ea147b428136b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5867,7 +5867,7 @@ finish_omp_declare_simd_methods (tree t)
 
   for (tree x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x))
     {
-      if (TREE_CODE (x) == USING_DECL
+      if (!FUNCTION_OR_TEMPLATE_DECL_P (x)
          || !DECL_NONSTATIC_MEMBER_FUNCTION_P (x))
        continue;
       tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x));
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ec722a360357d..b132d847a1c09 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1887,7 +1887,8 @@ invalid_nonstatic_memfn_p (location_t loc, tree expr, 
tsubst_flags_t complain)
     return false;
   if (is_overloaded_fn (expr) && !really_overloaded_fn (expr))
     expr = get_first_fn (expr);
-  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (expr))
+  if (FUNCTION_OR_TEMPLATE_DECL_P (expr)
+      && DECL_NONSTATIC_MEMBER_FUNCTION_P (expr))
     {
       if (complain & tf_error)
        {


-- 
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

Reply via email to