complete_type (type);
int is_complete = COMPLETE_TYPE_P (type);
- /* Can't load the value if we don't know the type. */
- if (is_volatile && !is_complete)
+ /* Don't load the value if this is an implicit dereference, or if
+ the type needs to be handled by ctors/dtors. */
+ if (is_reference)
{
- if (complain & tf_warning)
+ if (is_volatile && (complain & tf_warning)
+ /* A co_await expression, in its await_resume expression, also
+ contains an implicit dereference. As a result, we don't
+ need to warn about them here. */
+ && TREE_CODE (TREE_OPERAND (expr, 0)) != CO_AWAIT_EXPR)
switch (implicit)
{
case ICV_CAST:
warning_at (loc, 0, "conversion to void will not access "
- "object of incomplete type %qT", type);
+ "object of type %qT", type);
break;
case ICV_SECOND_OF_COND:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in second operand "
- "of conditional expression", type);
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in second operand of "
+ "conditional expression", type);
break;
case ICV_THIRD_OF_COND:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in third operand "
- "of conditional expression", type);
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in third operand of "
+ "conditional expression", type);
break;
case ICV_RIGHT_OF_COMMA:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in right operand of "
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in right operand of "
"comma operator", type);
break;
case ICV_LEFT_OF_COMMA:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in left operand of "
- "comma operator", type);
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in left operand of comma "
+ "operator", type);
break;
case ICV_STATEMENT:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in statement", type);
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in statement", type);
break;
case ICV_THIRD_IN_FOR:
- warning_at (loc, 0, "indirection will not access object of "
- "incomplete type %qT in for increment "
- "expression", type);
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in for increment expression",
+ type);
break;
default:
gcc_unreachable ();
}
+
+ /* Since this was an implicit dereference, we should also act as if
+ it was never there. */
+ return convert_to_void (TREE_OPERAND (expr, 0), implicit, complain);
}
- /* Don't load the value if this is an implicit dereference, or if
- the type needs to be handled by ctors/dtors. */
- else if (is_volatile && is_reference)
+ /* Can't load the value if we don't know the type. */
+ else if (is_volatile && !is_complete)
{
if (complain & tf_warning)
switch (implicit)
{
case ICV_CAST:
warning_at (loc, 0, "conversion to void will not access "
- "object of type %qT", type);
+ "object of incomplete type %qT", type);
break;
case ICV_SECOND_OF_COND:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in second operand of "
- "conditional expression", type);
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in second operand "
+ "of conditional expression", type);
break;
case ICV_THIRD_OF_COND:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in third operand of "
- "conditional expression", type);
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in third operand "
+ "of conditional expression", type);
break;
case ICV_RIGHT_OF_COMMA:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in right operand of "
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in right operand of "
"comma operator", type);
break;
case ICV_LEFT_OF_COMMA:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in left operand of comma "
- "operator", type);
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in left operand of "
+ "comma operator", type);
break;
case ICV_STATEMENT:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in statement", type);
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in statement", type);
break;
case ICV_THIRD_IN_FOR:
- warning_at (loc, 0, "implicit dereference will not access "
- "object of type %qT in for increment expression",
- type);
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in for increment "
+ "expression", type);
break;
default:
gcc_unreachable ();
gcc_unreachable ();
}
}
- if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
+ if (!is_volatile || !is_complete || TREE_ADDRESSABLE (type))
{
/* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
operation is stripped off. Note that we don't warn about
&& !is_reference)
warning_at (loc, OPT_Wunused_value, "value computed is not used");
expr = TREE_OPERAND (expr, 0);
- if (TREE_CODE (expr) == CALL_EXPR
- && (complain & tf_warning))
- maybe_warn_nodiscard (expr, implicit);
}
break;
break;
case CO_AWAIT_EXPR:
- {
- auto awr = co_await_get_resume_call (expr);
- if (awr && *awr)
- *awr = convert_to_void (*awr, implicit, complain);
- break;
- }
+ if (auto awr = co_await_get_resume_call (expr))
+ convert_to_void (awr, implicit, complain);
+ break;
default:;
}
--- /dev/null
+#include <coroutine>
+/* Make sure that we correctly warn for unused co_await results. */
+
+struct task
+{
+ struct promise_type
+ {
+ std::suspend_never initial_suspend () noexcept;
+ std::suspend_never final_suspend () noexcept;
+ void return_void ();
+ void unhandled_exception ();
+ task get_return_object ();
+ };
+};
+
+template<typename T>
+struct nodiscardable : std::suspend_never
+{ [[nodiscard]] T await_resume (); };
+
+template<typename T>
+struct discardable : std::suspend_never
+{ T await_resume (); };
+
+task
+thing ()
+{
+ co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */
+ co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */
+
+ (void) co_await nodiscardable<int&>{};
+ (void) co_await nodiscardable<int>{};
+
+ co_await discardable<int&>{};
+ co_await discardable<volatile int&>{};
+ /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */
+}
+
+template<typename>
+task
+other_thing ()
+{
+ co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */
+ co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */
+
+ (void) co_await nodiscardable<int&>{};
+ (void) co_await nodiscardable<int>{};
+
+ co_await discardable<int&>{};
+ co_await discardable<volatile int&>{};
+ /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */
+}
+
+void
+other_thing_caller ()
+{
+ other_thing <int> ();
+}
+
+task
+yet_another_thing (auto)
+{
+ co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */
+ co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */
+
+ (void) co_await nodiscardable<int&>{};
+ (void) co_await nodiscardable<int>{};
+
+ co_await discardable<int&>{};
+ co_await discardable<volatile int&>{};
+ /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */
+}
+
+void
+yet_another_thing_caller ()
+{
+ yet_another_thing (1);
+}