public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Paolo Carlini <paolo.carlini@oracle.com>
To: "gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>
Cc: Jason Merrill <jason@redhat.com>
Subject: [C++ RFC / Patch] PR 51213 ("access control under SFINAE")
Date: Fri, 15 Jun 2012 14:57:00 -0000	[thread overview]
Message-ID: <4FDB4640.3050502@oracle.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 3021 bytes --]

Hi,

as I mentioned a few days ago, I'm working on implementing this feature, 
which I personally consider rather high priority, from the library point 
of view too (eg, <type_traits>).

I have been making some progress - I'm attaching below what I have so 
far in my local tree - but I also think it's time to get feedback both 
about the general approach and about more specific issues with the 
testsuite. The attached leads to unexpected fails for 4 testcases in 
g++.dg, which I would bundle in 2 pairs: I (we) should obviously do 
something about both but the second one seems more subtle (and indeed 
I'm looking for guidance!). The first pair is:

FAIL: g++.dg/template/access7.C -std=c++98 (test for errors, line 8)
FAIL: g++.dg/template/access7.C -std=c++98 (test for errors, line 12)
FAIL: g++.dg/template/access7.C -std=c++98 (test for warnings, line 17)
FAIL: g++.dg/template/access7.C -std=c++98 (test for excess errors)
FAIL: g++.dg/template/access7.C -std=c++11 (test for excess errors)
FAIL: g++.dg/template/typedef11.C -std=c++98 (test for errors, line 8)
FAIL: g++.dg/template/typedef11.C -std=c++98 (test for errors, line 14)
FAIL: g++.dg/template/typedef11.C -std=c++98 (test for errors, line 25)
FAIL: g++.dg/template/typedef11.C -std=c++98 (test for excess errors)
FAIL: g++.dg/template/typedef11.C -std=c++11 (test for errors, line 8)
FAIL: g++.dg/template/typedef11.C -std=c++11 (test for errors, line 14)
FAIL: g++.dg/template/typedef11.C -std=c++11 (test for errors, line 25)
FAIL: g++.dg/template/typedef11.C -std=c++11 (test for excess errors)

The problem is that with the patch applied we get errors of the "no 
matching function" type, instead of access control errors. For example, 
for access7.C:

access7.C: In function ‘void g()’:
access7.C:17:15: error: no matching function for call to ‘f(S<int>)’
f (S<int> ()); // { dg-message "required" }
^
access7.C:17:15: note: candidate is:
access7.C:12:16: note: template<class A> typename A::T* f(A)
typename A::T* f (A) { // { dg-error "this context" }
^

I suppose this is expected, right?!? (we may have more in old-deja, have 
to re-check)

The second pair is more subtle:

FAIL: g++.dg/template/friend13.C -std=c++11 (test for excess errors)
FAIL: g++.dg/template/friend15.C -std=c++98 (test for excess errors)
FAIL: g++.dg/template/friend15.C -std=c++11 (test for excess errors)

That is, we have that the first one fails only in c++11 mode, rather 
subtle per se. And in general friend* cases seem quite unexpected to me.

Now, something rather interesting is that, clang 3.0, which I tried 
online, rejects friend13 and friend15 as patched GCC does, thus 
disagreeing with current mainline.

For example, for friend13.C, it emits an access control error for struct 
Inner in the context of line 8, like patched GCC. And, for friend15.C, 
an error @ line 18, for undeclared 'foo', whereas patched GCC gives "no 
matching function for call to ‘foo()’" for the same line.

Thanks for any help!
Paolo.

/////////////////////////



[-- Attachment #2: patch_51213_2 --]
[-- Type: text/plain, Size: 33724 bytes --]

Index: libstdc++-v3/testsuite/20_util/pair/noncopyable.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/pair/noncopyable.cc	(revision 0)
+++ libstdc++-v3/testsuite/20_util/pair/noncopyable.cc	(revision 0)
@@ -0,0 +1,39 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+
+// PR c++/51213
+class Uncopyable
+{
+  Uncopyable(const Uncopyable&);
+ public:
+  Uncopyable() = default;
+};
+
+struct ContainsUncopyable
+{
+  std::pair<Uncopyable, int> pv;
+};
+
+void foo()
+{
+  ContainsUncopyable c;
+}
Index: gcc/testsuite/g++.dg/cpp0x/sfinae37.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/sfinae37.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/sfinae37.C	(revision 0)
@@ -0,0 +1,22 @@
+// PR c++/51213
+// { dg-options -std=c++11 }
+
+class C {
+  typedef int type;
+};
+
+template<class T, class = typename T::type>
+auto f(int) -> char;
+
+template<class>
+auto f(...) -> char (&)[2];
+
+static_assert(sizeof(f<C>(0)) == 2, "Ouch");
+
+template<class T>
+auto g(int) -> decltype(typename T::type(), char());
+
+template<class>
+auto g(...) -> char (&)[2];
+
+static_assert(sizeof(g<C>(0)) == 2, "Ouch");
Index: gcc/testsuite/g++.dg/template/sfinae10.C
===================================================================
--- gcc/testsuite/g++.dg/template/sfinae10.C	(revision 188652)
+++ gcc/testsuite/g++.dg/template/sfinae10.C	(working copy)
@@ -81,19 +81,19 @@ struct Y { };
 
 struct Z {
 private:
-  Z operator+(); // { dg-error "is private" }
-  Z operator-(); // { dg-error "is private" }
-  int operator*(); // { dg-error "is private" }
-  Z operator~(); // { dg-error "is private" } 
-  bool operator!(); // { dg-error "is private" }  
-  Z& operator++(); // { dg-error "is private" }  
-  Z& operator--(); // { dg-error "is private" }  
-  Z& operator++(int); // { dg-error "is private" }  
-  Z& operator--(int); // { dg-error "is private" }  
+  Z operator+();
+  Z operator-();
+  int operator*();
+  Z operator~();
+  bool operator!();
+  Z& operator++();
+  Z& operator--();
+  Z& operator++(int);
+  Z& operator--(int);
 };
 
 // has_unary_plus
-DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +);
 STATIC_ASSERT((has_unary_plus<int>::value));
 STATIC_ASSERT((!has_unary_plus<int X::*>::value));
 STATIC_ASSERT((has_unary_plus<W>::value));
@@ -101,7 +101,7 @@ STATIC_ASSERT((has_unary_plus<X>::value));
 STATIC_ASSERT((!has_unary_plus<Y>::value));
 
 // is_negatable
-DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -);
 STATIC_ASSERT((is_negatable<int>::value));
 STATIC_ASSERT((!is_negatable<int X::*>::value));
 STATIC_ASSERT((is_negatable<W>::value));
@@ -109,7 +109,7 @@ STATIC_ASSERT((is_negatable<X>::value));
 STATIC_ASSERT((!is_negatable<Y>::value));
 
 // is_dereferenceable
-DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *);
 STATIC_ASSERT((!is_dereferenceable<int>::value));
 STATIC_ASSERT((is_dereferenceable<int*>::value));
 STATIC_ASSERT((is_dereferenceable<W>::value));
