Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6953,6 +6953,44 @@ def warn_omp_linear_step_zero : Warning< "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">, InGroup; +def err_omp_loop_var_dsa : Error< + "loop iteration variable may not be %0">; +def err_omp_loop_not_canonical_init : Error< + "initialization of the openmp loop should be assignment to " + "(or definition of) the loop variable">; +def err_omp_loop_not_canonical_init_empty : Error< + "initialization of the openmp loop should be non-empty">; +def err_omp_loop_not_canonical_init_var : Error< + "expected variable in the initialization of the openmp loop">; +def err_omp_loop_not_canonical_init_var_init : Error< + "declaration of the loop variable should have initialization">; +def err_omp_loop_not_canonical_init_var_not_single : Error< + "expected exactly one variable in the initialization of the openmp loop">; +def err_omp_loop_not_canonical_init_many_ctor_params : Error< + "too many arguments to the constructor in canonical loop initialization">; +def err_omp_loop_not_canonical_cond_rel : Error< + "condition of the openmp loop should be relational operator">; +def err_omp_loop_not_canonical_cond_rel_var : Error< + "relation in the condition of the openmp loop should refer to the loop variable (%0)">; +def err_omp_loop_not_canonical_incr_empty : Error< + "increment of the openmp loop is empty">; +def err_omp_loop_not_canonical_incr : Error< + "expected increment or decrement of the loop variable by some loop-invariant step">; +def err_omp_loop_incr_expected_var : Error< + "expected loop variable (%0) in the openmp loop increment">; +def err_omp_loop_variable_type : Error< + "variable must be of integer or %select{pointer|random access iterator}0 type">; +def err_omp_loop_incr_not_integer : Error< + "increment expression of for loop must be of an integer type">; +def err_omp_loop_incr_not_compatible : Error< + "increment expression must cause %0 to %select{decrease|increase}1 " + "on each iteration of the loop">; +def note_omp_loop_cond_requres_compatible_incr : Note< + "loop step is expected to be %select{negative|positive}0 due to this condition">; +def err_omp_loop_cannot_break: Error< + "cannot break from a '#pragma omp %0' loop">; +def err_omp_loop_cannot_have_eh: Error< + "exception handling constructs are not allowed in a '#pragma omp %0' loop">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7243,10 +7243,13 @@ /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); - ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind); + /// \brief Return true if the given type is pointer or other random access + /// iterator (currently only std's iterators are allowed here). + bool IsRandomAccessIteratorType(QualType Ty, SourceLocation Loc); public: + ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, @@ -7289,7 +7292,12 @@ Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - + /// \brief Called on a for stmt to check and extract its iteration space + /// for further processing (such as collapsing). + bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S); + /// \brief Called on a for stmt to check itself and nested loops (if any). + bool CheckOpenMPLoop(OpenMPDirectiveKind DKind, unsigned NestedLoopCount, + Stmt *AStmt); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -770,27 +770,721 @@ Clauses, AStmt)); } +namespace { +/// \brief Helper class for checking canonical form of the OpenMP loops and +/// extracting iteration space of each loop in the loop nest, that will be used +/// for IR generation. +class OpenMPIterationSpaceChecker { + /// \brief Reference to Sema. + Sema &Actions; + /// \brief A location for diagnostics (when there is no some better location). + SourceLocation DefaultLoc; + /// \brief A location for diagnostics (when increment is not compatible). + SourceLocation ConditionLoc; + /// \brief A source location for referring to condition later. + SourceRange ConditionSrcRange; + /// \brief Loop variable. + VarDecl *Var; + /// \brief Lower bound (initializer for the var). + Expr *LB; + /// \brief Upper bound. + Expr *UB; + /// \brief Loop step (increment). + Expr *Step; + /// \brief This flag is true when condition is one of: + /// Var < UB + /// Var <= UB + /// UB > Var + /// UB >= Var + bool TestIsLessOp; + /// \brief This flag is true when condition is strict ( < or > ). + bool TestIsStrictOp; + /// \brief This flag requires to subtract the step instead of adding it. + bool SubtractStep; + +public: + OpenMPIterationSpaceChecker(Sema &A, SourceLocation DefaultLoc) + : Actions(A), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), + ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr), + UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false), + SubtractStep(false) {} + /// \brief Check init-expr for canonical loop form and save loop counter + /// variable - 'var' and its initialization value - 'lb'. + bool CheckInit(Stmt *S); + /// \brief Check test-expr for canonical form, save upper-bound, flags for + /// less/greater and for strict/non-strict comparison. + bool CheckCond(Expr *S); + /// \brief Check incr-expr for canonical loop form and return true if it + /// does not conform. + bool CheckInc(Expr *S); + /// \brief Return the loop counter variable. + VarDecl *GetLoopVar() const { return Var; } + /// \brief Return true if any expression is dependent. + bool Dependent() const; + +private: + /// \brief Check right-hand side of the increment expression. + bool CheckIncRHS(Expr *RHS); + /// \brief Helper to set loop counter variable and its initializer. + bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB); + /// \brief Helper to set upper bound. + bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR, + const SourceLocation &SL); + /// \brief Helper to set loop increment (step). + bool SetStep(Expr *NewStep, bool Subtract); +}; + +bool OpenMPIterationSpaceChecker::Dependent() const { + if (!Var) { + assert(!LB && !UB && !Step); + return false; + } + QualType VarType = Var->getType() + .getNonReferenceType() + .getCanonicalType() + .getUnqualifiedType(); + if (VarType->isDependentType()) + return true; + if (LB && + (LB->isTypeDependent() || LB->isValueDependent() || + LB->isInstantiationDependent() || LB->containsUnexpandedParameterPack())) + return true; + if (UB && + (UB->isTypeDependent() || UB->isValueDependent() || + UB->isInstantiationDependent() || UB->containsUnexpandedParameterPack())) + return true; + if (UB && + (UB->isTypeDependent() || UB->isValueDependent() || + UB->isInstantiationDependent() || UB->containsUnexpandedParameterPack())) + return true; + return false; +} + +bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) { + // State consistency checking to ensure correct usage. + assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr && + !TestIsLessOp && !TestIsStrictOp); + if (!NewVar || !NewLB) + return true; + Var = NewVar; + LB = NewLB; + return false; +} + +bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, + const SourceRange &SR, + const SourceLocation &SL) { + // State consistency checking to ensure correct usage. + assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && + !TestIsLessOp && !TestIsStrictOp); + if (!NewUB) + return true; + UB = NewUB; + TestIsLessOp = LessOp; + TestIsStrictOp = StrictOp; + ConditionSrcRange = SR; + ConditionLoc = SL; + return false; +} + +bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { + // State consistency checking to ensure correct usage. + assert(Var != nullptr && LB != nullptr && Step == nullptr); + if (!NewStep) + return true; + if (!NewStep->isValueDependent() && !NewStep->isTypeDependent() && + !NewStep->isInstantiationDependent() && + !NewStep->containsUnexpandedParameterPack()) { + + // Check that the step is integer expression. + SourceLocation StepLoc = NewStep->getLocStart(); + ExprResult Val = Actions.PerformImplicitIntegerConversion(StepLoc, NewStep); + if (!Val.isInvalid()) + NewStep = Val.take(); + else { + Actions.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_integer); + return true; + } + + // OpenMP [2.6, Canonical Loop Form, Restrictions] + // If test-expr is of form var relational-op b and relational-op is < or + // <= then incr-expr must cause var to increase on each iteration of the + // loop. If test-expr is of form var relational-op b and relational-op is + // > or >= then incr-expr must cause var to decrease on each iteration of + // the loop. + // If test-expr is of form b relational-op var and relational-op is < or + // <= then incr-expr must cause var to decrease on each iteration of the + // loop. If test-expr is of form b relational-op var and relational-op is + // > or >= then incr-expr must cause var to increase on each iteration of + // the loop. + llvm::APSInt Result; + bool IsConstant = NewStep->isIntegerConstantExpr(Result, Actions.Context); + bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation(); + bool IsConstNeg = + IsConstant && Result.isSigned() && (Subtract != Result.isNegative()); + bool IsConstZero = IsConstant && !Result.getBoolValue(); + if (UB && (IsConstZero || + (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract)) + : (!IsConstNeg || (IsUnsigned && !Subtract))))) { + Actions.Diag(NewStep->getExprLoc(), + diag::err_omp_loop_incr_not_compatible) + << Var << TestIsLessOp << NewStep->getSourceRange(); + Actions.Diag(ConditionLoc, + diag::note_omp_loop_cond_requres_compatible_incr) + << TestIsLessOp << ConditionSrcRange; + return true; + } + } + + Step = NewStep; + SubtractStep = Subtract; + return false; +} + +bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { + // Check init-expr for canonical loop form and save loop counter + // variable - 'var' and its initialization value - 'lb'. + // OpenMP [2.6] Canonical loop form. init-expr may be one of the following: + // var = lb + // integer-type var = lb + // random-access-iterator-type var = lb + // pointer-type var = lb + // + if (!S) { + Actions.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init_empty); + return true; + } + if (Expr *E = dyn_cast(S)) + S = E->IgnoreParens(); + SourceLocation InitLoc = S->getLocStart(); + if (auto BO = dyn_cast(S)) { + if (BO->getOpcode() != BO_Assign) { + Actions.Diag(InitLoc, diag::err_omp_loop_not_canonical_init) + << BO->getSourceRange(); + return true; + } + auto DRE = dyn_cast(BO->getLHS()->IgnoreParens()); + if (!DRE) { + Actions.Diag(InitLoc, diag::err_omp_loop_not_canonical_init_var) + << BO->getRHS()->getSourceRange(); + return true; + } + return SetVarAndLB(dyn_cast(DRE->getDecl()), BO->getLHS()); + } + if (auto DS = dyn_cast(S)) { + if (!DS->isSingleDecl()) { + Actions.Diag(InitLoc, + diag::err_omp_loop_not_canonical_init_var_not_single) + << DS->getSourceRange(); + return true; + } + if (auto Var = dyn_cast_or_null(DS->getSingleDecl())) { + if (!Var->hasInit()) { + Actions.Diag(InitLoc, diag::err_omp_loop_not_canonical_init_var_init) + << DS->getSourceRange(); + return true; + } + if (auto Init = dyn_cast(Var->getInit())) { + if (Init->getNumArgs() != 1) { + Actions.Diag(InitLoc, + diag::err_omp_loop_not_canonical_init_many_ctor_params) + << DS->getSourceRange(); + return true; + } + return SetVarAndLB(Var, Init->getArg(0)); + } + return SetVarAndLB(Var, Var->getInit()); + } + Actions.Diag(InitLoc, diag::err_omp_loop_not_canonical_init_var) + << DS->getSourceRange(); + return true; + } + if (auto CE = dyn_cast(S)) { + if (CE->getOperator() == OO_Equal) { + if (auto DRE = dyn_cast(CE->getArg(0))) { + return SetVarAndLB(dyn_cast(DRE->getDecl()), CE->getArg(1)); + } + } + } + Actions.Diag(InitLoc, diag::err_omp_loop_not_canonical_init); + return true; +} + +/// \brief Ignore parenthesises, implicit casts, copy constructor and return the +/// variable (which may be loop variable) if possible. +static const VarDecl *GetInitVarDecl(const Expr *E) { + if (!E) + return 0; + E = E->IgnoreParenImpCasts(); + if (auto *CE = dyn_cast_or_null(E)) + if (const CXXConstructorDecl *Ctor = CE->getConstructor()) + if (Ctor->isCopyConstructor() && CE->getNumArgs() == 1 && + CE->getArg(0) != nullptr) + E = CE->getArg(0)->IgnoreParenImpCasts(); + auto DRE = dyn_cast_or_null(E); + if (!DRE) + return nullptr; + return dyn_cast(DRE->getDecl()); +} + +bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { + // Check test-expr for canonical form, save upper-bound UB, flags for + // less/greater and for strict/non-strict comparison. + // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: + // var relational-op b + // b relational-op var + // + if (!S) { + Actions.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond_rel); + return true; + } + S = S->IgnoreParenImpCasts(); + SourceLocation CondLoc = S->getLocStart(); + if (auto BO = dyn_cast(S)) { + if (!BO->isRelationalOp()) { + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel) + << BO->getSourceRange(); + return true; + } + if (GetInitVarDecl(BO->getLHS()) == Var) + return SetUB(BO->getRHS(), + (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), + (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), + BO->getSourceRange(), BO->getOperatorLoc()); + if (GetInitVarDecl(BO->getRHS()) == Var) + return SetUB(BO->getLHS(), + (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), + (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), + BO->getSourceRange(), BO->getOperatorLoc()); + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel_var) + << BO->getSourceRange() << Var; + return true; + } + if (auto CE = dyn_cast(S)) { + if (CE->getNumArgs() != 2) { + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel) + << CE->getSourceRange(); + return true; + } + auto Op = CE->getOperator(); + switch (Op) { + case OO_Greater: + case OO_GreaterEqual: + case OO_Less: + case OO_LessEqual: + break; + default: + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel) + << CE->getSourceRange(); + return true; + } + if (GetInitVarDecl(CE->getArg(0)) == Var) + return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, + Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), + CE->getOperatorLoc()); + if (GetInitVarDecl(CE->getArg(1)) == Var) + return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, + Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), + CE->getOperatorLoc()); + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel_var) + << CE->getSourceRange() << Var; + return true; + } + Actions.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond_rel) + << S->getSourceRange(); + return true; +} + +bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { + // RHS of canonical loop form increment can be: + // var + incr + // incr + var + // var - incr + // + RHS = RHS->IgnoreParenImpCasts(); + if (auto BO = dyn_cast(RHS)) { + if (!BO->isAdditiveOp()) { + Actions.Diag(BO->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << BO->getSourceRange(); + return true; + } + bool IsIncrement = BO->getOpcode() == BO_Add; + if (GetInitVarDecl(BO->getLHS()) == Var) + return SetStep(BO->getRHS(), !IsIncrement); + if (IsIncrement && GetInitVarDecl(BO->getRHS()) == Var) + return SetStep(BO->getLHS(), false); + } else if (auto CE = dyn_cast(RHS)) { + bool IsIncrement = CE->getOperator() == OO_Plus; + if (!IsIncrement && CE->getOperator() != OO_Minus) { + Actions.Diag(CE->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << CE->getSourceRange(); + return true; + } + assert(CE->getNumArgs() == 2); + if (GetInitVarDecl(CE->getArg(0)) == Var) + return SetStep(CE->getArg(1), !IsIncrement); + if (IsIncrement && GetInitVarDecl(CE->getArg(1)) == Var) + return SetStep(CE->getArg(0), false); + } + Actions.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << RHS->getSourceRange(); + return true; +} + +bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { + // Check incr-expr for canonical loop form and return true if it + // does not conform. + // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: + // ++var + // var++ + // --var + // var-- + // var += incr + // var -= incr + // var = var + incr + // var = incr + var + // var = var - incr + // + if (!S) { + Actions.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr_empty); + return true; + } + S = S->IgnoreParens(); + if (auto UO = dyn_cast(S)) { + if (!UO->isIncrementDecrementOp()) { + Actions.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) + << UO->getSourceRange(); + return true; + } + if (GetInitVarDecl(UO->getSubExpr()) != Var) { + Expr *SubExpr = UO->getSubExpr(); + Actions.Diag(SubExpr->getLocStart(), diag::err_omp_loop_incr_expected_var) + << SubExpr->getSourceRange() << Var; + return true; + } + Expr *One = + Actions.ActOnIntegerConstant(UO->getLocStart(), + (UO->isDecrementOp() ? -1 : 1)).take(); + return SetStep(One, false); + } else if (auto BO = dyn_cast(S)) { + switch (BO->getOpcode()) { + case BO_AddAssign: + case BO_SubAssign: + if (GetInitVarDecl(BO->getLHS()) != Var) { + Actions.Diag(BO->getLHS()->getLocStart(), + diag::err_omp_loop_incr_expected_var) + << BO->getLHS()->getSourceRange() << Var; + return true; + } + return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); + case BO_Assign: + if (GetInitVarDecl(BO->getLHS()) != Var) { + Actions.Diag(BO->getLHS()->getLocStart(), + diag::err_omp_loop_incr_expected_var) + << BO->getLHS()->getSourceRange() << Var; + return true; + } + return CheckIncRHS(BO->getRHS()); + default: + break; + } + } else if (auto CE = dyn_cast(S)) { + switch (CE->getOperator()) { + case OO_PlusPlus: + case OO_MinusMinus: + if (GetInitVarDecl(CE->getArg(0)) == Var) { + Expr *One = + Actions.ActOnIntegerConstant( + CE->getLocStart(), + ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).take(); + return SetStep(One, false); + } + break; + case OO_PlusEqual: + case OO_MinusEqual: + if (GetInitVarDecl(CE->getArg(0)) == Var) + return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); + break; + case OO_Equal: + if (GetInitVarDecl(CE->getArg(0)) == Var) + return CheckIncRHS(CE->getArg(1)); + break; + default: + break; + } + } + Actions.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << S->getSourceRange(); + return true; +} +} + +/// \brief Return true if the given type is pointer or other random access +/// iterator (currently only std-compatible iterators are allowed here). +bool Sema::IsRandomAccessIteratorType(QualType Ty, SourceLocation Loc) { + if (Ty->isPointerType()) + return true; + if (!getLangOpts().CPlusPlus || !Ty->isOverloadableType()) + return false; + // Check that var type is a random access iterator, i.e. we can apply + // 'std::distance' to the init and test arguments of the for-loop. + CXXScopeSpec StdScopeSpec; + StdScopeSpec.Extend(Context, getOrCreateStdNamespace(), SourceLocation(), + SourceLocation()); + + TemplateDecl *TIT = nullptr; + { + DeclarationNameInfo DNI(&Context.Idents.get("iterator_traits"), + SourceLocation()); + LookupResult LR(*this, DNI, LookupNestedNameSpecifierName); + if (!LookupParsedName(LR, DSAStack->getCurScope(), &StdScopeSpec) || + !LR.isSingleResult() || !(TIT = LR.getAsSingle())) + return false; + } + + CXXRecordDecl *IT = nullptr; + { + TemplateArgumentListInfo Args; + TemplateArgument Arg(Ty); + TemplateArgumentLoc ArgLoc(Arg, Context.CreateTypeSourceInfo(Ty)); + Args.addArgument(ArgLoc); + QualType T = CheckTemplateIdType(TemplateName(TIT), SourceLocation(), Args); + if (T.isNull() || RequireCompleteType(Loc, T, 0) || + !(IT = T->getAsCXXRecordDecl())) + return false; + } + + TypeDecl *RAI = nullptr; + { + DeclarationNameInfo DNI(&Context.Idents.get("random_access_iterator_tag"), + SourceLocation()); + LookupResult LR(*this, DNI, LookupOrdinaryName); + CXXRecordDecl *RDType = Ty->getAsCXXRecordDecl(); + if (!LookupParsedName(LR, DSAStack->getCurScope(), &StdScopeSpec) || + !LR.isSingleResult() || !(RAI = LR.getAsSingle()) || !RDType) + return false; + } + + TypeDecl *IC = nullptr; + { + DeclarationNameInfo DNI(&Context.Idents.get("iterator_category"), + SourceLocation()); + LookupResult LR(*this, DNI, LookupOrdinaryName); + if (!LookupQualifiedName(LR, IT) || !LR.isSingleResult() || + !(IC = LR.getAsSingle()) || + !Context.hasSameType(Context.getTypeDeclType(RAI), + Context.getTypeDeclType(IC))) + return false; + } + + return true; +} + +bool Sema::CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S) { + // OpenMP [2.6, Canonical Loop Form] + // for (init-expr; test-expr; incr-expr) structured-block + auto For = dyn_cast_or_null(S); + if (!For) { + Diag(S->getLocStart(), diag::err_omp_not_for) + << getOpenMPDirectiveName(DKind); + return true; + } + assert(For->getBody()); + + OpenMPIterationSpaceChecker ISC(*this, For->getForLoc()); + + // Check init. + Stmt *Init = For->getInit(); + if (ISC.CheckInit(Init)) { + return true; + } + + bool HasErrors = false; + + // Check loop variable's type. + VarDecl *Var = ISC.GetLoopVar(); + + // OpenMP [2.6, Canonical Loop Form] + // Var is one of the following: + // A variable of signed or unsigned integer type. + // For C++, a variable of a random access iterator type. + // For C, a variable of a pointer type. + QualType VarType = Var->getType() + .getNonReferenceType() + .getCanonicalType() + .getUnqualifiedType(); + if (!VarType->isDependentType() && !VarType->isIntegerType() && + !IsRandomAccessIteratorType(VarType, Init->getLocStart())) { + Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) + << getLangOpts().CPlusPlus; + HasErrors = true; + } + + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in + // a Construct, C/C++]. + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(Var); + if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_linear && + DVar.CKind != OMPC_threadprivate) { + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop may be listed in a linear + // clause with a constant-linear-step that is the increment of the + // associated for-loop. + // FIXME: allow OMPC_lastprivate when it is ready. + assert(DKind == OMPD_simd && "DSA for non-simd loop vars"); + Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind); + if (DVar.RefExpr) + Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(DVar.CKind); + else + Diag(Var->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(DVar.CKind); + HasErrors = true; + } else { + // Make the loop iteration variable private by default. + DSAStack->addDSA(Var, nullptr, OMPC_private); + } + + // Check test-expr. + HasErrors |= ISC.CheckCond(For->getCond()); + + // Check incr-expr. + HasErrors |= ISC.CheckInc(For->getInc()); + + if (ISC.Dependent()) + return false; + + return HasErrors; +} + +static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) { + if (IgnoreCaptured) { + while (auto CapS = dyn_cast_or_null(S)) + S = CapS->getCapturedStmt(); + } + while (true) { + if (auto AS = dyn_cast_or_null(S)) + S = AS->getSubStmt(); + else if (auto CS = dyn_cast_or_null(S)) { + if (CS->size() != 1) + break; + S = CS->body_back(); + } else + break; + } + return S; +} + +namespace { +/// \brief Checker for break stmt absense. +class ForBreakStmtChecker : public StmtVisitor { + llvm::SmallVector BreakStmts; + +public: + bool VisitBreakStmt(BreakStmt *S) { + BreakStmts.push_back(S); + return true; + } + // Do not go into nested loops. + bool VisitSwitchStmt(SwitchStmt *S) { return false; } + bool VisitWhileStmt(WhileStmt *S) { return false; } + bool VisitDoStmt(DoStmt *S) { return false; } + bool VisitForStmt(ForStmt *S) { return false; } + bool VisitCXXForRangeStmt(CXXForRangeStmt *S) { return false; } + + bool VisitStmt(Stmt *S) { + bool SeenBreak = false; + for (auto I : S->children()) + SeenBreak |= (I && Visit(I)); + return SeenBreak; + } + ForBreakStmtChecker() {} + llvm::SmallVector &getBreakStmts() { return BreakStmts; } +}; + +/// \brief Checker for EH throw/try/catch stmt absense. +class EhChecker : public StmtVisitor { + llvm::SmallVector EhStmts; + +public: + bool VisitCXXCatchStmt(CXXCatchStmt *S) { + EhStmts.push_back(S); + VisitStmt(S); + return true; + } + bool VisitCXXThrowExpr(CXXThrowExpr *S) { + EhStmts.push_back(S); + return true; + } + bool VisitCXXTryStmt(CXXTryStmt *S) { + EhStmts.push_back(S); + VisitStmt(S); + return true; + } + bool VisitStmt(Stmt *S) { + bool SeenEh = false; + for (auto I : S->children()) + SeenEh |= (I && Visit(I)); + return SeenEh; + } + EhChecker() {} + llvm::SmallVector getEhStmts() { return EhStmts; } +}; +} + +bool Sema::CheckOpenMPLoop(OpenMPDirectiveKind DKind, unsigned NestedLoopCount, + Stmt *AStmt) { + // This is helper routine for loop directives (e.g., 'for', 'simd', + // 'for simd', etc.). + assert(NestedLoopCount == 1); + Stmt *CurStmt = IgnoreContainerStmts(AStmt, true); + for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { + if (CheckOpenMPIterationSpace(DKind, CurStmt)) + return true; + // Move on to the next nested for loop, or to the loop body. + CurStmt = IgnoreContainerStmts(cast(CurStmt)->getBody(), false); + } + + // Perform conformance checks of the loop body. + ForBreakStmtChecker BreakCheck; + if (CurStmt && BreakCheck.Visit(CurStmt)) { + for (auto Break : BreakCheck.getBreakStmts()) + Diag(Break->getLocStart(), diag::err_omp_loop_cannot_break) + << getOpenMPDirectiveName(DKind); + return true; + } + + if (DKind == OMPD_simd) { + // OpenMP [2.8.1] No exception can be raised in the simd region. + EhChecker EhCheck; + if (CurStmt && EhCheck.Visit(CurStmt)) { + for (auto EhStmt : EhCheck.getEhStmts()) + Diag(EhStmt->getLocStart(), diag::err_omp_loop_cannot_have_eh) + << getOpenMPDirectiveName(DKind); + return true; + } + } + + // FIXME: Build resulting iteration space for IR generation (collapsing + // iteration spaces when loop count > 1 ('collapse' clause)). + return false; +} + StmtResult Sema::ActOnOpenMPSimdDirective(ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - Stmt *CStmt = AStmt; - while (CapturedStmt *CS = dyn_cast_or_null(CStmt)) - CStmt = CS->getCapturedStmt(); - while (AttributedStmt *AS = dyn_cast_or_null(CStmt)) - CStmt = AS->getSubStmt(); - ForStmt *For = dyn_cast(CStmt); - if (!For) { - Diag(CStmt->getLocStart(), diag::err_omp_not_for) - << getOpenMPDirectiveName(OMPD_simd); + + // In presence of clause 'collapse', it will define the nested loops number. + // For now, pass default value of 1. + if (CheckOpenMPLoop(OMPD_simd, 1, AStmt)) { return StmtError(); } - // FIXME: Checking loop canonical form, collapsing etc. - getCurFunction()->setHasBranchProtectedScope(); - return Owned(OMPSimdDirective::Create(Context, StartLoc, EndLoc, - Clauses, AStmt)); + return Owned( + OMPSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); } OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Index: test/OpenMP/simd_loop_messages.cpp =================================================================== --- test/OpenMP/simd_loop_messages.cpp +++ test/OpenMP/simd_loop_messages.cpp @@ -0,0 +1,556 @@ +// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s + +static int sii; +#pragma omp threadprivate(sii) + +int test_iteration_spaces() { + const int N = 100; + float a[N], b[N], c[N]; + int ii, jj, kk; + float fii; + double dii; + #pragma omp simd + for (int i = 0; i < 10; i+=1) { + c[i] = a[i] + b[i]; + } + #pragma omp simd + for (char i = 0; i < 10; i++) { + c[i] = a[i] + b[i]; + } + #pragma omp simd + for (char i = 0; i < 10; i+='\1') { + c[i] = a[i] + b[i]; + } + #pragma omp simd + for (long long i = 0; i < 10; i++) { + c[i] = a[i] + b[i]; + } + // expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}} + #pragma omp simd + for (long long i = 0; i < 10; i+=1.5) { + c[i] = a[i] + b[i]; + } + #pragma omp simd + for (long long i = 0; i < 'z'; i+=1u) { + c[i] = a[i] + b[i]; + } + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (float fi = 0; fi < 10.0; fi++) { + c[(int)fi] = a[(int)fi] + b[(int)fi]; + } + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (double fi = 0; fi < 10.0; fi++) { + c[(int)fi] = a[(int)fi] + b[(int)fi]; + } + // expected-error@+2 {{declaration of the loop variable should have initialization}} + #pragma omp simd + for (int i; i < 10; i++) + c[i] = a[i]; + + // expected-error@+2 {{expected exactly one variable in the initialization of the openmp loop}} + #pragma omp simd + for (int i = 0, j = 0; i < 10; ++i) + c[i] = a[i]; + + // expected-error@+2 {{initialization of the openmp loop should be non-empty}} + #pragma omp simd + for (;ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-warning@+3 {{expression result unused}} + // expected-error@+2 {{initialization of the openmp loop should be assignment to (or definition of) the loop variable}} + #pragma omp simd + for (ii + 1;ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-error@+2 {{expected variable in the initialization of the openmp loop}} + #pragma omp simd + for (c[ii] = 0;ii < 10; ++ii) + c[ii] = a[ii]; + + // Ok to skip parenthesises. + #pragma omp simd + for (((ii)) = 0;ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (int i = 0; i; i++) + c[i] = a[i]; + + // expected-error@+3 {{relation in the condition of the openmp loop should refer to the loop variable ('i')}} + // expected-error@+2 {{expected loop variable ('i') in the openmp loop increment}} + #pragma omp simd + for (int i = 0; jj < kk; ii++) + c[i] = a[i]; + + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (int i = 0; !!i; i++) + c[i] = a[i]; + + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (int i = 0; i != 1; i++) + c[i] = a[i]; + + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (int i = 0; ; i++) + c[i] = a[i]; + + // Ok. + #pragma omp simd + for (int i = 11; i > 10; i--) + c[i] = a[i]; + + // Ok. + #pragma omp simd + for (int i = 0; i < 10; ++i) + c[i] = a[i]; + + // Ok. + #pragma omp simd + for (ii = 0; ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-error@+2 {{expected loop variable ('ii') in the openmp loop increment}} + #pragma omp simd + for (ii = 0; ii < 10; ++jj) + c[ii] = a[jj]; + + // expected-error@+2 {{expected loop variable ('ii') in the openmp loop increment}} + #pragma omp simd + for (ii = 0; ii < 10; ++ ++ ii) + c[ii] = a[ii]; + + // Ok but undefined behavior (in general, cannot check that incr + // is really loop-invariant). + #pragma omp simd + for (ii = 0; ii < 10; ii = ii + ii) + c[ii] = a[ii]; + + // expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}} + #pragma omp simd + for (ii = 0; ii < 10; ii = ii + 1.0f) + c[ii] = a[ii]; + + // Ok - step was converted to integer type. + #pragma omp simd + for (ii = 0; ii < 10; ii = ii + (int)1.1f) + c[ii] = a[ii]; + + // expected-error@+2 {{expected loop variable ('ii') in the openmp loop increment}} + #pragma omp simd + for (ii = 0; ii < 10; jj = ii + 2) + c[ii] = a[ii]; + + // expected-warning@+3 {{relational comparison result unused}} + // expected-error@+2 {{expected increment or decrement of the loop variable by some loop-invariant step}} + #pragma omp simd + for (ii = 0; ii < 10; jj > kk + 2) + c[ii] = a[ii]; + + // expected-error@+2 {{increment of the openmp loop is empty}} + #pragma omp simd + for (ii = 0; ii < 10;) + c[ii] = a[ii]; + + // expected-warning@+3 {{expression result unused}} + // expected-error@+2 {{expected increment or decrement of the loop variable by some loop-invariant step}} + #pragma omp simd + for (ii = 0; ii < 10; !ii) + c[ii] = a[ii]; + + // expected-error@+2 {{expected increment or decrement of the loop variable by some loop-invariant step}} + #pragma omp simd + for (ii = 0; ii < 10; ii ? ++ii : ++jj) + c[ii] = a[ii]; + + // expected-error@+2 {{expected increment or decrement of the loop variable by some loop-invariant step}} + #pragma omp simd + for (ii = 0; ii < 10; ii = ii < 10) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; ii < 10; ii = ii + 0) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45)) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; (ii) < 10; ii-=25) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; (ii < 10); ii-=0) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of the loop}} + #pragma omp simd + for (ii = 0; ii > 10; (ii+=0)) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; ii < 10; (ii) = (1-1)+(ii)) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of the loop}} + #pragma omp simd + for ((ii = 0); ii > 10; (ii-=0)) + c[ii] = a[ii]; + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of the loop}} + #pragma omp simd + for (ii = 0; (ii < 10); (ii-=0)) + c[ii] = a[ii]; + + // expected-note@+2 {{defined as private}} + // expected-error@+2 {{loop iteration variable may not be private}} + #pragma omp simd private(ii) + for (ii = 0; ii < 10; ii++) + c[ii] = a[ii]; + + // expected-error@+3 {{unexpected OpenMP clause 'shared' in directive '#pragma omp simd'}} + // expected-note@+2 {{defined as shared}} + // expected-error@+2 {{loop iteration variable may not be shared}} + #pragma omp simd shared(ii) + for (ii = 0; ii < 10; ii++) + c[ii] = a[ii]; + + #pragma omp simd linear(ii) + for (ii = 0; ii < 10; ii++) + c[ii] = a[ii]; + + // TODO: Add test for lastprivate. + +#pragma omp parallel + { + #pragma omp simd + for (sii = 0; sii < 10; sii+=1) + c[sii] = a[sii]; + } + + // expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}} + #pragma omp simd + for (auto &item : a) { + item = item + 1; + } + + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of the loop}} + #pragma omp simd + for (unsigned i = 9; i < 10; i--) { + c[i] = a[i] + b[i]; + } + return 0; +} + +// Iterators allowed in openmp for-loops. +namespace std { +struct random_access_iterator_tag { }; +template struct iterator_traits { + // expected-error@+2 {{no type named 'difference_type' in 'Iter1'}} + // expected-error@+1 {{no type named 'difference_type' in 'Iter0'}} + typedef typename Iter::difference_type difference_type; + // expected-error@+3 {{no type named 'iterator_category' in 'Iter2'}} + // expected-error@+2 {{no type named 'iterator_category' in 'Iter1'}} + // expected-error@+1 {{no type named 'iterator_category' in 'Iter0'}} + typedef typename Iter::iterator_category iterator_category; +}; +template +typename iterator_traits::difference_type +distance(Iter first, Iter last) { return first - last; } +} +class Iter0 { + public: + Iter0() { } + Iter0(const Iter0 &) { } + Iter0 operator ++() { return *this; } + Iter0 operator --() { return *this; } + bool operator <(Iter0 a) { return true; } +}; +int operator -(Iter0 a, Iter0 b) { return 0; } +class Iter1 { + public: + Iter1() { } + Iter1(const Iter1 &) { } + Iter1 operator ++() { return *this; } + Iter1 operator --() { return *this; } + bool operator <(Iter1 a) { return true; } + bool operator >=(Iter1 a) { return false; } +}; +class Iter2 { + public: + Iter2() { } + Iter2(const Iter2 &) { } + Iter2 operator ++() { return *this; } + Iter2 operator --() { return *this; } + bool operator <(Iter2 a) { return true; } + bool operator >=(Iter2 a) { return false; } + typedef int difference_type; +}; +int operator -(Iter2 a, Iter2 b) { return 0; } +class Iter3 { + public: + Iter3() { } + Iter3(const Iter3 &) { } + Iter3 operator ++() { return *this; } + Iter3 operator --() { return *this; } + bool operator <(Iter3 a) { return true; } + bool operator >=(Iter3 a) { return false; } + typedef int difference_type; + typedef int iterator_category; +}; +int operator -(Iter3 a, Iter3 b) { return 0; } +class GoodIter { + public: + GoodIter() { } + GoodIter(const GoodIter &) { } + GoodIter(int fst, int snd) { } + GoodIter &operator =(const GoodIter &that) { return *this; } + GoodIter &operator =(const Iter0 &that) { return *this; } + GoodIter &operator +=(int x) { return *this; } + explicit GoodIter(void *) { } + GoodIter operator ++() { return *this; } + GoodIter operator --() { return *this; } + bool operator !() { return true; } + bool operator <(GoodIter a) { return true; } + bool operator <=(GoodIter a) { return true; } + bool operator >=(GoodIter a) { return false; } + typedef int difference_type; + typedef std::random_access_iterator_tag iterator_category; +}; +int operator -(GoodIter a, GoodIter b) { return 0; } +GoodIter operator -(GoodIter a, int v) { return GoodIter(); } +GoodIter operator +(GoodIter a, int v) { return GoodIter(); } +GoodIter operator -(int v, GoodIter a) { return GoodIter(); } +GoodIter operator +(int v, GoodIter a) { return GoodIter(); } + +int test_with_random_access_iterator() { + GoodIter begin, end; + Iter0 begin0, end0; + #pragma omp simd + for (GoodIter I = begin; I < end; ++I) + ++I; + #pragma omp simd + for (GoodIter I = begin; I >= end; --I) + ++I; + #pragma omp simd + for (GoodIter I(begin); I < end; ++I) + ++I; + #pragma omp simd + for (GoodIter I(nullptr); I < end; ++I) + ++I; + #pragma omp simd + for (GoodIter I(0); I < end; ++I) + ++I; + // expected-error@+2{{too many arguments to the constructor in canonical loop initialization}} + #pragma omp simd + for (GoodIter I(1,2); I < end; ++I) + ++I; + #pragma omp simd + for (begin = GoodIter(0); begin < end; ++begin) + ++begin; + #pragma omp simd + for (begin = begin0; begin < end; ++begin) + ++begin; + // expected-error@+2 {{initialization of the openmp loop should be assignment to (or definition of) the loop variable}} + #pragma omp simd + for (++begin; begin < end; ++begin) + ++begin; + #pragma omp simd + for (begin = end; begin < end; ++begin) + ++begin; + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (GoodIter I = begin; I - I; ++I) + ++I; + // expected-error@+2 {{relation in the condition of the openmp loop should refer to the loop variable ('I')}} + #pragma omp simd + for (GoodIter I = begin; begin < end; ++I) + ++I; + // expected-error@+2 {{condition of the openmp loop should be relational operator}} + #pragma omp simd + for (GoodIter I = begin; !I; ++I) + ++I; + // expected-note@+3 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of the loop}} + #pragma omp simd + for (GoodIter I = begin; I >= end; I = I + 1) + ++I; + #pragma omp simd + for (GoodIter I = begin; I >= end; I = I - 1) + ++I; + // expected-note@+3 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of the loop}} + #pragma omp simd + for (GoodIter I = begin; I >= end; I = 2 + I) + ++I; + // expected-error@+2 {{expected increment or decrement of the loop variable by some loop-invariant step}} + #pragma omp simd + for (GoodIter I = begin; I >= end; I = 2 - I) + ++I; + // expected-error@+3 {{variable must be of integer or random access iterator type}} + // expected-note@+2 {{in instantiation of template class 'std::iterator_traits' requested here}} + #pragma omp simd + for (Iter0 I = begin0; I < end0; ++I) + ++I; + Iter1 begin1, end1; + // expected-error@+3 {{variable must be of integer or random access iterator type}} + // expected-note@+2 {{in instantiation of template class 'std::iterator_traits' requested here}} + #pragma omp simd + for (Iter1 I = begin1; I < end1; ++I) + ++I; + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (Iter1 I = begin1; I < end1; ++I) + ++I; + Iter2 begin2, end2; + // expected-error@+3 {{variable must be of integer or random access iterator type}} + // expected-note@+2 {{in instantiation of template class 'std::iterator_traits' requested here}} + #pragma omp simd + for (Iter2 I = begin2; I < end2; ++I) + ++I; + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (Iter2 I = begin2; I < end2; ++I) + ++I; + Iter3 begin3, end3; + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (Iter3 I = begin3; I < end3; ++I) + ++I; + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (Iter3 I = begin3; I >= end3; --I) + ++I; + return 0; +} + +template class TC { + public: + int dotest_lt(IT begin, IT end) { + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of the loop}} + #pragma omp simd + for (IT I = begin; I < end; I = I + ST) { + ++I; + } + // expected-note@+3 {{loop step is expected to be positive due to this condition}} + // expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of the loop}} + #pragma omp simd + for (IT I = begin; I <= end; I += ST) { + ++I; + } + #pragma omp simd + for (IT I = begin; I < end; ++I) { + ++I; + } + } +}; +template int dotest_gt(IT begin, IT end) { + // expected-note@+3 2 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of the loop}} +#pragma omp simd + for (IT I = begin; I >= end; I = I + ST) { + ++I; + } + // expected-note@+3 2 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of the loop}} +#pragma omp simd + for (IT I = begin; I >= end; I += ST) { + ++I; + } + + // expected-note@+3 3 {{loop step is expected to be negative due to this condition}} + // expected-error@+2 3 {{increment expression must cause 'I' to decrease on each iteration of the loop}} +#pragma omp simd + for (IT I = begin; I >= end; ++I) { + ++I; + } +} + +void test_with_template() { + GoodIter begin, end; + TC t1; + TC t2; + t1.dotest_lt(begin, end); + t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC::dotest_lt' requested here}} + dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt' requested here}} + dotest_gt(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt' requested here}} +} + +void test_loop_break() { + const int N = 100; + float a[N], b[N], c[N]; + #pragma omp simd + for (int i = 0; i < 10; i++) { + c[i] = a[i] + b[i]; + for (int j = 0; j < 10; ++j) { + if (a[i] > b[j]) + break; // OK in nested loop + } + switch(i) { + case 1: + b[i]++; + break; + default: + break; + } + if (c[i] > 10) + break; // expected-error {{cannot break from a '#pragma omp simd' loop}} + + if (c[i] > 11) + break; // expected-error {{cannot break from a '#pragma omp simd' loop}} + } +} + +void test_loop_eh() { + const int N = 100; + float a[N], b[N], c[N]; + #pragma omp simd + for (int i = 0; i < 10; i++) { + c[i] = a[i] + b[i]; + try { // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + for (int j = 0; j < 10; ++j) { + if (a[i] > b[j]) + throw a[i]; // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + } + throw a[i]; // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + } + catch (float f) { // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + if (f > 0.1) + throw a[i]; // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + return; // expected-error {{cannot return from OpenMP region}} + } + switch(i) { + case 1: + b[i]++; + break; + default: + break; + } + if (c[i] > 10) + throw c[i]; // expected-error {{exception handling constructs are not allowed in a '#pragma omp simd' loop}} + } +} + + Index: test/OpenMP/simd_misc_messages.c =================================================================== --- test/OpenMP/simd_misc_messages.c +++ test/OpenMP/simd_misc_messages.c @@ -265,3 +265,18 @@ for (i = 0; i < 16; ++i) ; } +void test_loop_messages() +{ + float a[100], b[100], c[100]; + // expected-error@+2 {{variable must be of integer or pointer type}} + #pragma omp simd + for (float fi = 0; fi < 10.0; fi++) { + c[(int)fi] = a[(int)fi] + b[(int)fi]; + } + // expected-error@+2 {{variable must be of integer or pointer type}} + #pragma omp simd + for (double fi = 0; fi < 10.0; fi++) { + c[(int)fi] = a[(int)fi] + b[(int)fi]; + } +} +