@@ -222,18 +222,13 @@ static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
222222 return S.Diag (Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
223223}
224224
225- void Sema::DiagnoseUnusedExprResult (const Stmt *S, unsigned DiagID) {
226- const unsigned OrigDiagID = DiagID;
227- if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
228- return DiagnoseUnusedExprResult (Label->getSubStmt (), DiagID);
229-
230- const Expr *E = dyn_cast_or_null<Expr>(S);
231- if (!E)
232- return ;
225+ namespace {
226+ void DiagnoseUnused (Sema &S, const Expr *E, std::optional<unsigned > DiagID) {
227+ bool NoDiscardOnly = !DiagID.has_value ();
233228
234229 // If we are in an unevaluated expression context, then there can be no unused
235230 // results because the results aren't expected to be used in the first place.
236- if (isUnevaluatedContext ())
231+ if (S. isUnevaluatedContext ())
237232 return ;
238233
239234 SourceLocation ExprLoc = E->IgnoreParenImpCasts ()->getExprLoc ();
@@ -242,30 +237,31 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
242237 // expression is a call to a function with the warn_unused_result attribute,
243238 // we warn no matter the location. Because of the order in which the various
244239 // checks need to happen, we factor out the macro-related test here.
245- bool ShouldSuppress =
246- SourceMgr.isMacroBodyExpansion (ExprLoc) ||
247- SourceMgr.isInSystemMacro (ExprLoc);
240+ bool ShouldSuppress = S.SourceMgr .isMacroBodyExpansion (ExprLoc) ||
241+ S.SourceMgr .isInSystemMacro (ExprLoc);
248242
249243 const Expr *WarnExpr;
250244 SourceLocation Loc;
251245 SourceRange R1, R2;
252- if (!E->isUnusedResultAWarning (WarnExpr, Loc, R1, R2, Context))
246+ if (!E->isUnusedResultAWarning (WarnExpr, Loc, R1, R2, S. Context ))
253247 return ;
254248
255- // If this is a GNU statement expression expanded from a macro, it is probably
256- // unused because it is a function-like macro that can be used as either an
257- // expression or statement. Don't warn, because it is almost certainly a
258- // false positive.
259- if (isa<StmtExpr>(E) && Loc.isMacroID ())
260- return ;
261-
262- // Check if this is the UNREFERENCED_PARAMETER from the Microsoft headers.
263- // That macro is frequently used to suppress "unused parameter" warnings,
264- // but its implementation makes clang's -Wunused-value fire. Prevent this.
265- if (isa<ParenExpr>(E->IgnoreImpCasts ()) && Loc.isMacroID ()) {
266- SourceLocation SpellLoc = Loc;
267- if (findMacroSpelling (SpellLoc, " UNREFERENCED_PARAMETER" ))
249+ if (!NoDiscardOnly) {
250+ // If this is a GNU statement expression expanded from a macro, it is
251+ // probably unused because it is a function-like macro that can be used as
252+ // either an expression or statement. Don't warn, because it is almost
253+ // certainly a false positive.
254+ if (isa<StmtExpr>(E) && Loc.isMacroID ())
268255 return ;
256+
257+ // Check if this is the UNREFERENCED_PARAMETER from the Microsoft headers.
258+ // That macro is frequently used to suppress "unused parameter" warnings,
259+ // but its implementation makes clang's -Wunused-value fire. Prevent this.
260+ if (isa<ParenExpr>(E->IgnoreImpCasts ()) && Loc.isMacroID ()) {
261+ SourceLocation SpellLoc = Loc;
262+ if (S.findMacroSpelling (SpellLoc, " UNREFERENCED_PARAMETER" ))
263+ return ;
264+ }
269265 }
270266
271267 // Okay, we have an unused result. Depending on what the base expression is,
@@ -276,7 +272,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
276272 if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
277273 E = TempExpr->getSubExpr ();
278274
279- if (DiagnoseUnusedComparison (* this , E))
275+ if (DiagnoseUnusedComparison (S , E))
280276 return ;
281277
282278 E = WarnExpr;
@@ -289,8 +285,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
289285 if (E->getType ()->isVoidType ())
290286 return ;
291287
292- if (DiagnoseNoDiscard (*this , cast_or_null<WarnUnusedResultAttr>(
293- CE->getUnusedResultAttr (Context)),
288+ if (DiagnoseNoDiscard (S,
289+ cast_if_present<WarnUnusedResultAttr>(
290+ CE->getUnusedResultAttr (S.Context )),
294291 Loc, R1, R2, /* isCtor=*/ false ))
295292 return ;
296293
@@ -302,50 +299,50 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
302299 if (ShouldSuppress)
303300 return ;
304301 if (FD->hasAttr <PureAttr>()) {
305- Diag (Loc, diag::warn_unused_call) << R1 << R2 << " pure" ;
302+ S. Diag (Loc, diag::warn_unused_call) << R1 << R2 << " pure" ;
306303 return ;
307304 }
308305 if (FD->hasAttr <ConstAttr>()) {
309- Diag (Loc, diag::warn_unused_call) << R1 << R2 << " const" ;
306+ S. Diag (Loc, diag::warn_unused_call) << R1 << R2 << " const" ;
310307 return ;
311308 }
312309 }
313310 } else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
314311 if (const CXXConstructorDecl *Ctor = CE->getConstructor ()) {
315312 const auto *A = Ctor->getAttr <WarnUnusedResultAttr>();
316313 A = A ? A : Ctor->getParent ()->getAttr <WarnUnusedResultAttr>();
317- if (DiagnoseNoDiscard (* this , A, Loc, R1, R2, /* isCtor=*/ true ))
314+ if (DiagnoseNoDiscard (S , A, Loc, R1, R2, /* isCtor=*/ true ))
318315 return ;
319316 }
320317 } else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
321318 if (const TagDecl *TD = ILE->getType ()->getAsTagDecl ()) {
322319
323- if (DiagnoseNoDiscard (* this , TD->getAttr <WarnUnusedResultAttr>(), Loc, R1,
324- R2, /* isCtor=*/ false ))
320+ if (DiagnoseNoDiscard (S , TD->getAttr <WarnUnusedResultAttr>(), Loc, R1, R2 ,
321+ /* isCtor=*/ false ))
325322 return ;
326323 }
327324 } else if (ShouldSuppress)
328325 return ;
329326
330327 E = WarnExpr;
331328 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
332- if (getLangOpts ().ObjCAutoRefCount && ME->isDelegateInitCall ()) {
333- Diag (Loc, diag::err_arc_unused_init_message) << R1;
329+ if (S. getLangOpts ().ObjCAutoRefCount && ME->isDelegateInitCall ()) {
330+ S. Diag (Loc, diag::err_arc_unused_init_message) << R1;
334331 return ;
335332 }
336333 const ObjCMethodDecl *MD = ME->getMethodDecl ();
337334 if (MD) {
338- if (DiagnoseNoDiscard (* this , MD->getAttr <WarnUnusedResultAttr>(), Loc, R1,
339- R2, /* isCtor=*/ false ))
335+ if (DiagnoseNoDiscard (S , MD->getAttr <WarnUnusedResultAttr>(), Loc, R1, R2 ,
336+ /* isCtor=*/ false ))
340337 return ;
341338 }
342339 } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
343340 const Expr *Source = POE->getSyntacticForm ();
344341 // Handle the actually selected call of an OpenMP specialized call.
345- if (LangOpts.OpenMP && isa<CallExpr>(Source) &&
342+ if (S. LangOpts .OpenMP && isa<CallExpr>(Source) &&
346343 POE->getNumSemanticExprs () == 1 &&
347344 isa<CallExpr>(POE->getSemanticExpr (0 )))
348- return DiagnoseUnusedExprResult ( POE->getSemanticExpr (0 ), DiagID);
345+ return DiagnoseUnused (S, POE->getSemanticExpr (0 ), DiagID);
349346 if (isa<ObjCSubscriptRefExpr>(Source))
350347 DiagID = diag::warn_unused_container_subscript_expr;
351348 else if (isa<ObjCPropertyRefExpr>(Source))
@@ -362,17 +359,21 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
362359 if (!RD->getAttr <WarnUnusedAttr>())
363360 return ;
364361 }
362+
363+ if (NoDiscardOnly)
364+ return ;
365+
365366 // Diagnose "(void*) blah" as a typo for "(void) blah".
366- else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
367+ if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
367368 TypeSourceInfo *TI = CE->getTypeInfoAsWritten ();
368369 QualType T = TI->getType ();
369370
370371 // We really do want to use the non-canonical type here.
371- if (T == Context.VoidPtrTy ) {
372+ if (T == S. Context .VoidPtrTy ) {
372373 PointerTypeLoc TL = TI->getTypeLoc ().castAs <PointerTypeLoc>();
373374
374- Diag (Loc, diag::warn_unused_voidptr)
375- << FixItHint::CreateRemoval (TL.getStarLoc ());
375+ S. Diag (Loc, diag::warn_unused_voidptr)
376+ << FixItHint::CreateRemoval (TL.getStarLoc ());
376377 return ;
377378 }
378379 }
@@ -381,23 +382,34 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
381382 // isn't an array.
382383 if (E->isGLValue () && E->getType ().isVolatileQualified () &&
383384 !E->getType ()->isArrayType ()) {
384- Diag (Loc, diag::warn_unused_volatile) << R1 << R2;
385+ S. Diag (Loc, diag::warn_unused_volatile) << R1 << R2;
385386 return ;
386387 }
387388
388389 // Do not diagnose use of a comma operator in a SFINAE context because the
389390 // type of the left operand could be used for SFINAE, so technically it is
390391 // *used*.
391- if (DiagID == diag::warn_unused_comma_left_operand && isSFINAEContext ())
392+ if (DiagID == diag::warn_unused_comma_left_operand && S. isSFINAEContext ())
392393 return ;
393394
394- // Don't diagnose discarded left of dot in static class member access
395- // because its type is "used" to determine the class to access
396- if (OrigDiagID == diag::warn_discarded_class_member_access)
395+ S.DiagIfReachable (Loc, llvm::ArrayRef<const Stmt *>(E),
396+ S.PDiag (*DiagID) << R1 << R2);
397+ }
398+ } // namespace
399+
400+ void Sema::DiagnoseDiscardedNodiscard (const Expr *E) {
401+ DiagnoseUnused (*this , E, std::nullopt );
402+ }
403+
404+ void Sema::DiagnoseUnusedExprResult (const Stmt *S, unsigned DiagID) {
405+ if (const LabelStmt *Label = dyn_cast_if_present<LabelStmt>(S))
406+ S = Label->getSubStmt ();
407+
408+ const Expr *E = dyn_cast_if_present<Expr>(S);
409+ if (!E)
397410 return ;
398411
399- DiagIfReachable (Loc, S ? llvm::ArrayRef (S) : std::nullopt ,
400- PDiag (DiagID) << R1 << R2);
412+ DiagnoseUnused (*this , E, DiagID);
401413}
402414
403415void Sema::ActOnStartOfCompoundStmt (bool IsStmtExpr) {
0 commit comments