@@ -117,7 +117,7 @@ STATIC_ASSERT((is_dereferenceable<X>::value));
 STATIC_ASSERT((!is_dereferenceable<Y>::value));
 
 // has_bitwise_not
-DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~);
 STATIC_ASSERT((has_bitwise_not<int>::value));
 STATIC_ASSERT((!has_bitwise_not<int*>::value));
 STATIC_ASSERT((has_bitwise_not<W>::value));
@@ -125,7 +125,7 @@ STATIC_ASSERT((has_bitwise_not<X>::value));
 STATIC_ASSERT((!has_bitwise_not<Y>::value));
 
 // has_truth_not
-DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !);
 STATIC_ASSERT((has_truth_not<int>::value));
 STATIC_ASSERT((has_truth_not<int*>::value));
 STATIC_ASSERT((has_truth_not<W>::value));
@@ -133,7 +133,7 @@ STATIC_ASSERT((has_truth_not<X>::value));
 STATIC_ASSERT((!has_truth_not<Y>::value));
 
 // has_preincrement
-DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++);
 STATIC_ASSERT((has_preincrement<int>::value));
 STATIC_ASSERT((has_preincrement<int*>::value));
 STATIC_ASSERT((!has_preincrement<int X::*>::value));
@@ -142,7 +142,7 @@ STATIC_ASSERT((has_preincrement<X>::value));
 STATIC_ASSERT((!has_preincrement<Y>::value));
 
 // has_predecrement
-DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --);
 STATIC_ASSERT((has_predecrement<int>::value));
 STATIC_ASSERT((has_predecrement<int*>::value));
 STATIC_ASSERT((!has_predecrement<int X::*>::value));
@@ -151,7 +151,7 @@ STATIC_ASSERT((has_predecrement<X>::value));
 STATIC_ASSERT((!has_predecrement<Y>::value));
 
 // has_postincrement
-DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++); // { dg-error "within this context" }
+DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++);
 STATIC_ASSERT((has_postincrement<int>::value));
 STATIC_ASSERT((has_postincrement<int*>::value));
 STATIC_ASSERT((!has_postincrement<int X::*>::value));
@@ -160,7 +160,7 @@ STATIC_ASSERT((has_postincrement<X>::value));
 STATIC_ASSERT((!has_postincrement<Y>::value));
 
 // has_postdecrement
-DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --); // { dg-error "within this context" }
+DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --);
 STATIC_ASSERT((has_postdecrement<int>::value));
 STATIC_ASSERT((has_postdecrement<int*>::value));
 STATIC_ASSERT((!has_postdecrement<int X::*>::value));
@@ -169,13 +169,12 @@ STATIC_ASSERT((has_postdecrement<X>::value));
 STATIC_ASSERT((!has_postdecrement<Y>::value));
 
 // Check for private members
-STATIC_ASSERT((has_unary_plus<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((is_negatable<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((is_dereferenceable<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_bitwise_not<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_truth_not<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_preincrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_predecrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_postincrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_postdecrement<Z>::value)); // { dg-message "required from here" }
-
+STATIC_ASSERT((!has_unary_plus<Z>::value));
+STATIC_ASSERT((!is_negatable<Z>::value));
+STATIC_ASSERT((!is_dereferenceable<Z>::value));
+STATIC_ASSERT((!has_bitwise_not<Z>::value));
+STATIC_ASSERT((!has_truth_not<Z>::value)); 
+STATIC_ASSERT((!has_preincrement<Z>::value));
+STATIC_ASSERT((!has_predecrement<Z>::value));
+STATIC_ASSERT((!has_postincrement<Z>::value));
+STATIC_ASSERT((!has_postdecrement<Z>::value));
Index: gcc/testsuite/g++.dg/template/sfinae6_neg.C
===================================================================
--- gcc/testsuite/g++.dg/template/sfinae6_neg.C	(revision 188652)
+++ gcc/testsuite/g++.dg/template/sfinae6_neg.C	(working copy)
@@ -14,14 +14,14 @@ template<typename T> struct enable_if<false, T> {
 template<typename F, typename T1, typename T2>
   typename enable_if<sizeof(create_a<F>()(create_a<T1>(), create_a<T2>()), 1),
 		     yes_type>::type
-  check_is_callable2(type<F>, type<T1>, type<T2>); // { dg-error "within this context" "" { target c++11 } }
+  check_is_callable2(type<F>, type<T1>, type<T2>);
 
 no_type check_is_callable2(...);
 
 template<typename F, typename T1, typename T2 = T1>
 struct is_callable2
 {
-  static const bool value = // { dg-error "within this context" }
+  static const bool value =
     (sizeof(check_is_callable2(type<F>(), type<T1>(), type<T2>()))
      == sizeof(yes_type));
 };
@@ -52,7 +52,7 @@ struct F {
   void operator()(A, A);
 
 private:
-  void operator()(B, B); // { dg-error "is private" }
+  void operator()(B, B);
 };
 
-STATIC_ASSERT((is_callable2<F, B, B>::value));
+STATIC_ASSERT((!is_callable2<F, B, B>::value));
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 188652)
+++ gcc/cp/init.c	(working copy)
@@ -1876,9 +1876,9 @@ build_offset_ref (tree type, tree member, bool add
 	       (or any class derived from that class).  */
 	  if (address_p && DECL_P (t)
 	      && DECL_NONSTATIC_MEMBER_P (t))
-	    perform_or_defer_access_check (TYPE_BINFO (type), t, t);
+	    perform_or_defer_access_check (TYPE_BINFO (type), t, t, true);
 	  else
-	    perform_or_defer_access_check (basebinfo, t, t);
+	    perform_or_defer_access_check (basebinfo, t, t, true);
 
 	  if (DECL_STATIC_FUNCTION_P (t))
 	    return t;
@@ -1891,7 +1891,7 @@ build_offset_ref (tree type, tree member, bool add
     /* We need additional test besides the one in
        check_accessibility_of_qualified_id in case it is
        a pointer to non-static member.  */
-    perform_or_defer_access_check (TYPE_BINFO (type), member, member);
+    perform_or_defer_access_check (TYPE_BINFO (type), member, member, true);
 
   if (!address_p)
     {
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 188652)
+++ gcc/cp/class.c	(working copy)
@@ -1190,7 +1190,7 @@ alter_access (tree t, tree fdecl, tree access)
     }
   else
     {
-      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl);
+      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl, true);
       DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
       return 1;
     }
@@ -7135,7 +7135,7 @@ resolve_address_of_overloaded_function (tree targe
       && DECL_FUNCTION_MEMBER_P (fn))
     {
       gcc_assert (access_path);
-      perform_or_defer_access_check (access_path, fn, fn);
+      perform_or_defer_access_check (access_path, fn, fn, true);
     }
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 188652)
+++ gcc/cp/decl.c	(working copy)
@@ -3305,10 +3305,11 @@ make_typename_type (tree context, tree name, enum
 	       context, name, t);
       return error_mark_node;
     }
-  
-  if (complain & tf_error)
-    perform_or_defer_access_check (TYPE_BINFO (context), t, t);
 
+  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t,
+				      complain & tf_error))
+    return error_mark_node;
+
   /* If we are currently parsing a template and if T is a typedef accessed
      through CONTEXT then we need to remember and check access of T at
      template instantiation time.  */
