summaryrefslogtreecommitdiff
path: root/gcc/cp/cvt.c
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-28 19:01:19 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-28 19:01:19 +0000
commitddd2a3d49aa496309f7ab3eebe1ded20da121b24 (patch)
tree0f443efe47d371ec7fe124b59afcaef0d9fe8d67 /gcc/cp/cvt.c
parent3ae3cb42eba0091e719425ce61d3010b5cdbd430 (diff)
downloadgcc-ddd2a3d49aa496309f7ab3eebe1ded20da121b24.tar.gz
Implement C++17 [[nodiscard]] attribute.
PR c++/38172 PR c++/54379 gcc/c-family/ * c-lex.c (c_common_has_attribute): Handle nodiscard. gcc/cp/ * parser.c (cp_parser_std_attribute): Handle [[nodiscard]]. * tree.c (handle_nodiscard_attribute): New. (cxx_attribute_table): Add [[nodiscard]]. * cvt.c (cp_get_fndecl_from_callee, cp_get_callee_fndecl): New. (maybe_warn_nodiscard): New. (convert_to_void): Call it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@235597 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp/cvt.c')
-rw-r--r--gcc/cp/cvt.c103
1 files changed, 102 insertions, 1 deletions
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 8c9d78b641c..2e2bac74307 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -918,6 +918,104 @@ cp_get_callee (tree call)
return NULL_TREE;
}
+/* FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+ if we can. */
+
+tree
+cp_get_fndecl_from_callee (tree fn)
+{
+ if (fn == NULL_TREE)
+ return fn;
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ tree type = TREE_TYPE (fn);
+ if (type == unknown_type_node)
+ return NULL_TREE;
+ gcc_assert (POINTER_TYPE_P (type));
+ fn = maybe_constant_init (fn);
+ STRIP_NOPS (fn);
+ if (TREE_CODE (fn) == ADDR_EXPR)
+ {
+ fn = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ }
+ return NULL_TREE;
+}
+
+/* Like get_callee_fndecl, but handles AGGR_INIT_EXPR as well and uses the
+ constexpr machinery. */
+
+tree
+cp_get_callee_fndecl (tree call)
+{
+ return cp_get_fndecl_from_callee (cp_get_callee (call));
+}
+
+/* Subroutine of convert_to_void. Warn if we're discarding something with
+ attribute [[nodiscard]]. */
+
+static void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
+{
+ tree call = expr;
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ call = TARGET_EXPR_INITIAL (expr);
+ location_t loc = EXPR_LOC_OR_LOC (call, input_location);
+ tree callee = cp_get_callee (call);
+ if (!callee)
+ return;
+
+ tree type = TREE_TYPE (callee);
+ if (TYPE_PTRMEMFUNC_P (type))
+ type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ if (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ tree rettype = TREE_TYPE (type);
+ tree fn = cp_get_fndecl_from_callee (callee);
+ if (implicit != ICV_CAST && fn
+ && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
+ {
+ if (warning_at (loc, OPT_Wunused_result,
+ "ignoring return value of %qD, "
+ "declared with attribute nodiscard", fn))
+ inform (DECL_SOURCE_LOCATION (fn), "declared here");
+ }
+ else if (implicit != ICV_CAST
+ && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
+ {
+ if (warning_at (loc, OPT_Wunused_result,
+ "ignoring returned value of type %qT, "
+ "declared with attribute nodiscard", rettype))
+ {
+ if (fn)
+ inform (DECL_SOURCE_LOCATION (fn),
+ "in call to %qD, declared here", fn);
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+ "%qT declared here", rettype);
+ }
+ }
+ else if (TREE_CODE (expr) == TARGET_EXPR
+ && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (type)))
+ {
+ /* The TARGET_EXPR confuses do_warn_unused_result into thinking that the
+ result is used, so handle that case here. */
+ if (fn)
+ {
+ if (warning_at (loc, OPT_Wunused_result,
+ "ignoring return value of %qD, "
+ "declared with attribute warn_unused_result",
+ fn))
+ inform (DECL_SOURCE_LOCATION (fn), "declared here");
+ }
+ else
+ warning_at (loc, OPT_Wunused_result,
+ "ignoring return value of function "
+ "declared with attribute warn_unused_result");
+ }
+}
+
/* When an expression is used in a void context, its value is discarded and
no lvalue-rvalue and similar conversions happen [expr.static.cast/4,
stmt.expr/1, expr.comma/1]. This permits dereferencing an incomplete type
@@ -1032,6 +1130,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
break;
case CALL_EXPR: /* We have a special meaning for volatile void fn(). */
+ maybe_warn_nodiscard (expr, implicit);
break;
case INDIRECT_REF:
@@ -1257,12 +1356,14 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
{
tree fn = AGGR_INIT_EXPR_FN (init);
expr = build_call_array_loc (input_location,
- TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ TREE_TYPE (TREE_TYPE
+ (TREE_TYPE (fn))),
fn,
aggr_init_expr_nargs (init),
AGGR_INIT_EXPR_ARGP (init));
}
}
+ maybe_warn_nodiscard (expr, implicit);
break;
default:;