aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2020-05-01 16:18:19 -0400
committerPatrick Palka <ppalka@redhat.com>2020-05-01 16:37:57 -0400
commit4f6c1ca287d2c64856ef67fa50bc462633d5b8cf (patch)
tree24cfe5a8dd12327815e4d4e7566b6e0b7d2dcd9c
parent30da2906ac521749aef8260fc1d942e62073f19d (diff)
downloadgcc-4f6c1ca287d2c64856ef67fa50bc462633d5b8cf.zip
gcc-4f6c1ca287d2c64856ef67fa50bc462633d5b8cf.tar.gz
gcc-4f6c1ca287d2c64856ef67fa50bc462633d5b8cf.tar.bz2
c++: Missing SFINAE with inaccessible static data member [PR90880]
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.
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/parser.c3
-rw-r--r--gcc/cp/pt.c5
-rw-r--r--gcc/cp/semantics.c18
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/sfinae29.C25
7 files changed, 61 insertions, 11 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0b6b0ee..5f2db01 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e115a8a..c4b8142 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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 *);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e1f9786..337f22d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9332865..8106c25 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 64a7b76..4d1592a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 997ef8d..176aa11 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..0ccaea8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sfinae29.C
@@ -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");
+}