re PR c/66516 (missing diagnostic on taking the address of a builtin function)
authorMartin Sebor <msebor@redhat.com>
Thu, 3 Sep 2015 16:23:11 +0000 (16:23 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 3 Sep 2015 16:23:11 +0000 (10:23 -0600)
gcc/ChangeLog
2015-09-03  Martin Sebor  <msebor@redhat.com>

PR c/66516
* doc/extend.texi (Other Builtins): Document when the address
of a built-in function can be taken.

gcc/c-family/ChangeLog
2015-09-03  Martin Sebor  <msebor@redhat.com>

PR c/66516
* c-common.h (c_decl_implicit, reject_gcc_builtin): Declare new
functions.
* c-common.c (reject_gcc_builtin): Define.

gcc/c/ChangeLog
2015-09-03  Martin Sebor  <msebor@redhat.com>

PR c/66516
* c/c-typeck.c (convert_arguments, parser_build_unary_op)
(build_conditional_expr, c_cast_expr, convert_for_assignment)
(build_binary_op, _objc_common_truthvalue_conversion): Call
reject_gcc_builtin.
(c_decl_implicit): Define.

gcc/cp/ChangeLog
2015-09-03  Martin Sebor  <msebor@redhat.com>

PR c/66516
* cp/cp-tree.h (mark_rvalue_use, decay_conversion): Add new
argument(s).
* cp/expr.c (mark_rvalue_use): Use new argument.
* cp/call.c (build_addr_func): Call decay_conversion with new
argument.
* cp/pt.c (convert_template_argument): Call reject_gcc_builtin.
* cp/typeck.c (decay_conversion): Use new argument.
(c_decl_implicit): Define.

gcc/testsuite/ChangeLog
2015-09-03  Martin Sebor  <msebor@redhat.com>

PR c/66516
* g++.dg/addr_builtin-1.C: New test.
* gcc.dg/addr_builtin-1.c: New test.

From-SVN: r227458

15 files changed:
gcc/ChangeLog
gcc/builtins.c.orig [new file with mode: 0644]
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/expr.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog

index 3a04aaf9506cc3b83042429f329ea086af4ef50b..42010ed418ef1ba51a637cffd617b33373dba386 100644 (file)
@@ -1,3 +1,9 @@
+2015-09-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c/66516
+       * doc/extend.texi (Other Builtins): Document when the address
+       of a built-in function can be taken.
+
 2015-09-03  Richard Biener  <rguenther@suse.de>
 
        * dwarf2out.c (flush_limbo_die_list): Split out from ...
diff --git a/gcc/builtins.c.orig b/gcc/builtins.c.orig
new file mode 100644 (file)
index 0000000..e69de29
index 09b425f2b053f96c5b004bd9d7bc10cbafe21581..964f6dda7623e0b991bf7c9ce415afd5cb0f4da0 100644 (file)
@@ -1,3 +1,10 @@
+2015-09-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c/66516
+       * c-common.h (c_decl_implicit, reject_gcc_builtin): Declare new
+       functions.
+       * c-common.c (reject_gcc_builtin): Define.
+
 2015-09-02  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
        PR middle-end/60586
index 7691035c7f840ad01d5bb2e3a60a5ff4403c978a..9758b9e07e819588675a935e99ca45dd5b9827f7 100644 (file)
@@ -12882,4 +12882,41 @@ pointer_to_zero_sized_aggr_p (tree t)
   return (TYPE_SIZE (t) && integer_zerop (TYPE_SIZE (t)));
 }
 
+/* For an EXPR of a FUNCTION_TYPE that references a GCC built-in function
+   with no library fallback or for an ADDR_EXPR whose operand is such type
+   issues an error pointing to the location LOC.
+   Returns true when the expression has been diagnosed and false
+   otherwise.  */
+bool
+reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */)
+{
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+
+  if (TREE_TYPE (expr)
+      && TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+      && DECL_P (expr)
+      /* The intersection of DECL_BUILT_IN and DECL_IS_BUILTIN avoids
+        false positives for user-declared built-ins such as abs or
+        strlen, and for C++ operators new and delete.
+        The c_decl_implicit() test avoids false positives for implicitly
+        declared built-ins with library fallbacks (such as abs).  */
+      && DECL_BUILT_IN (expr)
+      && DECL_IS_BUILTIN (expr)
+      && !c_decl_implicit (expr)
+      && !DECL_ASSEMBLER_NAME_SET_P (expr))
+    {
+      if (loc == UNKNOWN_LOCATION)
+       loc = EXPR_LOC_OR_LOC (expr, input_location);
+
+      /* Reject arguments that are built-in functions with
+        no library fallback.  */
+      error_at (loc, "built-in function %qE must be directly called", expr);
+
+      return true;
+    }
+
+  return false;
+}
+
 #include "gt-c-family-c-common.h"