@@ -3377,8 +3378,9 @@ make_unbound_class_template (tree context, tree na
 	  return error_mark_node;
 	}
 
-      if (complain & tf_error)
-	perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl);
+      if (!perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl,
+					  complain & tf_error))
+	return error_mark_node;
 
       return tmpl;
     }
@@ -6646,7 +6648,8 @@ register_dtor_fn (tree decl)
       gcc_assert (idx >= 0);
       cleanup = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
       /* Make sure it is accessible.  */
-      perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup);
+      perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup,
+				     true);
     }
   else
     {
@@ -10568,7 +10571,7 @@ local_variable_p_walkfn (tree *tp, int *walk_subtr
    DECL, if there is no DECL available.  */
 
 tree
-check_default_argument (tree decl, tree arg)
+check_default_argument (tree decl, tree arg, tsubst_flags_t complain)
 {
   tree var;
   tree decl_type;
@@ -10601,15 +10604,15 @@ tree
      parameter type.  */
   if (!TREE_TYPE (arg)
       || !can_convert_arg (decl_type, TREE_TYPE (arg), arg, LOOKUP_NORMAL,
-			   tf_warning_or_error))
+			   complain))
     {
-      if (decl)
-	error ("default argument for %q#D has type %qT",
-	       decl, TREE_TYPE (arg));
-      else
-	error ("default argument for parameter of type %qT has type %qT",
-	       decl_type, TREE_TYPE (arg));
-
+      if (complain & tf_error)
+	if (decl)
+	  error ("default argument for %q#D has type %qT",
+		 decl, TREE_TYPE (arg));
+	else
+	  error ("default argument for parameter of type %qT has type %qT",
+		 decl_type, TREE_TYPE (arg));
       return error_mark_node;
     }
 
@@ -10619,8 +10622,9 @@ tree
       && null_ptr_cst_p (arg)
       && !NULLPTR_TYPE_P (TREE_TYPE (arg)))
     {
-      warning (OPT_Wzero_as_null_pointer_constant,
-	       "zero as null pointer constant");
+      if (complain & tf_warning)
+	warning (OPT_Wzero_as_null_pointer_constant,
+		 "zero as null pointer constant");
       return nullptr_node;
     }
 
@@ -10634,10 +10638,11 @@ tree
   var = cp_walk_tree_without_duplicates (&arg, local_variable_p_walkfn, NULL);
   if (var)
     {
-      if (DECL_NAME (var) == this_identifier)
-	permerror (input_location, "default argument %qE uses %qD", arg, var);
-      else
-	error ("default argument %qE uses local variable %qD", arg, var);
+      if (complain & tf_error)
+	if (DECL_NAME (var) == this_identifier)
+	  permerror (input_location, "default argument %qE uses %qD", arg, var);
+	else
+	  error ("default argument %qE uses local variable %qD", arg, var);
       return error_mark_node;
     }
 
@@ -10788,7 +10793,7 @@ grokparms (tree parmlist, tree *parms)
 	  if (any_error)
 	    init = NULL_TREE;
 	  else if (init && !processing_template_decl)
