On Wed, Jan 16, 2013 at 5:17 PM, Richard Smith <[email protected]> wrote: > Author: rsmith > Date: Wed Jan 16 19:17:56 2013 > New Revision: 172690 > > URL: http://llvm.org/viewvc/llvm-project?rev=172690&view=rev > Log: > Add -Wunsequenced (with compatibility alias -Wsequence-point) to warn on > expressions which have undefined behavior due to multiple unsequenced > modifications or an unsequenced modification and use of a variable.
I believe this resolves PR4579. (I've marked it resolved on your behalf) > Added: > cfe/trunk/test/SemaCXX/warn-unsequenced.cpp > Modified: > cfe/trunk/include/clang/AST/EvaluatedExprVisitor.h > cfe/trunk/include/clang/Basic/DiagnosticGroups.td > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/Sema/SemaChecking.cpp > cfe/trunk/lib/Sema/SemaDeclCXX.cpp > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/lib/Sema/SemaExprCXX.cpp > cfe/trunk/test/SemaCXX/altivec.cpp > > Modified: cfe/trunk/include/clang/AST/EvaluatedExprVisitor.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/EvaluatedExprVisitor.h?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/EvaluatedExprVisitor.h (original) > +++ cfe/trunk/include/clang/AST/EvaluatedExprVisitor.h Wed Jan 16 19:17:56 > 2013 > @@ -49,6 +49,9 @@ > } > > void VisitChooseExpr(ChooseExpr *E) { > + // Don't visit either child expression if the condition is dependent. > + if (E->getCond()->isValueDependent()) > + return; > // Only the selected subexpression matters; the other one is not > evaluated. > return this->Visit(E->getChosenSubExpr(Context)); > } > > Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Jan 16 19:17:56 2013 > @@ -198,7 +198,6 @@ > def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; > def Sentinel : DiagGroup<"sentinel">; > def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; > -def : DiagGroup<"sequence-point">; > def Shadow : DiagGroup<"shadow">; > def Shorten64To32 : DiagGroup<"shorten-64-to-32">; > def : DiagGroup<"sign-promo">; > @@ -218,6 +217,10 @@ > def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">; > def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">; > > +def Unsequenced : DiagGroup<"unsequenced">; > +// GCC name for -Wunsequenced > +def : DiagGroup<"sequence-point", [Unsequenced]>; > + > // Preprocessor warnings. > def AmbiguousMacro : DiagGroup<"ambiguous-macro">; > > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jan 16 19:17:56 > 2013 > @@ -1323,6 +1323,11 @@ > "is always %select{false|true}2">; > def err_init_incomplete_type : Error<"initialization of incomplete type %0">; > > +def warn_unsequenced_mod_mod : Warning< > + "multiple unsequenced modifications to %0">, InGroup<Unsequenced>; > +def warn_unsequenced_mod_use : Warning< > + "unsequenced modification and access to %0">, InGroup<Unsequenced>; > + > def err_temp_copy_no_viable : Error< > "no viable constructor %select{copying variable|copying parameter|" > "returning object|throwing object|copying member subobject|copying array " > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 16 19:17:56 2013 > @@ -7319,6 +7319,11 @@ > SourceLocation ReturnLoc); > void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); > void CheckImplicitConversions(Expr *E, SourceLocation CC = > SourceLocation()); > + void CheckUnsequencedOperations(Expr *E); > + > + /// \brief Perform semantic checks on a completed expression. This will > either > + /// be a full-expression or a default argument expression. > + void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = > SourceLocation()); > > void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, > Expr *Init); > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jan 16 19:17:56 2013 > @@ -5171,6 +5171,424 @@ > AnalyzeImplicitConversions(*this, E, CC); > } > > +namespace { > +/// \brief Visitor for expressions which looks for unsequenced operations on > the > +/// same object. > +class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { > + /// \brief A tree of sequenced regions within an expression. Two regions > are > + /// unsequenced if one is an ancestor or a descendent of the other. When we > + /// finish processing an expression with sequencing, such as a comma > + /// expression, we fold its tree nodes into its parent, since they are > + /// unsequenced with respect to nodes we will visit later. > + class SequenceTree { > + struct Value { > + explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {} > + unsigned Parent : 31; > + bool Merged : 1; > + }; > + llvm::SmallVector<Value, 8> Values; > + > + public: > + /// \brief A region within an expression which may be sequenced with > respect > + /// to some other region. > + class Seq { > + explicit Seq(unsigned N) : Index(N) {} > + unsigned Index; > + friend class SequenceTree; > + public: > + Seq() : Index(0) {} > + }; > + > + SequenceTree() { Values.push_back(Value(0)); } > + Seq root() const { return Seq(0); } > + > + /// \brief Create a new sequence of operations, which is an unsequenced > + /// subset of \p Parent. This sequence of operations is sequenced with > + /// respect to other children of \p Parent. > + Seq allocate(Seq Parent) { > + Values.push_back(Value(Parent.Index)); > + return Seq(Values.size() - 1); > + } > + > + /// \brief Merge a sequence of operations into its parent. > + void merge(Seq S) { > + Values[S.Index].Merged = true; > + } > + > + /// \brief Determine whether two operations are unsequenced. This > operation > + /// is asymmetric: \p Cur should be the more recent sequence, and \p Old > + /// should have been merged into its parent as appropriate. > + bool isUnsequenced(Seq Cur, Seq Old) { > + unsigned C = representative(Cur.Index); > + unsigned Target = representative(Old.Index); > + while (C >= Target) { > + if (C == Target) > + return true; > + C = Values[C].Parent; > + } > + return false; > + } > + > + private: > + /// \brief Pick a representative for a sequence. > + unsigned representative(unsigned K) { > + if (Values[K].Merged) > + // Perform path compression as we go. > + return Values[K].Parent = representative(Values[K].Parent); > + return K; > + } > + }; > + > + /// An object for which we can track unsequenced uses. > + typedef NamedDecl *Object; > + > + /// Different flavors of object usage which we track. We only track the > + /// least-sequenced usage of each kind. > + enum UsageKind { > + /// A read of an object. Multiple unsequenced reads are OK. > + UK_Use, > + /// A modification of an object which is sequenced before the value > + /// computation of the expression, such as ++n. > + UK_ModAsValue, > + /// A modification of an object which is not sequenced before the value > + /// computation of the expression, such as n++. > + UK_ModAsSideEffect, > + > + UK_Count = UK_ModAsSideEffect + 1 > + }; > + > + struct Usage { > + Usage() : Use(0), Seq() {} > + Expr *Use; > + SequenceTree::Seq Seq; > + }; > + > + struct UsageInfo { > + UsageInfo() : Diagnosed(false) {} > + Usage Uses[UK_Count]; > + /// Have we issued a diagnostic for this variable already? > + bool Diagnosed; > + }; > + typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap; > + > + Sema &SemaRef; > + /// Sequenced regions within the expression. > + SequenceTree Tree; > + /// Declaration modifications and references which we have seen. > + UsageInfoMap UsageMap; > + /// The region we are currently within. > + SequenceTree::Seq Region; > + /// Filled in with declarations which were modified as a side-effect > + /// (that is, post-increment operations). > + llvm::SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect; > + > + /// RAII object wrapping the visitation of a sequenced subexpression of an > + /// expression. At the end of this process, the side-effects of the > evaluation > + /// become sequenced with respect to the value computation of the result, > so > + /// we downgrade any UK_ModAsSideEffect within the evaluation to > + /// UK_ModAsValue. > + struct SequencedSubexpression { > + SequencedSubexpression(SequenceChecker &Self) > + : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) { > + Self.ModAsSideEffect = &ModAsSideEffect; > + } > + ~SequencedSubexpression() { > + for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) { > + UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first]; > + U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second; > + Self.addUsage(U, ModAsSideEffect[I].first, > + ModAsSideEffect[I].second.Use, UK_ModAsValue); > + } > + Self.ModAsSideEffect = OldModAsSideEffect; > + } > + > + SequenceChecker &Self; > + llvm::SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect; > + llvm::SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect; > + }; > + > + /// \brief Find the object which is produced by the specified expression, > + /// if any. > + Object getObject(Expr *E, bool Mod) const { > + E = E->IgnoreParenCasts(); > + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { > + if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == > UO_PreDec)) > + return getObject(UO->getSubExpr(), Mod); > + } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { > + if (BO->getOpcode() == BO_Comma) > + return getObject(BO->getRHS(), Mod); > + if (Mod && BO->isAssignmentOp()) > + return getObject(BO->getLHS(), Mod); > + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { > + // FIXME: Check for more interesting cases, like "x.n = ++x.n". > + if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts())) > + return ME->getMemberDecl(); > + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) > + // FIXME: If this is a reference, map through to its value. > + return DRE->getDecl(); > + return 0; > + } > + > + /// \brief Note that an object was modified or used by an expression. > + void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { > + Usage &U = UI.Uses[UK]; > + if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { > + if (UK == UK_ModAsSideEffect && ModAsSideEffect) > + ModAsSideEffect->push_back(std::make_pair(O, U)); > + U.Use = Ref; > + U.Seq = Region; > + } > + } > + /// \brief Check whether a modification or use conflicts with a prior > usage. > + void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, > + bool IsModMod) { > + if (UI.Diagnosed) > + return; > + > + const Usage &U = UI.Uses[OtherKind]; > + if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) > + return; > + > + Expr *Mod = U.Use; > + Expr *ModOrUse = Ref; > + if (OtherKind == UK_Use) > + std::swap(Mod, ModOrUse); > + > + SemaRef.Diag(Mod->getExprLoc(), > + IsModMod ? diag::warn_unsequenced_mod_mod > + : diag::warn_unsequenced_mod_use) > + << O << SourceRange(ModOrUse->getExprLoc()); > + UI.Diagnosed = true; > + } > + > + void notePreUse(Object O, Expr *Use) { > + UsageInfo &U = UsageMap[O]; > + // Uses conflict with other modifications. > + checkUsage(O, U, Use, UK_ModAsValue, false); > + } > + void notePostUse(Object O, Expr *Use) { > + UsageInfo &U = UsageMap[O]; > + checkUsage(O, U, Use, UK_ModAsSideEffect, false); > + addUsage(U, O, Use, UK_Use); > + } > + > + void notePreMod(Object O, Expr *Mod) { > + UsageInfo &U = UsageMap[O]; > + // Modifications conflict with other modifications and with uses. > + checkUsage(O, U, Mod, UK_ModAsValue, true); > + checkUsage(O, U, Mod, UK_Use, false); > + } > + void notePostMod(Object O, Expr *Use, UsageKind UK) { > + UsageInfo &U = UsageMap[O]; > + checkUsage(O, U, Use, UK_ModAsSideEffect, true); > + addUsage(U, O, Use, UK); > + } > + > +public: > + SequenceChecker(Sema &S, Expr *E) > + : EvaluatedExprVisitor(S.Context), SemaRef(S), Region(Tree.root()), > + ModAsSideEffect(0) { > + Visit(E); > + } > + > + void VisitStmt(Stmt *S) { > + // Skip all statements which aren't expressions for now. > + } > + > + void VisitExpr(Expr *E) { > + // By default, just recurse to evaluated subexpressions. > + EvaluatedExprVisitor::VisitStmt(E); > + } > + > + void VisitCastExpr(CastExpr *E) { > + Object O = Object(); > + if (E->getCastKind() == CK_LValueToRValue) > + O = getObject(E->getSubExpr(), false); > + > + if (O) > + notePreUse(O, E); > + VisitExpr(E); > + if (O) > + notePostUse(O, E); > + } > + > + void VisitBinComma(BinaryOperator *BO) { > + // C++11 [expr.comma]p1: > + // Every value computation and side effect associated with the left > + // expression is sequenced before every value computation and side > + // effect associated with the right expression. > + SequenceTree::Seq LHS = Tree.allocate(Region); > + SequenceTree::Seq RHS = Tree.allocate(Region); > + SequenceTree::Seq OldRegion = Region; > + > + { > + SequencedSubexpression SeqLHS(*this); > + Region = LHS; > + Visit(BO->getLHS()); > + } > + > + Region = RHS; > + Visit(BO->getRHS()); > + > + Region = OldRegion; > + > + // Forget that LHS and RHS are sequenced. They are both unsequenced > + // with respect to other stuff. > + Tree.merge(LHS); > + Tree.merge(RHS); > + } > + > + void VisitBinAssign(BinaryOperator *BO) { > + // The modification is sequenced after the value computation of the LHS > + // and RHS, so check it before inspecting the operands and update the > + // map afterwards. > + Object O = getObject(BO->getLHS(), true); > + if (!O) > + return VisitExpr(BO); > + > + notePreMod(O, BO); > + > + // C++11 [expr.ass]p7: > + // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is > evaluated > + // only once. > + // > + // Therefore, for a compound assignment operator, O is considered used > + // everywhere except within the evaluation of E1 itself. > + if (isa<CompoundAssignOperator>(BO)) > + notePreUse(O, BO); > + > + Visit(BO->getLHS()); > + > + if (isa<CompoundAssignOperator>(BO)) > + notePostUse(O, BO); > + > + Visit(BO->getRHS()); > + > + notePostMod(O, BO, UK_ModAsValue); > + } > + void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { > + VisitBinAssign(CAO); > + } > + > + void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } > + void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } > + void VisitUnaryPreIncDec(UnaryOperator *UO) { > + Object O = getObject(UO->getSubExpr(), true); > + if (!O) > + return VisitExpr(UO); > + > + notePreMod(O, UO); > + Visit(UO->getSubExpr()); > + notePostMod(O, UO, UK_ModAsValue); > + } > + > + void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } > + void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } > + void VisitUnaryPostIncDec(UnaryOperator *UO) { > + Object O = getObject(UO->getSubExpr(), true); > + if (!O) > + return VisitExpr(UO); > + > + notePreMod(O, UO); > + Visit(UO->getSubExpr()); > + notePostMod(O, UO, UK_ModAsSideEffect); > + } > + > + /// Don't visit the RHS of '&&' or '||' if it might not be evaluated. > + void VisitBinLOr(BinaryOperator *BO) { > + // The side-effects of the LHS of an '&&' are sequenced before the > + // value computation of the RHS, and hence before the value computation > + // of the '&&' itself, unless the LHS evaluates to zero. We treat them > + // as if they were unconditionally sequenced. > + { > + SequencedSubexpression Sequenced(*this); > + Visit(BO->getLHS()); > + } > + > + bool Result; > + if (!BO->getLHS()->isValueDependent() && > + BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context) && > + !Result) > + Visit(BO->getRHS()); > + } > + void VisitBinLAnd(BinaryOperator *BO) { > + { > + SequencedSubexpression Sequenced(*this); > + Visit(BO->getLHS()); > + } > + > + bool Result; > + if (!BO->getLHS()->isValueDependent() && > + BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context) && > + Result) > + Visit(BO->getRHS()); > + } > + > + // Only visit the condition, unless we can be sure which subexpression will > + // be chosen. > + void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) { > + SequencedSubexpression Sequenced(*this); > + Visit(CO->getCond()); > + > + bool Result; > + if (!CO->getCond()->isValueDependent() && > + CO->getCond()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) > + Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr()); > + } > + > + void VisitCXXConstructExpr(CXXConstructExpr *CCE) { > + if (!CCE->isListInitialization()) > + return VisitExpr(CCE); > + > + // In C++11, list initializations are sequenced. > + llvm::SmallVector<SequenceTree::Seq, 32> Elts; > + SequenceTree::Seq Parent = Region; > + for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(), > + E = CCE->arg_end(); > + I != E; ++I) { > + Region = Tree.allocate(Parent); > + Elts.push_back(Region); > + Visit(*I); > + } > + > + // Forget that the initializers are sequenced. > + Region = Parent; > + for (unsigned I = 0; I < Elts.size(); ++I) > + Tree.merge(Elts[I]); > + } > + > + void VisitInitListExpr(InitListExpr *ILE) { > + if (!SemaRef.getLangOpts().CPlusPlus11) > + return VisitExpr(ILE); > + > + // In C++11, list initializations are sequenced. > + llvm::SmallVector<SequenceTree::Seq, 32> Elts; > + SequenceTree::Seq Parent = Region; > + for (unsigned I = 0; I < ILE->getNumInits(); ++I) { > + Expr *E = ILE->getInit(I); > + if (!E) continue; > + Region = Tree.allocate(Parent); > + Elts.push_back(Region); > + Visit(E); > + } > + > + // Forget that the initializers are sequenced. > + Region = Parent; > + for (unsigned I = 0; I < Elts.size(); ++I) > + Tree.merge(Elts[I]); > + } > +}; > +} > + > +void Sema::CheckUnsequencedOperations(Expr *E) { > + SequenceChecker(*this, E); > +} > + > +void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc) { > + CheckImplicitConversions(E, CheckLoc); > + CheckUnsequencedOperations(E); > +} > + > void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, > FieldDecl *BitField, > Expr *Init) { > > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 16 19:17:56 2013 > @@ -252,7 +252,7 @@ > return true; > Arg = Result.takeAs<Expr>(); > > - CheckImplicitConversions(Arg, EqualLoc); > + CheckCompletedExpr(Arg, EqualLoc); > Arg = MaybeCreateExprWithCleanups(Arg); > > // Okay: add the default argument to the parameter > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 16 19:17:56 2013 > @@ -3534,7 +3534,7 @@ > return ExprError(); > > Expr *Arg = Result.takeAs<Expr>(); > - CheckImplicitConversions(Arg, Param->getOuterLocStart()); > + CheckCompletedExpr(Arg, Param->getOuterLocStart()); > // Build the default argument expression. > return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg)); > } > > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 16 19:17:56 2013 > @@ -18,6 +18,7 @@ > #include "clang/AST/CXXInheritance.h" > #include "clang/AST/CharUnits.h" > #include "clang/AST/DeclObjC.h" > +#include "clang/AST/EvaluatedExprVisitor.h" > #include "clang/AST/ExprCXX.h" > #include "clang/AST/ExprObjC.h" > #include "clang/AST/TypeLoc.h" > @@ -5496,7 +5497,7 @@ > return ExprError(); > } > > - CheckImplicitConversions(FullExpr.get(), CC); > + CheckCompletedExpr(FullExpr.get(), CC); > return MaybeCreateExprWithCleanups(FullExpr); > } > > > Modified: cfe/trunk/test/SemaCXX/altivec.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/altivec.cpp?rev=172690&r1=172689&r2=172690&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/altivec.cpp (original) > +++ cfe/trunk/test/SemaCXX/altivec.cpp Wed Jan 16 19:17:56 2013 > @@ -62,7 +62,7 @@ > vector float vf; > vf++; > > - ++vi=vi; > + ++vi=vi; // expected-warning {{unsequenced}} > (++vi)[1]=1; > template_f(vi); > } > > Added: cfe/trunk/test/SemaCXX/warn-unsequenced.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unsequenced.cpp?rev=172690&view=auto > ============================================================================== > --- cfe/trunk/test/SemaCXX/warn-unsequenced.cpp (added) > +++ cfe/trunk/test/SemaCXX/warn-unsequenced.cpp Wed Jan 16 19:17:56 2013 > @@ -0,0 +1,91 @@ > +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-unused %s > + > +int f(int, int); > + > +struct A { > + int x, y; > +}; > +struct S { > + S(int, int); > +}; > + > +void test() { > + int a; > + int xs[10]; > + ++a = 0; // ok > + a + ++a; // expected-warning {{unsequenced modification and access to 'a'}} > + a = ++a; // ok > + a + a++; // expected-warning {{unsequenced modification and access to 'a'}} > + a = a++; // expected-warning {{multiple unsequenced modifications to 'a'}} > + ++ ++a; // ok > + (a++, a++); // ok > + ++a + ++a; // expected-warning {{multiple unsequenced modifications to > 'a'}} > + a++ + a++; // expected-warning {{multiple unsequenced modifications}} > + (a++, a) = 0; // ok, increment is sequenced before value computation of LHS > + a = xs[++a]; // ok > + a = xs[a++]; // expected-warning {{multiple unsequenced modifications}} > + (a ? xs[0] : xs[1]) = ++a; // expected-warning {{unsequenced modification > and access}} > + a = (++a, ++a); // ok > + a = (a++, ++a); // ok > + a = (a++, a++); // expected-warning {{multiple unsequenced modifications}} > + f(a, a); // ok > + f(a = 0, a); // expected-warning {{unsequenced modification and access}} > + f(a, a += 0); // expected-warning {{unsequenced modification and access}} > + f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}} > + > + // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that > A > + // is evaluated only once. > + (++a, a) = 1; // ok > + (++a, a) += 1; // ok > + a = ++a; // ok > + a += ++a; // expected-warning {{unsequenced modification and access}} > + > + A agg1 = { a++, a++ }; // ok > + A agg2 = { a++ + a, a++ }; // expected-warning {{unsequenced modification > and access}} > + > + S str1(a++, a++); // expected-warning {{multiple unsequenced > modifications}} > + S str2 = { a++, a++ }; // ok > + S str3 = { a++ + a, a++ }; // expected-warning {{unsequenced modification > and access}} > + > + (xs[2] && (a = 0)) + a; // ok > + (0 && (a = 0)) + a; // ok > + (1 && (a = 0)) + a; // expected-warning {{unsequenced modification and > access}} > + > + (xs[3] || (a = 0)) + a; // ok > + (0 || (a = 0)) + a; // expected-warning {{unsequenced modification and > access}} > + (1 || (a = 0)) + a; // ok > + > + (xs[4] ? a : ++a) + a; // ok > + (0 ? a : ++a) + a; // expected-warning {{unsequenced modification and > access}} > + (1 ? a : ++a) + a; // ok > + (xs[5] ? ++a : ++a) + a; // FIXME: warn here > + > + (++a, xs[6] ? ++a : 0) + a; // expected-warning {{unsequenced modification > and access}} > + > + // Here, the read of the fourth 'a' might happen before or after the write > to > + // the second 'a'. > + a += (a++, a) + a; // expected-warning {{unsequenced modification and > access}} > + > + int *p = xs; > + a = *(a++, p); // ok > + a = a++ && a; // ok > + > + A *q = &agg1; > + (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and > access to 'q'}} > + > + // This has undefined behavior if a == 0; otherwise, the side-effect of the > + // increment is sequenced before the value computation of 'f(a, a)', which > is > + // sequenced before the value computation of the '&&', which is sequenced > + // before the assignment. We treat the sequencing in '&&' as being > + // unconditional. > + a = a++ && f(a, a); > + > + // This has undefined behavior if a != 0. FIXME: We should diagnose this. > + (a && a++) + a; > + > + (xs[7] && ++a) * (!xs[7] && ++a); // ok > + > + xs[0] = (a = 1, a); // ok > + (a -= 128) &= 128; // ok > + ++a += 1; // ok > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
