Skip to content

Commit cc2c637

Browse files
committed
Change __declspec(property) handling; Refactor code; Tests
Create Sema::DiagnoseDiscardedNodiscard Remove warn_discarded_class_member_access and call Sema::DiagnoseDiscardedNodiscard instead Remove MakeGLValue from the MSPropertyRefExpr path Fix [[nodiscard]] test in test/CXX Add test for [[nodiscard]] and explicit object member functions in test/SemaCXX
1 parent a353728 commit cc2c637

File tree

7 files changed

+137
-86
lines changed

7 files changed

+137
-86
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9182,9 +9182,6 @@ def warn_unused_constructor : Warning<
91829182
def warn_unused_constructor_msg : Warning<
91839183
"ignoring temporary created by a constructor declared with %0 attribute: %1">,
91849184
InGroup<UnusedValue>;
9185-
def warn_discarded_class_member_access : Warning<
9186-
"left operand of dot in this class member access is discarded and has no effect">,
9187-
InGroup<UnusedValue>;
91889185
def warn_side_effects_unevaluated_context : Warning<
91899186
"expression with side effects has no effect in an unevaluated context">,
91909187
InGroup<UnevaluatedExpression>;

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8502,6 +8502,11 @@ class Sema final : public SemaBase {
85028502
SourceLocation EndLoc);
85038503
void ActOnForEachDeclStmt(DeclGroupPtrTy Decl);
85048504

8505+
/// DiagnoseDiscardedNodiscard - Given an expression that is semantically
8506+
/// a discarded-value expression, diagnose if any [[nodiscard]] value
8507+
/// has been discarded
8508+
void DiagnoseDiscardedNodiscard(const Expr *E);
8509+
85058510
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
85068511
/// whose result is unused, warn.
85078512
void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID);

clang/lib/AST/Expr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,6 +2962,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
29622962
case ExprWithCleanupsClass:
29632963
return cast<ExprWithCleanups>(this)->getSubExpr()
29642964
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
2965+
case OpaqueValueExprClass:
2966+
return cast<OpaqueValueExpr>(this)->getSourceExpr()->isUnusedResultAWarning(
2967+
WarnE, Loc, R1, R2, Ctx);
29652968
}
29662969
}
29672970

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11361136
// an enumerator, the first expression is a discarded-value expression; if
11371137
// the id-expression names a non-static data member, the first expression
11381138
// shall be a glvalue.
1139-
auto MakeDiscardedValue = [&BaseExpr, IsArrow, this] {
1139+
auto MakeDiscardedValue = [&] {
11401140
assert(getLangOpts().CPlusPlus &&
11411141
"Static member / member enumerator outside of C++");
11421142
if (IsArrow)
@@ -1145,11 +1145,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11451145
if (Converted.isInvalid())
11461146
return true;
11471147
BaseExpr = Converted.get();
1148-
DiagnoseUnusedExprResult(BaseExpr,
1149-
diag::warn_discarded_class_member_access);
1148+
DiagnoseDiscardedNodiscard(BaseExpr);
11501149
return false;
11511150
};
1152-
auto MakeGLValue = [&BaseExpr, IsArrow, this] {
1151+
auto MakeGLValue = [&] {
11531152
if (IsArrow || !BaseExpr->isPRValue())
11541153
return false;
11551154
ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
@@ -1171,10 +1170,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11711170
}
11721171

11731172
if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) {
1174-
// Properties treated as non-static data members for the purpose of
1175-
// temporary materialization
1176-
if (MakeGLValue())
1177-
return ExprError();
1173+
// No temporaries are materialized for property references yet.
1174+
// They might be materialized when this is transformed into a member call.
1175+
// Note that this is slightly different behaviour from MSVC which doesn't
1176+
// implement CWG2813 yet: MSVC might materialize an extra temporary if the
1177+
// getter or setter function is an explicit object member function.
11781178
return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
11791179
MemberNameInfo);
11801180
}

clang/lib/Sema/SemaStmt.cpp

Lines changed: 63 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -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

403415
void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {

0 commit comments

Comments
 (0)