c++: Missing SFINAE with inaccessible static data member [PR90880]
authorPatrick Palka <ppalka@redhat.com>
Fri, 1 May 2020 20:18:19 +0000 (16:18 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 1 May 2020 20:37:57 +0000 (16:37 -0400)
This is a missing SFINAE issue when verifying the accessibility of a
static data member.

The cause is that check_accessibility_of_qualified_id unconditionally
passes tf_warning_or_error to perform_or_defer_access_check, even when
called from tsubst_qualified_id(..., complain=tf_none).

This patch fixes this by plumbing 'complain' from tsubst_qualified_id
through check_accessibility_of_qualified_id to reach
perform_or_defer_access_check, and by giving
check_accessibility_of_qualified_id the appropriate return value.

gcc/cp/ChangeLog:

PR c++/90880
* cp-tree.h (check_accessibility_of_qualified_id): Add
tsubst_flags_t parameter and change return type to bool.
* parser.c (cp_parser_lookup_name): Pass tf_warning_to_error to
check_accessibility_of_qualified_id.
* pt.c (tsubst_qualified_id): Return error_mark_node if
check_accessibility_of_qualified_id returns false.
* semantics.c (check_accessibility_of_qualified_id): Add
complain parameter.  Pass complain instead of
tf_warning_or_error to perform_or_defer_access_check.  Return
true unless perform_or_defer_access_check returns false.

gcc/testsuite/ChangeLog:

PR c++/90880
* g++.dg/template/sfinae29.C: New test.

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/sfinae29.C [new file with mode: 0644]

index 0b6b0ee2f5ff816321690b2816795afdd9a4c5e2..5f2db010cb2b1b2f47a772dc3317a49e59dd86a2 100644 (file)
@@ -1,3 +1,17 @@
+2020-05-01  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/90880
+       * cp-tree.h (check_accessibility_of_qualified_id): Add
+       tsubst_flags_t parameter and change return type to bool.
+       * parser.c (cp_parser_lookup_name): Pass tf_warning_to_error to
+       check_accessibility_of_qualified_id.
+       * pt.c (tsubst_qualified_id): Return error_mark_node if
+       check_accessibility_of_qualified_id returns false.
+       * semantics.c (check_accessibility_of_qualified_id): Add
+       complain parameter.  Pass complain instead of
+       tf_warning_or_error to perform_or_defer_access_check.  Return
+       true unless perform_or_defer_access_check returns false.
+
 2020-05-01  Marek Polacek  <polacek@redhat.com>
 
        PR c++/94885
index e115a8a1d25484765f138b5de44c9945d53d6742..c4b81428e143c69c647483098da7e53b165a5fc7 100644 (file)
@@ -7258,7 +7258,7 @@ extern bool expand_or_defer_fn_1          (tree);
 extern void expand_or_defer_fn                 (tree);
 extern void add_typedef_to_current_template_for_access_check (tree, tree,
                                                              location_t);
-extern void check_accessibility_of_qualified_id (tree, tree, tree);
+extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t);
 extern tree finish_qualified_id_expr           (tree, tree, bool, bool,
                                                 bool, bool, tsubst_flags_t);
 extern void simplify_aggr_init_expr            (tree *);
index e1f9786893acd460c0e0e6adf1423dfc3b1d0e50..337f22d2784074f3d03cc99e8fc9ade8d7693f39 100644 (file)
@@ -28394,7 +28394,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
      During an explicit instantiation, access is not checked at all,
      as per [temp.explicit].  */
   if (DECL_P (decl))
-    check_accessibility_of_qualified_id (decl, object_type, parser->scope);
+    check_accessibility_of_qualified_id (decl, object_type, parser->scope,
+                                        tf_warning_or_error);
 
   maybe_record_typedef_use (decl);
 
index 9332865cf468749689c95f1977bdbf40f5a30d37..8106c25a2d98e599906f01671055c3a7af6fc772 100644 (file)
@@ -16180,8 +16180,9 @@ tsubst_qualified_id (tree qualified_id, tree args,
 
   if (DECL_P (expr))
     {
-      check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
-                                          scope);
+      if (!check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
+                                               scope, complain))
+       return error_mark_node;
       /* Remember that there was a reference to this entity.  */
       if (!mark_used (expr, complain) && !(complain & tf_error))
        return error_mark_node;
index 64a7b76d43783788be3b2ffb8e96962fd83cf1e4..4d1592ab0d2f3960b298941e7318aece4789411d 100644 (file)
@@ -2028,12 +2028,14 @@ add_typedef_to_current_template_for_access_check (tree typedef_decl,
    an error message if it is not accessible.  If OBJECT_TYPE is
    non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
    type of `*x', or `x', respectively.  If the DECL was named as
-   `A::B' then NESTED_NAME_SPECIFIER is `A'.  */
+   `A::B' then NESTED_NAME_SPECIFIER is `A'.  Return value is like
+   perform_access_checks above.  */
 
-void
+bool
 check_accessibility_of_qualified_id (tree decl,
                                     tree object_type,
-                                    tree nested_name_specifier)
+                                    tree nested_name_specifier,
+                                    tsubst_flags_t complain)
 {
   tree scope;
   tree qualifying_type = NULL_TREE;
@@ -2050,13 +2052,13 @@ check_accessibility_of_qualified_id (tree decl,
 
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
-    return;
+    return true;
 
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
   /* If the SCOPE is not a type, then DECL is not a member.  */
   if (!TYPE_P (scope))
-    return;
+    return true;
   /* Compute the scope through which DECL is being accessed.  */
   if (object_type
       /* OBJECT_TYPE might not be a class type; consider:
@@ -2097,8 +2099,10 @@ check_accessibility_of_qualified_id (tree decl,
         or similar in a default argument value.  */
       && CLASS_TYPE_P (qualifying_type)
       && !dependent_type_p (qualifying_type))
-    perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
-                                  decl, tf_warning_or_error);
+    return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
+                                         decl, complain);
+
+  return true;
 }
 
 /* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
index 997ef8d091c8f6f788da000fb82a175c4f815c09..176aa117904b3e27cc73454630d73b2cf1cd2798 100644 (file)
@@ -1,3 +1,8 @@
+2020-05-01  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/90880
+       * g++.dg/template/sfinae29.C: New test.
+
 2020-05-01  Marek Polacek  <polacek@redhat.com>
 
        PR c++/94885
diff --git a/gcc/testsuite/g++.dg/template/sfinae29.C b/gcc/testsuite/g++.dg/template/sfinae29.C
new file mode 100644 (file)
index 0000000..0ccaea8
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/90880
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename = void>
+struct status
+{ static const bool value = false; };
+
+template <typename T>
+struct status<T, decltype((void)T::member)>
+{ static const bool value = true; };
+
+struct s1{int member;};
+struct s2{int _member;};
+
+class c1{int member;};
+class c2{int _member;};
+
+void
+foo()
+{
+  static_assert(status<s1>::value, "has member");
+  static_assert(!status<s2>::value, "has no member");
+  static_assert(!status<c1>::value, "has inaccessible member");
+  static_assert(!status<c2>::value, "has no member");
+}