+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
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 *);
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);
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;
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;
/* 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:
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
+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
--- /dev/null
+// 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");
+}