index d24dfdab35efac48bc3032847a67ae4ee639f3d2..74d1bc149e3b2cfc7b0b34ec1ea0e4da7b78417e 100644 (file)
@@ -572,6 +572,7 @@ extern int field_decl_cmp (const void *, const void *);
 extern void resort_sorted_fields (void *, void *, gt_pointer_operator,
                                  void *);
 extern bool has_c_linkage (const_tree decl);
+extern bool c_decl_implicit (const_tree);
 \f
 /* Switches common to the C front ends.  */
 
@@ -1439,5 +1440,6 @@ extern bool contains_cilk_spawn_stmt (tree);
 extern tree cilk_for_number_of_iterations (tree);
 extern bool check_no_cilk (tree, const char *, const char *,
                           location_t loc = UNKNOWN_LOCATION);
+extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION);
 
 #endif /* ! GCC_C_COMMON_H */
index 47461d18578695716d03e5f91c19f230a2b77f74..658b62bbbe3f0f5f2f62945c6755c73d2a1cf0ec 100644 (file)
@@ -1,3 +1,12 @@
+2015-09-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c/66516
+       * c/c-typeck.c (convert_arguments, parser_build_unary_op)
+       (build_conditional_expr, c_cast_expr, convert_for_assignment)
+       (build_binary_op, _objc_common_truthvalue_conversion): Call
+       reject_gcc_builtin.
+       (c_decl_implicit): Define.
+
 2015-09-02  Marek Polacek  <polacek@redhat.com>
 
        PR c/67432
index e8c818989ee9b7ca62f9eed3b1ba4ac2744c8d9c..c622a9027e6f9bb0b38162f5aac0864cd5e459ff 100644 (file)
@@ -3339,6 +3339,10 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
          error (invalid_func_diag);
          return -1;
        }
+      else if (TREE_CODE (val) == ADDR_EXPR && reject_gcc_builtin (val))
+       {
+         return -1;
+       }
       else
        /* Convert `short' and `char' to full-size `int'.  */
        parmval = default_conversion (val);
@@ -3376,12 +3380,20 @@ parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg)
 {
   struct c_expr result;
 
-  result.value = build_unary_op (loc, code, arg.value, 0);
   result.original_code = code;
   result.original_type = NULL;
 
+  if (reject_gcc_builtin (arg.value))
+    {
+      result.value = error_mark_node;
+    }
+  else
+    {
+      result.value = build_unary_op (loc, code, arg.value, 0);
+
   if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
     overflow_warning (loc, result.value);
+    }
 
   return result;
 }
@@ -4484,6 +4496,12 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
   type2 = TREE_TYPE (op2);
   code2 = TREE_CODE (type2);
 
+  if (code1 == POINTER_TYPE && reject_gcc_builtin (op1))
+    return error_mark_node;
+
+  if (code2 == POINTER_TYPE && reject_gcc_builtin (op2))
+    return error_mark_node;
+
   /* C90 does not permit non-lvalue arrays in conditional expressions.
      In C99 they will be pointers by now.  */
   if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE)
@@ -5222,6 +5240,10 @@ c_cast_expr (location_t loc, struct c_type_name *type_name, tree expr)
   type = groktypename (type_name, &type_expr, &type_expr_const);
   warn_strict_prototypes = saved_wsp;
 