-	    init = check_default_argument (decl, init);
+	    init = check_default_argument (decl, init, tf_warning_or_error);
 	}
 
       DECL_CHAIN (decl) = decls;
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 188652)
+++ gcc/cp/pt.c	(working copy)
@@ -183,7 +183,7 @@ static int coerce_template_template_parms (tree, t
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
 static int template_args_equal (tree, tree);
-static void tsubst_default_arguments (tree);
+static void tsubst_default_arguments (tree, tsubst_flags_t);
 static tree for_each_template_parm_r (tree *, int *, void *);
 static tree copy_default_args_to_explicit_spec_1 (tree, tree);
 static void copy_default_args_to_explicit_spec (tree);
@@ -195,7 +195,7 @@ static tree tsubst_expr	(tree, tree, tsubst_flags_
 static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t);
-static void perform_typedefs_access_check (tree tmpl, tree targs);
+static bool perform_typedefs_access_check (tree, tree, bool);
 static void append_type_to_template_for_access_check_1 (tree, tree, tree,
 							location_t);
 static tree listify (tree);
@@ -8652,17 +8652,18 @@ apply_late_template_attributes (tree *decl_p, tree
    TMPL is the template to consider and TARGS is the list of arguments of
    that template.  */
 
-static void
-perform_typedefs_access_check (tree tmpl, tree targs)
+static bool
+perform_typedefs_access_check (tree tmpl, tree targs, bool complain)
 {
   location_t saved_location;
   int i;
   qualified_typedef_usage_t *iter;
+  bool ret = true;
 
   if (!tmpl
       || (!CLASS_TYPE_P (tmpl)
 	  && TREE_CODE (tmpl) != FUNCTION_DECL))
-    return;
+    return true;
 
   saved_location = input_location;
   FOR_EACH_VEC_ELT (qualified_typedef_usage_t,
@@ -8683,10 +8684,12 @@ apply_late_template_attributes (tree *decl_p, tree
       /* Make access check error messages point to the location
          of the use of the typedef.  */
       input_location = iter->locus;
-      perform_or_defer_access_check (TYPE_BINFO (type_scope),
-				     type_decl, type_decl);
+      ret &= perform_or_defer_access_check (TYPE_BINFO (type_scope),
+					    type_decl, type_decl, complain);
     }
-    input_location = saved_location;
+
+  input_location = saved_location;
+  return ret;
 }
 
 static tree
@@ -9190,8 +9193,8 @@ instantiate_class_template_1 (tree type)
      checked at template instantiation time, i.e now. These types were
      added to the template at parsing time. Let's get those and perform
      the access checks then.  */
-  perform_typedefs_access_check (pattern, args);
-  perform_deferred_access_checks ();
+  perform_typedefs_access_check (pattern, args, true);
+  perform_deferred_access_checks (true);
   pop_nested_class ();
   maximum_field_alignment = saved_maximum_field_alignment;
   if (!fn_context)
@@ -9910,7 +9913,8 @@ tsubst_aggr_type (tree t,
    FN), which has the indicated TYPE.  */
 
 tree
-tsubst_default_argument (tree fn, tree type, tree arg)
+tsubst_default_argument (tree fn, tree type, tree arg,
+			 tsubst_flags_t complain)
 {
   tree saved_class_ptr = NULL_TREE;
   tree saved_class_ref = NULL_TREE;
@@ -9949,7 +9953,7 @@ tree
      stack.  */
   ++function_depth;
   arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
-		     tf_warning_or_error, NULL_TREE,
+		     complain, NULL_TREE,
 		     /*integral_constant_expression_p=*/false);
   --function_depth;
   pop_deferring_access_checks();
@@ -9962,7 +9966,7 @@ tree
     }
 
   /* Make sure the default argument is reasonable.  */
-  arg = check_default_argument (type, arg);
+  arg = check_default_argument (type, arg, complain);
 
   pop_access_scope (fn);
 
@@ -9972,7 +9976,7 @@ tree
 /* Substitute into all the default arguments for FN.  */
 
 static void
-tsubst_default_arguments (tree fn)
+tsubst_default_arguments (tree fn, tsubst_flags_t complain)
 {
   tree arg;
   tree tmpl_args;
@@ -9993,7 +9997,8 @@ static void
     if (TREE_PURPOSE (arg))
       TREE_PURPOSE (arg) = tsubst_default_argument (fn,
 						    TREE_VALUE (arg),
-						    TREE_PURPOSE (arg));
+						    TREE_PURPOSE (arg),
+						    complain);
 }
 
 /* Substitute the ARGS into the T, which is a _DECL.  Return the
@@ -10335,7 +10340,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t com
 	    if (!member
 		&& !PRIMARY_TEMPLATE_P (gen_tmpl)
 		&& !uses_template_parms (argvec))
-	      tsubst_default_arguments (r);
+	      tsubst_default_arguments (r, complain);
 	  }
 	else
 	  DECL_TEMPLATE_INFO (r) = NULL_TREE;
@@ -14639,6 +14644,7 @@ instantiate_template_1 (tree tmpl, tree orig_args,
   tree fndecl;
   tree gen_tmpl;
   tree spec;
+  tree tmp = NULL_TREE;
 
   if (tmpl == error_mark_node)
     return error_mark_node;
@@ -14726,8 +14732,11 @@ instantiate_template_1 (tree tmpl, tree orig_args,
      checked at template instantiation time, i.e now. These types were
      added to the template at parsing time. Let's get those and perfom
      the acces checks then.  */
-  perform_typedefs_access_check (DECL_TEMPLATE_RESULT (tmpl), targ_ptr);
-  perform_deferred_access_checks ();
+  if (!perform_typedefs_access_check (DECL_TEMPLATE_RESULT (tmpl), targ_ptr,
+				      complain & tf_error))
+    tmp = error_mark_node;
+  if (!perform_deferred_access_checks (complain & tf_error))
+    tmp = error_mark_node;
   pop_access_scope (fndecl);
   pop_deferring_access_checks ();
 
@@ -14742,7 +14751,7 @@ instantiate_template_1 (tree tmpl, tree orig_args,
   if (DECL_CHAIN (gen_tmpl) && DECL_CLONED_FUNCTION_P (DECL_CHAIN (gen_tmpl)))
     clone_function_decl (fndecl, /*update_method_vec_p=*/0);
 
-  return fndecl;
+  return tmp ? error_mark_node : fndecl;
 }
 
 /* Wrapper for instantiate_template_1.  */
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 188652)
+++ gcc/cp/semantics.c	(working copy)
@@ -223,7 +223,7 @@ pop_to_parent_deferring_access_checks (void)
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
 	{
 	  /* Check access.  */
-	  perform_access_checks (checks);
+	  perform_access_checks (checks, true);
 	}
       else
 	{
@@ -254,17 +254,22 @@ pop_to_parent_deferring_access_checks (void)
    is the BINFO indicating the qualifying scope used to access the
    DECL node stored in the TREE_VALUE of the node.  */
 
-void
-perform_access_checks (VEC (deferred_access_check,gc)* checks)
+bool
+perform_access_checks (VEC (deferred_access_check,gc)* checks,
+		       bool complain)
 {
   int i;
   deferred_access_check *chk;
+  bool tmp = true;
 
   if (!checks)
-    return;
+    return true;
 
   FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
-    enforce_access (chk->binfo, chk->decl, chk->diag_decl);
+    tmp &= enforce_access (chk->binfo, chk->decl, chk->diag_decl,
+			   complain);
+
+  return complain ? true : tmp;
 }
 
 /* Perform the deferred access checks.
@@ -283,28 +288,28 @@ pop_to_parent_deferring_access_checks (void)
    We have to perform deferred access of `A::X', first with `A::a',
    next with `x'.  */
 
-void
-perform_deferred_access_checks (void)
+bool
+perform_deferred_access_checks (bool complain)
 {
-  perform_access_checks (get_deferred_access_checks ());
+  return perform_access_checks (get_deferred_access_checks (), complain);
 }
 
 /* Defer checking the accessibility of DECL, when looked up in
    BINFO. DIAG_DECL is the declaration to use to print diagnostics.  */
 
-void
-perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
+bool
+perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
+			       bool complain)
 {
   int i;
   deferred_access *ptr;
   deferred_access_check *chk;
   deferred_access_check *new_access;
 
-
   /* Exit if we are in a context that no access checking is performed.
      */
   if (deferred_access_no_check)
-    return;
+    return true;
 
   gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
 
@@ -313,8 +318,8 @@ pop_to_parent_deferring_access_checks (void)
   /* If we are not supposed to defer access checks, just check now.  */
   if (ptr->deferring_access_checks_kind == dk_no_deferred)
     {
-      enforce_access (binfo, decl, diag_decl);
-      return;
+      bool tmp = enforce_access (binfo, decl, diag_decl, complain);
+      return complain ? true : tmp;
     }
 
   /* See if we are already going to perform this check.  */
@@ -324,7 +329,7 @@ pop_to_parent_deferring_access_checks (void)
       if (chk->decl == decl && chk->binfo == binfo &&
 	  chk->diag_decl == diag_decl)
 	{
-	  return;
+	  return true;
 	}
     }
   /* If not, record the check.  */
