@@ -222,18 +222,13 @@ static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
222
222
return S.Diag (Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
223
223
}
224
224
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 ();
233
228
234
229
// If we are in an unevaluated expression context, then there can be no unused
235
230
// results because the results aren't expected to be used in the first place.
236
- if (isUnevaluatedContext ())
231
+ if (S. isUnevaluatedContext ())
237
232
return ;
238
233
239
234
SourceLocation ExprLoc = E->IgnoreParenImpCasts ()->getExprLoc ();
@@ -242,30 +237,31 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
242
237
// expression is a call to a function with the warn_unused_result attribute,
243
238
// we warn no matter the location. Because of the order in which the various
244
239
// 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);
248
242
249
243
const Expr *WarnExpr;
250
244
SourceLocation Loc;
251
245
SourceRange R1, R2;
252
- if (!E->isUnusedResultAWarning (WarnExpr, Loc, R1, R2, Context))
246
+ if (!E->isUnusedResultAWarning (WarnExpr, Loc, R1, R2, S. Context ))
253
247
return ;
254
248
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 ())
268
255
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
+ }
269
265
}
270
266
271
267
// 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) {
276
272
if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
277
273
E = TempExpr->getSubExpr ();
278
274
279
- if (DiagnoseUnusedComparison (* this , E))
275
+ if (DiagnoseUnusedComparison (S , E))
280
276
return ;
281
277
282
278
E = WarnExpr;
@@ -289,8 +285,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
289
285
if (E->getType ()->isVoidType ())
290
286
return ;
291
287
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 )),
294
291
Loc, R1, R2, /* isCtor=*/ false ))
295
292
return ;
296
293
@@ -302,50 +299,50 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
302
299
if (ShouldSuppress)
303
300
return ;
304
301
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" ;
306
303
return ;
307
304
}
308
305
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" ;
310
307
return ;
311
308
}
312
309
}
313
310
} else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
314
311
if (const CXXConstructorDecl *Ctor = CE->getConstructor ()) {
315
312
const auto *A = Ctor->getAttr <WarnUnusedResultAttr>();
316
313
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 ))
318
315
return ;
319
316
}
320
317
} else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
321
318
if (const TagDecl *TD = ILE->getType ()->getAsTagDecl ()) {
322
319
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 ))
325
322
return ;
326
323
}
327
324
} else if (ShouldSuppress)
328
325
return ;
329
326
330
327
E = WarnExpr;
331
328
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;
334
331
return ;
335
332
}
336
333
const ObjCMethodDecl *MD = ME->getMethodDecl ();
337
334
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 ))
340
337
return ;
341
338
}
342
339
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
343
340
const Expr *Source = POE->getSyntacticForm ();
344
341
// 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) &&
346
343
POE->getNumSemanticExprs () == 1 &&
347
344
isa<CallExpr>(POE->getSemanticExpr (0 )))
348
- return DiagnoseUnusedExprResult ( POE->getSemanticExpr (0 ), DiagID);
345
+ return DiagnoseUnused (S, POE->getSemanticExpr (0 ), DiagID);
349
346
if (isa<ObjCSubscriptRefExpr>(Source))
350
347
DiagID = diag::warn_unused_container_subscript_expr;
351
348
else if (isa<ObjCPropertyRefExpr>(Source))
@@ -362,17 +359,21 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
362
359
if (!RD->getAttr <WarnUnusedAttr>())
363
360
return ;
364
361
}
362
+
363
+ if (NoDiscardOnly)
364
+ return ;
365
+
365
366
// 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)) {
367
368
TypeSourceInfo *TI = CE->getTypeInfoAsWritten ();
368
369
QualType T = TI->getType ();
369
370
370
371
// We really do want to use the non-canonical type here.
371
- if (T == Context.VoidPtrTy ) {
372
+ if (T == S. Context .VoidPtrTy ) {
372
373
PointerTypeLoc TL = TI->getTypeLoc ().castAs <PointerTypeLoc>();
373
374
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 ());
376
377
return ;
377
378
}
378
379
}
@@ -381,23 +382,34 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
381
382
// isn't an array.
382
383
if (E->isGLValue () && E->getType ().isVolatileQualified () &&
383
384
!E->getType ()->isArrayType ()) {
384
- Diag (Loc, diag::warn_unused_volatile) << R1 << R2;
385
+ S. Diag (Loc, diag::warn_unused_volatile) << R1 << R2;
385
386
return ;
386
387
}
387
388
388
389
// Do not diagnose use of a comma operator in a SFINAE context because the
389
390
// type of the left operand could be used for SFINAE, so technically it is
390
391
// *used*.
391
- if (DiagID == diag::warn_unused_comma_left_operand && isSFINAEContext ())
392
+ if (DiagID == diag::warn_unused_comma_left_operand && S. isSFINAEContext ())
392
393
return ;
393
394
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)
397
410
return ;
398
411
399
- DiagIfReachable (Loc, S ? llvm::ArrayRef (S) : std::nullopt,
400
- PDiag (DiagID) << R1 << R2);
412
+ DiagnoseUnused (*this , E, DiagID);
401
413
}
402
414
403
415
void Sema::ActOnStartOfCompoundStmt (bool IsStmtExpr) {
0 commit comments