+  if (TREE_CODE (expr) == ADDR_EXPR && !VOID_TYPE_P (type)
+      && reject_gcc_builtin (expr))
+    return error_mark_node;
+
   ret = build_c_cast (loc, type, expr);
   if (type_expr)
     {
@@ -5861,6 +5883,10 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   rhs = require_complete_type (rhs);
   if (rhs == error_mark_node)
     return error_mark_node;
+
+  if (coder == POINTER_TYPE && reject_gcc_builtin (rhs))
+    return error_mark_node;
+
   /* A non-reference type can convert to a reference.  This handles
      va_start, va_copy and possibly port built-ins.  */
   if (codel == REFERENCE_TYPE && coder != REFERENCE_TYPE)
@@ -10350,6 +10376,14 @@ build_binary_op (location_t location, enum tree_code code,
   if (code0 == ERROR_MARK || code1 == ERROR_MARK)
     return error_mark_node;
 
+  if (code0 == POINTER_TYPE
+      && reject_gcc_builtin (op0, EXPR_LOCATION (orig_op0)))
+    return error_mark_node;
+
+  if (code1 == POINTER_TYPE
+      && reject_gcc_builtin (op1, EXPR_LOCATION (orig_op1)))
+    return error_mark_node;
+
   if ((invalid_op_diag
        = targetm.invalid_binary_op (code, type0, type1)))
     {
@@ -11330,6 +11364,11 @@ c_objc_common_truthvalue_conversion (location_t location, tree expr)
       error_at (location, "void value not ignored as it ought to be");
       return error_mark_node;
 
+    case POINTER_TYPE:
+      if (reject_gcc_builtin (expr))
+       return error_mark_node;
+      break;
+
     case FUNCTION_TYPE:
       gcc_unreachable ();
 
@@ -12882,3 +12921,13 @@ cilk_install_body_with_frame_cleanup (tree fndecl, tree body, void *w)
   append_to_statement_list (build_stmt (EXPR_LOCATION (body), TRY_FINALLY_EXPR,
                                        body_list, dtor), &list);
 }
+
+/* Returns true when the function declaration FNDECL is implicit,
+   introduced as a result of a call to an otherwise undeclared
+   function, and false otherwise.  */
+
+bool
+c_decl_implicit (const_tree fndecl)
+{
+  return C_DECL_IMPLICIT (fndecl);
+}
index cd00395f1135f49b32d540454ba31bc20b0fe9a4..41c56583004baff4200dc702c6c6d78aebd52a4c 100644 (file)
@@ -1,3 +1,15 @@
+2015-09-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c/66516
+       * cp/cp-tree.h (mark_rvalue_use, decay_conversion): Add new
+       argument(s).
+       * cp/expr.c (mark_rvalue_use): Use new argument.
+       * cp/call.c (build_addr_func): Call decay_conversion with new
+       argument.
+       * cp/pt.c (convert_template_argument): Call reject_gcc_builtin.
+       * cp/typeck.c (decay_conversion): Use new argument.
+       (c_decl_implicit): Define.
+
 2015-09-02  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
        PR middle-end/60586
index 8d4a9e23a0a51ba95dacaaaa285d6ecb9969b412..367d42b217c83f5c37c605b55ae64c399c596a5d 100644 (file)
@@ -288,7 +288,7 @@ build_addr_func (tree function, tsubst_flags_t complain)
       function = build_address (function);
     }
   else
-    function = decay_conversion (function, complain);
+    function = decay_conversion (function, complain, /*reject_builtin=*/false);
 
   return function;
 }
index 4dee60c052703f580513c4623497365225c029b6..784a61664ebc51fb7d1f8923565d39f2ec4b2977 100644 (file)
@@ -5787,7 +5787,9 @@ extern tree create_try_catch_expr               (tree, tree);
 
 /* in expr.c */
 extern tree cplus_expand_constant              (tree);
-extern tree mark_rvalue_use                    (tree);
+extern tree mark_rvalue_use                    (tree,
+                                                 location_t = UNKNOWN_LOCATION,
+                                                 bool = true);
 extern tree mark_lvalue_use                    (tree);
 extern tree mark_type_use                      (tree);
 extern void mark_exp_read                      (tree);
@@ -6461,7 +6463,9 @@ extern tree cxx_alignas_expr                    (tree);
 extern tree cxx_sizeof_nowarn                   (tree);
 extern tree is_bitfield_expr_with_lowered_type  (const_tree);
 extern tree unlowered_expr_type                 (const_tree);
-extern tree decay_conversion                   (tree, tsubst_flags_t);
+extern tree decay_conversion                   (tree,
+                                                 tsubst_flags_t,
+                                                 bool = true);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool,
                                                 tsubst_flags_t);
 extern tree finish_class_member_access_expr     (tree, tree, bool, 
index 6d2d658c7fae757e7db646e4d7ba494771096dd1..71dec3da0335df86bc28034d6b0f820dc43658c4 100644 (file)
@@ -91,18 +91,24 @@ cplus_expand_constant (tree cst)
   return cst;
 }
 
-/* Called whenever an expression is used
-   in a rvalue context.  */
-
+/* Called whenever the expression EXPR is used in an rvalue context.
+   When REJECT_BUILTIN is true the expression is checked to make sure
+   it doesn't make it possible to obtain the address of a GCC built-in
+   function with no library fallback (or any of its bits, such as in
+   a conversion to bool).  */
 tree