@@ -334,6 +339,8 @@ pop_to_parent_deferring_access_checks (void)
   new_access->binfo = binfo;
   new_access->decl = decl;
   new_access->diag_decl = diag_decl;
+
+  return true;
 }
 
 /* Used by build_over_call in LOOKUP_SPECULATIVE mode: return whether DECL
@@ -353,7 +360,7 @@ speculative_access_check (tree binfo, tree decl, t
     {
       /* Unless we're under maybe_explain_implicit_delete.  */
       if (complain)
-	enforce_access (binfo, decl, diag_decl);
+	enforce_access (binfo, decl, diag_decl, true);
       return false;
     }
 
@@ -1601,7 +1608,7 @@ finish_non_static_data_member (tree decl, tree obj
       tree access_type = TREE_TYPE (object);
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
-				     decl);
+				     decl, true);
 
       /* If the data member was named `C::M', convert `*this' to `C'
 	 first.  */
@@ -1723,7 +1730,7 @@ check_accessibility_of_qualified_id (tree decl,
       && CLASS_TYPE_P (qualifying_type)
       && !dependent_type_p (qualifying_type))
     perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
-				   decl);
+				   decl, true);
 }
 
 /* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
@@ -3331,7 +3338,7 @@ finish_id_expression (tree id_expression,
 		{
 		  tree path = currently_open_derived_class (context);
 		  perform_or_defer_access_check (TYPE_BINFO (path),
-						 decl, decl);
+						 decl, decl, true);
 		}
 	    }
 
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 188652)
+++ gcc/cp/parser.c	(working copy)
@@ -10472,7 +10472,7 @@ cp_parser_simple_declaration (cp_parser* parser,
       if (cp_parser_declares_only_class_p (parser))
 	shadow_tag (&decl_specifiers);
       /* Perform any deferred access checks.  */
