From 6c93b3e29c56d14eab570ce62cd646a95f0c1403 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Wed, 17 Dec 2014 21:57:17 +0000 Subject: [PATCH] Adding a -Wunused-value warning for expressions with side effects used in an unevaluated expression context, such as sizeof(), or decltype(). Also adds a similar warning when the expression passed to typeid() *is* evaluated, since it is equally likely that the user would expect the expression operand to be unevaluated in that case. llvm-svn: 224465 --- clang/include/clang/AST/Expr.h | 9 +++- clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 +++ clang/include/clang/Sema/Sema.h | 5 +- clang/lib/AST/Expr.cpp | 57 ++++++++++++++-------- clang/lib/Sema/SemaExpr.cpp | 13 +++++ clang/lib/Sema/SemaExprCXX.cpp | 20 +++++++- clang/lib/Sema/SemaTemplateDeduction.cpp | 2 +- clang/lib/Sema/SemaType.cpp | 10 +++- .../expr.prim.lambda/p2-generic-lambda-1y.cpp | 2 +- .../CXX/expr/expr.prim/expr.prim.lambda/p2.cpp | 2 +- .../expr/expr.unary/expr.unary.noexcept/sema.cpp | 2 +- clang/test/Sema/bitfield.c | 3 +- clang/test/Sema/expr-comma-c99.c | 3 +- clang/test/Sema/expr-comma.c | 3 +- clang/test/Sema/warn-unused-value.c | 25 ++++++++-- clang/test/SemaCXX/constant-expression-cxx11.cpp | 3 +- clang/test/SemaCXX/runtimediag-ppe.cpp | 2 +- clang/test/SemaCXX/undefined-internal.cpp | 2 +- clang/test/SemaCXX/vararg-non-pod.cpp | 2 +- clang/test/SemaCXX/warn-unused-result.cpp | 2 +- clang/test/SemaCXX/warn-unused-value-cxx11.cpp | 30 +++++++++++- clang/test/SemaCXX/warn-unused-value.cpp | 33 +++++++++++-- clang/test/SemaObjCXX/arc-ppe.mm | 2 +- 23 files changed, 191 insertions(+), 47 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 6b2c939..975e1b3 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -586,8 +586,13 @@ public: /// HasSideEffects - This routine returns true for all those expressions /// which have any effect other than producing a value. Example is a function - /// call, volatile variable read, or throwing an exception. - bool HasSideEffects(const ASTContext &Ctx) const; + /// call, volatile variable read, or throwing an exception. If + /// IncludePossibleEffects is false, this call treats certain expressions with + /// potential side effects (such as function call-like expressions, + /// instantiation-dependent expressions, or invocations from a macro) as not + /// having side effects. + bool HasSideEffects(const ASTContext &Ctx, + bool IncludePossibleEffects = true) const; /// \brief Determine whether this expression involves a call to any function /// that is not trivial. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a939f51..99049c8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6107,6 +6107,12 @@ def warn_unused_container_subscript_expr : Warning< def warn_unused_call : Warning< "ignoring return value of function declared with %0 attribute">, InGroup; +def warn_side_effects_unevaluated_context : Warning< + "expression with side effects has no effect in an unevaluated context">, + InGroup; +def warn_side_effects_typeid : Warning< + "expression with side effects will be evaluated despite being used as an " + "operand to 'typeid'">, InGroup; def warn_unused_result : Warning< "ignoring return value of function declared with warn_unused_result " "attribute">, InGroup>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8786b6a..39f8e66 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1399,7 +1399,10 @@ public: const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); - QualType BuildDecltypeType(Expr *E, SourceLocation Loc); + /// If AsUnevaluated is false, E is treated as though it were an evaluated + /// context, such as when building a type for decltype(auto). + QualType BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index c98448f..818b60c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2866,9 +2866,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, return false; } -bool Expr::HasSideEffects(const ASTContext &Ctx) const { +bool Expr::HasSideEffects(const ASTContext &Ctx, + bool IncludePossibleEffects) const { + // In circumstances where we care about definite side effects instead of + // potential side effects, we want to ignore expressions that are part of a + // macro expansion as a potential side effect. + if (!IncludePossibleEffects && getExprLoc().isMacroID()) + return false; + if (isInstantiationDependent()) - return true; + return IncludePossibleEffects; switch (getStmtClass()) { case NoStmtClass: @@ -2921,21 +2928,27 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return false; case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: + case CUDAKernelCallExprClass: + case BlockExprClass: + case CXXBindTemporaryExprClass: + case UserDefinedLiteralClass: + // We don't know a call definitely has side effects, but we can check the + // call's operands. + if (!IncludePossibleEffects) + break; + return true; + case MSPropertyRefExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: case StmtExprClass: - case CXXOperatorCallExprClass: - case CXXMemberCallExprClass: - case UserDefinedLiteralClass: case CXXThrowExprClass: case CXXNewExprClass: case CXXDeleteExprClass: case ExprWithCleanupsClass: - case CXXBindTemporaryExprClass: - case BlockExprClass: - case CUDAKernelCallExprClass: // These always have a side-effect. return true; @@ -2971,24 +2984,26 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case InitListExprClass: // FIXME: The children for an InitListExpr doesn't include the array filler. if (const Expr *E = cast(this)->getArrayFiller()) - if (E->HasSideEffects(Ctx)) + if (E->HasSideEffects(Ctx, IncludePossibleEffects)) return true; break; case GenericSelectionExprClass: return cast(this)->getResultExpr()-> - HasSideEffects(Ctx); + HasSideEffects(Ctx, IncludePossibleEffects); case ChooseExprClass: - return cast(this)->getChosenSubExpr()->HasSideEffects(Ctx); + return cast(this)->getChosenSubExpr()->HasSideEffects( + Ctx, IncludePossibleEffects); case CXXDefaultArgExprClass: - return cast(this)->getExpr()->HasSideEffects(Ctx); + return cast(this)->getExpr()->HasSideEffects( + Ctx, IncludePossibleEffects); case CXXDefaultInitExprClass: { const FieldDecl *FD = cast(this)->getField(); if (const Expr *E = FD->getInClassInitializer()) - return E->HasSideEffects(Ctx); + return E->HasSideEffects(Ctx, IncludePossibleEffects); // If we've not yet parsed the initializer, assume it has side-effects. return true; } @@ -3021,7 +3036,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { const CXXConstructExpr *CE = cast(this); - if (!CE->getConstructor()->isTrivial()) + if (!CE->getConstructor()->isTrivial() && IncludePossibleEffects) return true; // A trivial constructor does not add any side-effects of its own. Just look // at its arguments. @@ -3049,7 +3064,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { const Expr *Subexpr = *I; if (const OpaqueValueExpr *OVE = dyn_cast(Subexpr)) Subexpr = OVE->getSourceExpr(); - if (Subexpr->HasSideEffects(Ctx)) + if (Subexpr->HasSideEffects(Ctx, IncludePossibleEffects)) return true; } return false; @@ -3058,22 +3073,24 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case ObjCBoxedExprClass: case ObjCArrayLiteralClass: case ObjCDictionaryLiteralClass: - case ObjCMessageExprClass: case ObjCSelectorExprClass: case ObjCProtocolExprClass: - case ObjCPropertyRefExprClass: case ObjCIsaExprClass: case ObjCIndirectCopyRestoreExprClass: case ObjCSubscriptRefExprClass: case ObjCBridgedCastExprClass: - // FIXME: Classify these cases better. - return true; + case ObjCMessageExprClass: + case ObjCPropertyRefExprClass: + // FIXME: Classify these cases better. + if (IncludePossibleEffects) + return true; + break; } // Recurse to children. for (const_child_range SubStmts = children(); SubStmts; ++SubStmts) if (const Stmt *S = *SubStmts) - if (cast(S)->HasSideEffects(Ctx)) + if (cast(S)->HasSideEffects(Ctx, IncludePossibleEffects)) return true; return false; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 22cc925..ef38fec 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1290,6 +1290,13 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, ControllingExpr = result.get(); } + // The controlling expression is an unevaluated operand, so side effects are + // likely unintended. + if (ActiveTemplateInstantiations.empty() && + ControllingExpr->HasSideEffects(Context, false)) + Diag(ControllingExpr->getExprLoc(), + diag::warn_side_effects_unevaluated_context); + bool TypeErrorFound = false, IsResultDependent = ControllingExpr->isTypeDependent(), ContainsUnexpandedParameterPack @@ -3525,6 +3532,12 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return true; } + // The operand for sizeof and alignof is in an unevaluated expression context, + // so side effects could result in unintended consequences. + if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) && + ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false)) + Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); + if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return true; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 2d3d127..d3a1fa8 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -396,6 +396,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { + bool WasEvaluated = false; if (E && !E->isTypeDependent()) { if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); @@ -425,6 +426,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); + WasEvaluated = true; } } @@ -444,6 +446,14 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (E->getType()->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << E->getType()); + else if (ActiveTemplateInstantiations.empty() && + E->HasSideEffects(Context, WasEvaluated)) { + // The expression operand for typeid is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(E->getExprLoc(), WasEvaluated + ? diag::warn_side_effects_typeid + : diag::warn_side_effects_unevaluated_context); + } return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, SourceRange(TypeidLoc, RParenLoc)); @@ -5622,7 +5632,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), + false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); @@ -5690,6 +5701,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { + if (ActiveTemplateInstantiations.empty() && + Operand->HasSideEffects(Context, false)) { + // The expression operand for noexcept is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); + } + CanThrowResult CanThrow = canThrow(Operand); return new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 221a84d..0d43c01 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3989,7 +3989,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { return DAR_FailedAlreadyDiagnosed; } - QualType Deduced = BuildDecltypeType(Init, Init->getLocStart()); + QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false); // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); Result = SubstituteAutoTransform(*this, Deduced).Apply(Type); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f442743..4582406 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5518,11 +5518,19 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { return T; } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { +QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated) { ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.get(); + if (AsUnevaluated && ActiveTemplateInstantiations.empty() && + E->HasSideEffects(Context, false)) { + // The expression operand for decltype is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); + } + return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp index 03147a6..d791ed6 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp @@ -18,7 +18,7 @@ void unevaluated_operand(P &p, int i) { //expected-note{{declared here}} // FIXME: this should only emit one error. int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \ // expected-error{{invalid application of 'sizeof'}} - const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i)); + const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\ // expected-error{{cannot be implicitly captured}}\ // expected-note{{begins here}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp index 1fbe287..647c76d 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-unused-value %s -verify // prvalue void prvalue() { diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp index 427e8c5..a2a5795 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions -Wno-delete-incomplete %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions -Wno-delete-incomplete -Wno-unused-value %s // expected-no-diagnostics #define P(e) static_assert(noexcept(e), "expected nothrow") diff --git a/clang/test/Sema/bitfield.c b/clang/test/Sema/bitfield.c index a4629c6..fb72213 100644 --- a/clang/test/Sema/bitfield.c +++ b/clang/test/Sema/bitfield.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c11 +// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c11 -Wno-unused-value + enum e0; // expected-note{{forward declaration of 'enum e0'}} struct a { diff --git a/clang/test/Sema/expr-comma-c99.c b/clang/test/Sema/expr-comma-c99.c index 02886bf..934c81c 100644 --- a/clang/test/Sema/expr-comma-c99.c +++ b/clang/test/Sema/expr-comma-c99.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -std=c99 -Wno-sizeof-array-decay -// expected-no-diagnostics // rdar://6095180 struct s { char c[17]; }; @@ -14,5 +13,5 @@ int B[sizeof((a.c)) == 17 ? 1 : -1]; // comma does array/function promotion in c99. int X[sizeof(0, (foo().c)) == sizeof(char*) ? 1 : -1]; int Y[sizeof(0, (a,b).c) == sizeof(char*) ? 1 : -1]; -int Z[sizeof(0, (a=b).c) == sizeof(char*) ? 1 : -1]; +int Z[sizeof(0, (a=b).c) == sizeof(char*) ? 1 : -1]; // expected-warning {{expression with side effects has no effect in an unevaluated context}} diff --git a/clang/test/Sema/expr-comma.c b/clang/test/Sema/expr-comma.c index e2beafe..04e57de 100644 --- a/clang/test/Sema/expr-comma.c +++ b/clang/test/Sema/expr-comma.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -std=c89 -Wno-sizeof-array-decay -// expected-no-diagnostics // rdar://6095180 struct s { char c[17]; }; @@ -15,4 +14,4 @@ int B[sizeof((a.c)) == 17 ? 1 : -1]; int W[sizeof(0, a.c) == sizeof(char*) ? 1 : -1]; int X[sizeof(0, (foo().c)) == 17 ? 1 : -1]; int Y[sizeof(0, (a,b).c) == 17 ? 1 : -1]; -int Z[sizeof(0, (a=b).c) == 17 ? 1 : -1]; +int Z[sizeof(0, (a=b).c) == 17 ? 1 : -1]; // expected-warning {{expression with side effects has no effect in an unevaluated context}} diff --git a/clang/test/Sema/warn-unused-value.c b/clang/test/Sema/warn-unused-value.c index 95cd8fb..edf7915 100644 --- a/clang/test/Sema/warn-unused-value.c +++ b/clang/test/Sema/warn-unused-value.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -Wunused-label %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wunused-value -Wunused-label %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wunused %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wall %s int i = 0; int j = 0; @@ -88,3 +88,22 @@ void f1(struct s0 *a) { // rdar://8139785 f0((int)(a->f0 + 1, 10)); // expected-warning {{expression result unused}} } + +void blah(int a); +#define GenTest(x) _Generic(x, default : blah)(x) + +void unevaluated_operands(void) { + int val = 0; + + (void)sizeof(++val); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + (void)_Generic(val++, default : 0); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + (void)_Alignof(val++); // expected-warning {{expression with side effects has no effect in an unevaluated context}} expected-warning {{'_Alignof' applied to an expression is a GNU extension}} + + // VLAs can have side effects so long as it's part of the type and not + // an expression. + (void)sizeof(int[++val]); // Ok + (void)_Alignof(int[++val]); // Ok + + // Side effects as part of macro expansion are ok. + GenTest(val++); +} diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index e684f09..d8f6f08 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1613,7 +1613,8 @@ namespace TypeId { A &g(); constexpr auto &x = typeid(f()); constexpr auto &y = typeid(g()); // expected-error{{constant expression}} \ - // expected-note{{typeid applied to expression of polymorphic type 'TypeId::A' is not allowed in a constant expression}} + // expected-note{{typeid applied to expression of polymorphic type 'TypeId::A' is not allowed in a constant expression}} \ + // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} } namespace PR14203 { diff --git a/clang/test/SemaCXX/runtimediag-ppe.cpp b/clang/test/SemaCXX/runtimediag-ppe.cpp index 0e8451b..2788963 100644 --- a/clang/test/SemaCXX/runtimediag-ppe.cpp +++ b/clang/test/SemaCXX/runtimediag-ppe.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value %s // Make sure diagnostics that we don't print based on runtime control // flow are delayed correctly in cases where we can't immediately tell whether diff --git a/clang/test/SemaCXX/undefined-internal.cpp b/clang/test/SemaCXX/undefined-internal.cpp index d829380..0138967 100644 --- a/clang/test/SemaCXX/undefined-internal.cpp +++ b/clang/test/SemaCXX/undefined-internal.cpp @@ -163,7 +163,7 @@ namespace cxx11_odr_rules { // Check that the checks work with unevaluated contexts (void)sizeof(p(A::used1)); - (void)typeid(p(A::used1)); // xpected-note {{used here}} + (void)typeid(p(A::used1)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} xpected-note {{used here}} // Misc other testing a(A::unused, 1 ? A::used2 : A::used2); // xpected-note {{used here}} diff --git a/clang/test/SemaCXX/vararg-non-pod.cpp b/clang/test/SemaCXX/vararg-non-pod.cpp index 66da996..39d4ccc 100644 --- a/clang/test/SemaCXX/vararg-non-pod.cpp +++ b/clang/test/SemaCXX/vararg-non-pod.cpp @@ -103,7 +103,7 @@ Base &get_base(...); int eat_base(...); void test_typeid(Base &base) { - (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}} + (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}} expected-warning{{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} (void)typeid(eat_base(base)); // okay } diff --git a/clang/test/SemaCXX/warn-unused-result.cpp b/clang/test/SemaCXX/warn-unused-result.cpp index 1af0a01..7bdb424 100644 --- a/clang/test/SemaCXX/warn-unused-result.cpp +++ b/clang/test/SemaCXX/warn-unused-result.cpp @@ -132,7 +132,7 @@ void g() { D d; C c; (void)typeid(f(), c); // Should not warn. - (void)typeid(f(), d); // expected-warning {{ignoring return value}} + (void)typeid(f(), d); // expected-warning {{ignoring return value}} expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} // The sizeof expression operand is never evaluated. (void)sizeof(f(), c); // Should not warn. diff --git a/clang/test/SemaCXX/warn-unused-value-cxx11.cpp b/clang/test/SemaCXX/warn-unused-value-cxx11.cpp index 115ddf3..d929b4f 100644 --- a/clang/test/SemaCXX/warn-unused-value-cxx11.cpp +++ b/clang/test/SemaCXX/warn-unused-value-cxx11.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wunused-value %s -// expected-no-diagnostics void f() __attribute__((const)); @@ -13,4 +12,33 @@ auto foo(T) -> decltype(f(), bool()) { // Should not warn. void g() { foo(1); } + +void h() { + int i = 0; + (void)noexcept(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + decltype(i++) j = 0; // expected-warning {{expression with side effects has no effect in an unevaluated context}} } + +struct S { + S operator++(int); + S(int i); + S(); + + int& f(); + S g(); +}; + +void j() { + S s; + int i = 0; + (void)noexcept(s++); // Ok + (void)noexcept(i++); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + (void)noexcept(i = 5); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + (void)noexcept(s = 5); // Ok + + (void)sizeof(s.f()); // Ok + (void)sizeof(s.f() = 5); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + (void)noexcept(s.g() = 5); // Ok +} + +} \ No newline at end of file diff --git a/clang/test/SemaCXX/warn-unused-value.cpp b/clang/test/SemaCXX/warn-unused-value.cpp index 4e1347c..3be2844 100644 --- a/clang/test/SemaCXX/warn-unused-value.cpp +++ b/clang/test/SemaCXX/warn-unused-value.cpp @@ -39,13 +39,13 @@ namespace test2 { void method() const { X* x; &x[0]; // expected-warning {{expression result unused}} - } + } }; typedef basic_string string; - void func(const std::string& str) { + void func(const std::string& str) { str.method(); // expected-note {{in instantiation of member function}} } - } + } } } @@ -69,3 +69,30 @@ void f() { Unused(1, 1); // expected-warning {{expression result unused}} } } + +namespace std { + struct type_info {}; +} + +namespace test4 { +struct Good { Good &f(); }; +struct Bad { virtual Bad& f(); }; + +void f() { + int i = 0; + (void)typeid(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}} + + Good g; + (void)typeid(g.f()); // Ok; not a polymorphic use of a glvalue. + + // This is a polymorphic use of a glvalue, which results in the typeid being + // evaluated instead of unevaluated. + Bad b; + (void)typeid(b.f()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} + + // A dereference of a volatile pointer is a side effecting operation, despite + // it being a reasonable operation. + int * volatile x; + (void)sizeof(*x); // expected-warning {{expression with side effects has no effect in an unevaluated context}} +} +} diff --git a/clang/test/SemaObjCXX/arc-ppe.mm b/clang/test/SemaObjCXX/arc-ppe.mm index c9ff811..193f273 100644 --- a/clang/test/SemaObjCXX/arc-ppe.mm +++ b/clang/test/SemaObjCXX/arc-ppe.mm @@ -13,4 +13,4 @@ void test1() { (void)typeid(NP((void*)(id*)0)); } class Poly { virtual ~Poly(); }; Poly& P(void*); -void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}} +void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}} expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} -- 2.7.4