-mark_rvalue_use (tree expr)
+mark_rvalue_use (tree expr,
+                location_t loc /* = UNKNOWN_LOCATION */,
+                bool reject_builtin /* = true */)
 {
+  if (reject_builtin && reject_gcc_builtin (expr, loc))
+    return error_mark_node;
+
   mark_exp_read (expr);
   return expr;
 }
 
-/* Called whenever an expression is used
-   in a lvalue context.  */
+/* Called whenever an expression is used in an lvalue context.  */
 
 tree
 mark_lvalue_use (tree expr)
index fb7b9d21056b3c0212ccb1efef63bc92d7e26774..ec32c5a05426d0a6f7f5c3d15566990883268b31 100644 (file)
@@ -7199,6 +7199,18 @@ convert_template_argument (tree parm,
       else if (val == error_mark_node && (complain & tf_error))
        error ("could not convert template argument %qE to %qT",  orig_arg, t);
 
+      if (INDIRECT_REF_P (val))
+        {
+          /* Reject template arguments that are references to built-in
+             functions with no library fallbacks.  */
+          const_tree inner = TREE_OPERAND (val, 0);
+          if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE
+              && TREE_CODE (TREE_TYPE (TREE_TYPE (inner))) == FUNCTION_TYPE
+              && TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE
+              && reject_gcc_builtin (TREE_OPERAND (inner, 0)))
+              return error_mark_node;
+        }
+
       if (TREE_CODE (val) == SCOPE_REF)
        {
          /* Strip typedefs from the SCOPE_REF.  */
index 83fd34ca80ab337cc9add5330e9733bc60a6b6c4..388558c347dd2b3bba00ae0634935655684c80ee 100644 (file)
@@ -1911,7 +1911,9 @@ unlowered_expr_type (const_tree exp)
    that the return value is no longer an lvalue.  */
 
 tree
-decay_conversion (tree exp, tsubst_flags_t complain)
+decay_conversion (tree exp,
+                 tsubst_flags_t complain,
+                 bool reject_builtin /* = true */)
 {
   tree type;
   enum tree_code code;
@@ -1921,7 +1923,7 @@ decay_conversion (tree exp, tsubst_flags_t complain)
   if (type == error_mark_node)
     return error_mark_node;
 
-  exp = mark_rvalue_use (exp);
+  exp = mark_rvalue_use (exp, loc, reject_builtin);
 
   exp = resolve_nondeduced_context (exp);
   if (type_unknown_p (exp))
@@ -9397,3 +9399,12 @@ check_literal_operator_args (const_tree decl,
       return true;
     }
 }
+
+/* Always returns false since unlike C90, C++ has no concept of implicit
+   function declarations.  */
+
+bool
+c_decl_implicit (const_tree)
+{
+  return false;
+}
index dba8b4382b257172273175225cde3df441f5bcb3..23e6a76b8a8da6332af19be346095e880f814577 100644 (file)
@@ -10316,14 +10316,22 @@ recommend general use of these functions.
 
 The remaining functions are provided for optimization purposes.
 
+With the exception of built-ins that have library equivalents such as
+the standard C library functions discussed below, or that expand to
+library calls, GCC built-in functions are always expanded inline and
+thus do not have corresponding entry points and their address cannot
+be obtained.  Attempting to use them in an expression other than
+a function call results in a compile-time error.
+
 @opindex fno-builtin
 GCC includes built-in versions of many of the functions in the standard
-C library.  The versions prefixed with @code{__builtin_} are always
-treated as having the same meaning as the C library function even if you
-specify the @option{-fno-builtin} option.  (@pxref{C Dialect Options})
-Many of these functions are only optimized in certain cases; if they are
-not optimized in a particular case, a call to the library function is
-emitted.
+C library.  These functions come in two forms: one whose names start with
+the @code{__builtin_} prefix, and the other without.  Both forms have the
+same type (including prototype), the same address (when their address is
+taken), and the same meaning as the C library functions even if you specify
+the @option{-fno-builtin} option @pxref{C Dialect Options}).  Many of these
+functions are only optimized in certain cases; if they are not optimized in
+a particular case, a call to the library function is emitted.
 
 @opindex ansi
 @opindex std
index 4ca1b6a6e5aebf4ce465b319ac4071f1ffaedd4e..22a0bc56e8986a83269fe673b071ff1640a882d5 100644 (file)
@@ -1,3 +1,9 @@
+2015-09-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c/66516
+       * g++.dg/addr_builtin-1.C: New test.
+       * gcc.dg/addr_builtin-1.c: New test.
+
 2015-09-03  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
 
        * gcc.target/powerpc/vec-shift.c: New test.