-      perform_deferred_access_checks ();
+      perform_deferred_access_checks (true);
     }
 
   /* Consume the `;'.  */
@@ -12373,7 +12373,7 @@ cp_parser_template_id (cp_parser *parser,
 	  FOR_EACH_VEC_ELT (deferred_access_check, access_check, i, chk)
 	    perform_or_defer_access_check (chk->binfo,
 					   chk->decl,
-					   chk->diag_decl);
+					   chk->diag_decl, true);
 	}
       /* Return the stored value.  */
       return check_value->value;
@@ -15700,7 +15700,7 @@ cp_parser_init_declarator (cp_parser* parser,
 
       /* Perform the access control checks for the declarator and the
 	 decl-specifiers.  */
-      perform_deferred_access_checks ();
+      perform_deferred_access_checks (true);
 
       /* Restore the saved value.  */
       if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -20962,7 +20962,7 @@ cp_parser_function_definition_from_specifiers_and_
      did not check, check them now.  We must wait until we are in the
      scope of the function to perform the checks, since the function
      might be a friend.  */
-  perform_deferred_access_checks ();
+  perform_deferred_access_checks (true);
 
   if (!success_p)
     {
@@ -21257,7 +21257,7 @@ static void
 cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
 {
   ++processing_template_parmlist;
-  perform_access_checks (checks);
+  perform_access_checks (checks, true);
   --processing_template_parmlist;
 }
 
@@ -21784,7 +21784,8 @@ cp_parser_late_parse_one_default_arg (cp_parser *p
       /* In a non-template class, check conversions now.  In a template,
 	 we'll wait and instantiate these as needed.  */
       if (TREE_CODE (decl) == PARM_DECL)
-	parsed_arg = check_default_argument (parmtype, parsed_arg);
+	parsed_arg = check_default_argument (parmtype, parsed_arg,
+					     tf_warning_or_error);
       else
 	{
 	  int flags = LOOKUP_IMPLICIT;
@@ -22706,7 +22707,7 @@ cp_parser_pre_parsed_nested_name_specifier (cp_par
       FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
 	perform_or_defer_access_check (chk->binfo,
 				       chk->decl,
-				       chk->diag_decl);
+				       chk->diag_decl, true);
     }
   /* Set the scope from the stored value.  */
   parser->scope = check_value->value;
@@ -23964,7 +23965,7 @@ cp_parser_objc_method_definition_list (cp_parser*
 	  if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS 
 		|| ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
 	    {
-	      perform_deferred_access_checks ();
+	      perform_deferred_access_checks (true);
 	      stop_deferring_access_checks ();
 	      meth = cp_parser_function_definition_after_declarator (parser,
 								     false);
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 188652)
+++ gcc/cp/call.c	(working copy)
@@ -5503,7 +5503,7 @@ build_op_delete_call (enum tree_code code, tree ad
       /* If the FN is a member function, make sure that it is
 	 accessible.  */
       if (BASELINK_P (fns))
-	perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn);
+	perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn, true);
 
       /* Core issue 901: It's ok to new a type with deleted delete.  */
       if (DECL_DELETED_FN (fn) && alloc_fn)
@@ -5561,19 +5561,23 @@ build_op_delete_call (enum tree_code code, tree ad
    the declaration to use in the error diagnostic.  */
 
 bool
-enforce_access (tree basetype_path, tree decl, tree diag_decl)
+enforce_access (tree basetype_path, tree decl, tree diag_decl,
+		bool complain)
 {
   gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
 
   if (!accessible_p (basetype_path, decl, true))
     {
-      if (TREE_PRIVATE (decl))
-	error ("%q+#D is private", diag_decl);
-      else if (TREE_PROTECTED (decl))
-	error ("%q+#D is protected", diag_decl);
-      else
-	error ("%q+#D is inaccessible", diag_decl);
-      error ("within this context");
+      if (complain)
+	{
+	  if (TREE_PRIVATE (decl))
+	    error ("%q+#D is private", diag_decl);
+	  else if (TREE_PROTECTED (decl))
+	    error ("%q+#D is protected", diag_decl);
+	  else
+	    error ("%q+#D is inaccessible", diag_decl);
+	  error ("within this context");
+	}
       return false;
     }
 
@@ -6255,7 +6259,7 @@ convert_default_arg (tree type, tree arg, tree fn,
   push_defarg_context (fn);
 
   if (fn && DECL_TEMPLATE_INFO (fn))
-    arg = tsubst_default_argument (fn, type, arg);
+    arg = tsubst_default_argument (fn, type, arg, complain);
 
   /* Due to:
 
@@ -6504,8 +6508,9 @@ build_over_call (struct z_candidate *cand, int fla
 					 complain & tf_error))
 	    return error_mark_node;
 	}
-      else
-	perform_or_defer_access_check (cand->access_path, access_fn, fn);
+      else if (!perform_or_defer_access_check (cand->access_path, access_fn,
+					       fn, complain & tf_error))
+	return error_mark_node;
     }
 
   /* If we're checking for implicit delete, don't bother with argument
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 188652)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4899,7 +4899,7 @@ extern bool can_convert_arg			(tree, tree, tree, i
 						 tsubst_flags_t);
 extern bool can_convert_arg_bad			(tree, tree, tree, int,
 						 tsubst_flags_t);
-extern bool enforce_access			(tree, tree, tree);
+extern bool enforce_access			(tree, tree, tree, bool);
 extern void push_defarg_context			(tree);
 extern void pop_defarg_context			(void);
 extern tree convert_default_arg			(tree, tree, tree, int,
@@ -5095,7 +5095,7 @@ extern tree static_fn_type			(tree);
 extern void revert_static_member_fn		(tree);
 extern void fixup_anonymous_aggr		(tree);
 extern tree compute_array_index_type		(tree, tree, tsubst_flags_t);
-extern tree check_default_argument		(tree, tree);
+extern tree check_default_argument		(tree, tree, tsubst_flags_t);
 typedef int (*walk_namespaces_fn)		(tree, void *);
 extern int walk_namespaces			(walk_namespaces_fn,
 						 void *);
@@ -5362,7 +5362,8 @@ extern tree maybe_process_partial_specialization (
 extern tree most_specialized_instantiation	(tree);
 extern void print_candidates			(tree);
 extern void instantiate_pending_templates	(int);
-extern tree tsubst_default_argument		(tree, tree, tree);
+extern tree tsubst_default_argument		(tree, tree, tree,
+						 tsubst_flags_t);
 extern tree tsubst (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_copy_and_build		(tree, tree, tsubst_flags_t,
 						 tree, bool, bool);
@@ -5493,9 +5494,9 @@ extern void stop_deferring_access_checks	(void);
 extern void pop_deferring_access_checks		(void);
 extern VEC (deferred_access_check,gc)* get_deferred_access_checks		(void);
 extern void pop_to_parent_deferring_access_checks (void);
-extern void perform_access_checks		(VEC (deferred_access_check,gc)*);
-extern void perform_deferred_access_checks	(void);
-extern void perform_or_defer_access_check	(tree, tree, tree);
+extern bool perform_access_checks (VEC (deferred_access_check,gc)*, bool);
+extern bool perform_deferred_access_checks	(bool);
+extern bool perform_or_defer_access_check	(tree, tree, tree, bool);
 extern bool speculative_access_check		(tree, tree, tree, bool);
 extern int stmts_are_full_exprs_p		(void);
 extern void init_cp_semantics			(void);
Index: gcc/cp/search.c
===================================================================
--- gcc/cp/search.c	(revision 188652)
+++ gcc/cp/search.c	(working copy)
@@ -1255,8 +1255,10 @@ lookup_member (tree xbasetype, tree name, int prot
       && !really_overloaded_fn (rval))
     {
       tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval;
-      if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
-	perform_or_defer_access_check (basetype_path, decl, decl);
+      if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
+	  && !perform_or_defer_access_check (basetype_path, decl, decl,
+					     complain & tf_error))
+	rval = error_mark_node;
     }
 
   if (errstr && protect)
Index: gcc/cp/friend.c
===================================================================
--- gcc/cp/friend.c	(revision 188652)
+++ gcc/cp/friend.c	(working copy)
@@ -166,7 +166,7 @@ add_friend (tree type, tree decl, bool complain)
 
   ctx = DECL_CONTEXT (decl);
   if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
-    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl);
+    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl, true);
 
   maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
 

             reply	other threads:[~2012-06-15 14:29 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-15 14:57 Paolo Carlini [this message]
2012-06-28 10:38 ` Paolo Carlini
2012-07-02 19:48 ` Jason Merrill
2012-07-09 16:05   ` Jason Merrill
2012-07-12 15:26 ` Jason Merrill
2012-07-12 23:54 ` Jason Merrill
2012-07-12 23:06   ` Jason Merrill
2012-07-19  1:36     ` Jason Merrill
2012-07-19  9:45       ` Paolo Carlini
2012-07-14  9:57   ` Paolo Carlini
2012-07-16 18:53     ` Jason Merrill
2012-07-17 12:46       ` Paolo Carlini
2012-07-17 14:11         ` Jason Merrill
2012-07-17 16:14           ` Paolo Carlini
2012-07-18  1:20             ` Paolo Carlini
2012-07-18  2:47               ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4FDB4640.3050502@oracle.com \
    --to=paolo.carlini@oracle.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).