Index: cfe/trunk/include/clang/Basic/DiagnosticGroups.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -678,6 +678,7 @@ // OpenMP warnings. def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">; def OpenMPClauses : DiagGroup<"openmp-clauses">; +def OpenMPLoopForm : DiagGroup<"openmp-loop-form">; // Backend warnings. def BackendInlineAsm : DiagGroup<"inline-asm">; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -6937,6 +6937,8 @@ "defined as %0">; def note_omp_predetermined_dsa : Note< "predetermined as %0">; +def err_omp_loop_var_dsa : Error< + "loop iteration variable may not be %0">; def err_omp_not_for : Error< "statement after '#pragma omp %0' must be a for loop">; def err_omp_negative_expression_in_clause : Error< @@ -6973,6 +6975,29 @@ "a variable cannot appear in more than one aligned clause">; def err_omp_local_var_in_threadprivate_init : Error< "variable with local storage in initial value of threadprivate variable">; +def err_omp_loop_not_canonical_init : Error< + "initialization clause of OpenMP for loop must be of the form " + "'var = init' or 'T var = init'">; +def ext_omp_loop_not_canonical_init : ExtWarn< + "initialization clause of OpenMP for loop is not in canonical form " + "('var = init' or 'T var = init')">, InGroup; +def err_omp_loop_not_canonical_cond : Error< + "condition of OpenMP for loop must be a relational comparison " + "('<', '<=', '>', or '>=') of loop variable %0">; +def err_omp_loop_not_canonical_incr : Error< + "increment clause of OpenMP for loop must perform simple addition " + "or subtraction on loop variable %0">; +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_compatible : Error< + "increment expression must cause %0 to %select{decrease|increase}1 " + "on each iteration of OpenMP for 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_use_stmt : Error< + "'%0' statement cannot be used in OpenMP for loop">; +def err_omp_simd_region_cannot_use_stmt : Error< + "'%0' statement cannot be used in OpenMP simd region">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { Index: cfe/trunk/include/clang/Sema/Scope.h =================================================================== --- cfe/trunk/include/clang/Sema/Scope.h +++ cfe/trunk/include/clang/Sema/Scope.h @@ -101,22 +101,30 @@ /// \brief This is the scope for a function-level C++ try or catch scope. FnTryCatchScope = 0x4000, - /// \brief This is the scope of OpenMP executable directive - OpenMPDirectiveScope = 0x8000 + /// \brief This is the scope of OpenMP executable directive. + OpenMPDirectiveScope = 0x8000, + + /// \brief This is the scope of some OpenMP loop directive. + OpenMPLoopDirectiveScope = 0x10000, + + /// \brief This is the scope of some OpenMP simd directive. + /// For example, it is used for 'omp simd', 'omp for simd'. + /// This flag is propagated to children scopes. + OpenMPSimdDirectiveScope = 0x20000 }; private: /// The parent scope for this scope. This is null for the translation-unit /// scope. Scope *AnyParent; + /// Flags - This contains a set of ScopeFlags, which indicates how the scope + /// interrelates with other control flow statements. + unsigned Flags; + /// Depth - This is the depth of this scope. The translation-unit scope has /// depth 0. unsigned short Depth; - /// Flags - This contains a set of ScopeFlags, which indicates how the scope - /// interrelates with other control flow statements. - unsigned short Flags; - /// \brief Declarations with static linkage are mangled with the number of /// scopes seen as a component. unsigned short MSLocalManglingNumber; @@ -360,6 +368,30 @@ return (getFlags() & Scope::OpenMPDirectiveScope); } + /// \brief Determine whether this scope is some OpenMP loop directive scope + /// (for example, 'omp for', 'omp simd'). + bool isOpenMPLoopDirectiveScope() const { + if (getFlags() & Scope::OpenMPLoopDirectiveScope) { + assert(isOpenMPDirectiveScope() && + "OpenMP loop directive scope is not a directive scope"); + return true; + } + return false; + } + + /// \brief Determine whether this scope is (or is nested into) some OpenMP + /// loop simd directive scope (for example, 'omp simd', 'omp for simd'). + bool isOpenMPSimdDirectiveScope() const { + return getFlags() & Scope::OpenMPSimdDirectiveScope; + } + + /// \brief Determine whether this scope is a loop having OpenMP loop + /// directive attached. + bool isOpenMPLoopScope() const { + const Scope *P = getParent(); + return P && P->isOpenMPLoopDirectiveScope(); + } + /// \brief Determine whether this scope is a C++ 'try' block. bool isTryScope() const { return getFlags() & Scope::TryScope; } Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -7258,10 +7258,11 @@ /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); - ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind); public: + ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, + Expr *Op); /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Index: cfe/trunk/lib/Parse/ParseOpenMP.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseOpenMP.cpp +++ cfe/trunk/lib/Parse/ParseOpenMP.cpp @@ -86,7 +86,7 @@ SmallVector Clauses; SmallVector, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); - const unsigned ScopeFlags = + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ConsumeToken(), EndLoc; OpenMPDirectiveKind DKind = Tok.isAnnotation() @@ -142,6 +142,9 @@ StmtResult AssociatedStmt; bool CreateDirective = true; + if (DKind == OMPD_simd) + ScopeFlags |= + Scope::OpenMPLoopDirectiveScope | Scope::OpenMPSimdDirectiveScope; ParseScope OMPDirectiveScope(this, ScopeFlags); { // The body is a block scope like in Lambdas and Blocks. Index: cfe/trunk/lib/Sema/Scope.cpp =================================================================== --- cfe/trunk/lib/Sema/Scope.cpp +++ cfe/trunk/lib/Sema/Scope.cpp @@ -39,6 +39,10 @@ BlockParent = parent->BlockParent; TemplateParamParent = parent->TemplateParamParent; MSLocalManglingParent = parent->MSLocalManglingParent; + if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope | + FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) == + 0) + Flags |= parent->getFlags() & OpenMPSimdDirectiveScope; } else { Depth = 0; PrototypeDepth = 0; @@ -178,6 +182,12 @@ } else if (Flags & OpenMPDirectiveScope) { OS << "OpenMPDirectiveScope"; Flags &= ~OpenMPDirectiveScope; + } else if (Flags & OpenMPLoopDirectiveScope) { + OS << "OpenMPLoopDirectiveScope"; + Flags &= ~OpenMPLoopDirectiveScope; + } else if (Flags & OpenMPSimdDirectiveScope) { + OS << "OpenMPSimdDirectiveScope"; + Flags &= ~OpenMPSimdDirectiveScope; } if (Flags) Index: cfe/trunk/lib/Sema/SemaExprCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp @@ -618,7 +618,10 @@ if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc)) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; - + + if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) + Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; + if (Ex && !Ex->isTypeDependent()) { ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope); if (ExRes.isInvalid()) Index: cfe/trunk/lib/Sema/SemaOpenMP.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOpenMP.cpp +++ cfe/trunk/lib/Sema/SemaOpenMP.cpp @@ -832,22 +832,497 @@ 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 &SemaRef; + /// \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 is true when step is subtracted on each iteration. + bool SubtractStep; + +public: + OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) + : SemaRef(SemaRef), 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 (#UB), 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, otherwise save loop step (#Step). + 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 the right-hand side of an assignment in 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. + bool SetStep(Expr *NewStep, bool Subtract); +}; + +bool OpenMPIterationSpaceChecker::Dependent() const { + if (!Var) { + assert(!LB && !UB && !Step); + return false; + } + return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || + (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); +} + +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()) { + // Check that the step is integer expression. + SourceLocation StepLoc = NewStep->getLocStart(); + ExprResult Val = + SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep); + if (Val.isInvalid()) + return true; + NewStep = Val.get(); + + // 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, SemaRef.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))))) { + SemaRef.Diag(NewStep->getExprLoc(), + diag::err_omp_loop_incr_not_compatible) + << Var << TestIsLessOp << NewStep->getSourceRange(); + SemaRef.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) { + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); + return true; + } + if (Expr *E = dyn_cast(S)) + S = E->IgnoreParens(); + if (auto BO = dyn_cast(S)) { + if (BO->getOpcode() == BO_Assign) + if (auto DRE = dyn_cast(BO->getLHS()->IgnoreParens())) + return SetVarAndLB(dyn_cast(DRE->getDecl()), BO->getLHS()); + } else if (auto DS = dyn_cast(S)) { + if (DS->isSingleDecl()) { + if (auto Var = dyn_cast_or_null(DS->getSingleDecl())) { + if (Var->hasInit()) { + // Accept non-canonical init form here but emit ext. warning. + if (Var->getInitStyle() != VarDecl::CInit) + SemaRef.Diag(S->getLocStart(), + diag::ext_omp_loop_not_canonical_init) + << S->getSourceRange(); + return SetVarAndLB(Var, Var->getInit()); + } + } + } + } else 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)); + + SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) + << S->getSourceRange(); + return true; +} + +/// \brief Ignore parenthesises, implicit casts, copy constructor and return the +/// variable (which may be the 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) { + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; + return true; + } + S = S->IgnoreParenImpCasts(); + SourceLocation CondLoc = S->getLocStart(); + if (auto BO = dyn_cast(S)) { + if (BO->isRelationalOp()) { + 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()); + } + } else if (auto CE = dyn_cast(S)) { + if (CE->getNumArgs() == 2) { + auto Op = CE->getOperator(); + switch (Op) { + case OO_Greater: + case OO_GreaterEqual: + case OO_Less: + case OO_LessEqual: + 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()); + break; + default: + break; + } + } + } + SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) + << S->getSourceRange() << Var; + 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()) { + bool IsAdd = BO->getOpcode() == BO_Add; + if (GetInitVarDecl(BO->getLHS()) == Var) + return SetStep(BO->getRHS(), !IsAdd); + if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) + return SetStep(BO->getLHS(), false); + } + } else if (auto CE = dyn_cast(RHS)) { + bool IsAdd = CE->getOperator() == OO_Plus; + if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { + if (GetInitVarDecl(CE->getArg(0)) == Var) + return SetStep(CE->getArg(1), !IsAdd); + if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) + return SetStep(CE->getArg(0), false); + } + } + SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << RHS->getSourceRange() << Var; + 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) { + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; + return true; + } + S = S->IgnoreParens(); + if (auto UO = dyn_cast(S)) { + if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) + return SetStep( + SemaRef.ActOnIntegerConstant(UO->getLocStart(), + (UO->isDecrementOp() ? -1 : 1)).get(), + false); + } else if (auto BO = dyn_cast(S)) { + switch (BO->getOpcode()) { + case BO_AddAssign: + case BO_SubAssign: + if (GetInitVarDecl(BO->getLHS()) == Var) + return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); + break; + case BO_Assign: + if (GetInitVarDecl(BO->getLHS()) == Var) + return CheckIncRHS(BO->getRHS()); + break; + default: + break; + } + } else if (auto CE = dyn_cast(S)) { + switch (CE->getOperator()) { + case OO_PlusPlus: + case OO_MinusMinus: + if (GetInitVarDecl(CE->getArg(0)) == Var) + return SetStep( + SemaRef.ActOnIntegerConstant( + CE->getLocStart(), + ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(), + 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; + } + } + SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) + << S->getSourceRange() << Var; + return true; +} +} + +/// \brief Called on a for stmt to check and extract its iteration space +/// for further processing (such as collapsing). +static bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S, + Sema &SemaRef, DSAStackTy &DSA) { + // OpenMP [2.6, Canonical Loop Form] + // for (init-expr; test-expr; incr-expr) structured-block + auto For = dyn_cast_or_null(S); + if (!For) { + SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for) + << getOpenMPDirectiveName(DKind); + return true; + } + assert(For->getBody()); + + OpenMPIterationSpaceChecker ISC(SemaRef, 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(); + if (!VarType->isDependentType() && !VarType->isIntegerType() && + !VarType->isPointerType() && + !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) + << SemaRef.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 = DSA.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"); + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind); + if (DVar.RefExpr) + SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(DVar.CKind); + else + SemaRef.Diag(Var->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(DVar.CKind); + HasErrors = true; + } else { + // Make the loop iteration variable private by default. + DSA.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 HasErrors; + + // FIXME: Build loop's iteration space representation. + return HasErrors; +} + +/// \brief A helper routine to skip no-op (attributed, compound) stmts get the +/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt +/// to get the first for loop. +static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) { + if (IgnoreCaptured) + if (auto CapS = dyn_cast_or_null(S)) + S = CapS->getCapturedStmt(); + // OpenMP [2.8.1, simd construct, Restrictions] + // All loops associated with the construct must be perfectly nested; that is, + // there must be no intervening code nor any OpenMP directive between any two + // loops. + 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; +} + +/// \brief Called on a for stmt to check itself and nested loops (if any). +static bool CheckOpenMPLoop(OpenMPDirectiveKind DKind, unsigned NestedLoopCount, + Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA) { + // 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, SemaRef, DSA)) + return true; + // Move on to the next nested for loop, or to the loop body. + CurStmt = IgnoreContainerStmts(cast(CurStmt)->getBody(), false); + } + + // 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, 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, *this, *DSAStack)) return StmtError(); - } - - // FIXME: Checking loop canonical form, collapsing etc. getCurFunction()->setHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); @@ -904,8 +1379,8 @@ return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc); } -ExprResult Sema::PerformImplicitIntegerConversion(SourceLocation Loc, - Expr *Op) { +ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, + Expr *Op) { if (!Op) return ExprError(); @@ -958,7 +1433,7 @@ !NumThreads->containsUnexpandedParameterPack()) { SourceLocation NumThreadsLoc = NumThreads->getLocStart(); ExprResult Val = - PerformImplicitIntegerConversion(NumThreadsLoc, NumThreads); + PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads); if (Val.isInvalid()) return nullptr; @@ -1651,7 +2126,7 @@ !Step->isInstantiationDependent() && !Step->containsUnexpandedParameterPack()) { SourceLocation StepLoc = Step->getLocStart(); - ExprResult Val = PerformImplicitIntegerConversion(StepLoc, Step); + ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step); if (Val.isInvalid()) return nullptr; StepExpr = Val.get(); Index: cfe/trunk/lib/Sema/SemaStmt.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp +++ cfe/trunk/lib/Sema/SemaStmt.cpp @@ -2417,6 +2417,9 @@ // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch)); } + if (S->isOpenMPLoopScope()) + return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt) + << "break"); return new (Context) BreakStmt(BreakLoc); } @@ -3188,6 +3191,9 @@ !getSourceManager().isInSystemHeader(TryLoc)) Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) + Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try"; + const unsigned NumHandlers = Handlers.size(); assert(NumHandlers > 0 && "The parser shouldn't call this if there are no handlers."); Index: cfe/trunk/test/OpenMP/simd_loop_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/simd_loop_messages.cpp +++ cfe/trunk/test/OpenMP/simd_loop_messages.cpp @@ -0,0 +1,574 @@ +// 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 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (int &ref = ii; ref < 10; ref++) { + } + // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #pragma omp simd + for (int i; i < 10; i++) + c[i] = a[i]; + + // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #pragma omp simd + for (int i = 0, j = 0; i < 10; ++i) + c[i] = a[i]; + + // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #pragma omp simd + for (;ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-warning@+3 {{expression result unused}} + // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #pragma omp simd + for (ii + 1;ii < 10; ++ii) + c[ii] = a[ii]; + + // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #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 OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}} + #pragma omp simd + for (int i = 0; i; i++) + c[i] = a[i]; + + // expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}} + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}} + #pragma omp simd + for (int i = 0; jj < kk; ii++) + c[i] = a[i]; + + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}} + #pragma omp simd + for (int i = 0; !!i; i++) + c[i] = a[i]; + + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}} + #pragma omp simd + for (int i = 0; i != 1; i++) + c[i] = a[i]; + + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}} + #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 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #pragma omp simd + for (ii = 0; ii < 10; ++jj) + c[ii] = a[jj]; + + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #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 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #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 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #pragma omp simd + for (ii = 0; ii < 10; jj > kk + 2) + c[ii] = a[ii]; + + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #pragma omp simd + for (ii = 0; ii < 10;) + c[ii] = a[ii]; + + // expected-warning@+3 {{expression result unused}} + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #pragma omp simd + for (ii = 0; ii < 10; !ii) + c[ii] = a[ii]; + + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #pragma omp simd + for (ii = 0; ii < 10; ii ? ++ii : ++jj) + c[ii] = a[ii]; + + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}} + #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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for 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 OpenMP for loop}} + #pragma omp simd + for (unsigned i = 9; i < 10; i--) { + c[i] = a[i] + b[i]; + } + + int (*lb)[4] = nullptr; + #pragma omp simd + for (int (*p)[4] = lb; p < lb + 8; ++p) { + } + + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (int a{0}; a<10; ++a) { + } + + return 0; +} + +// Iterators allowed in openmp for-loops. +namespace std { +struct random_access_iterator_tag { }; +template struct iterator_traits { + typedef typename Iter::difference_type difference_type; + 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(float f=0.0f, double d=0.0) { } + Iter1(const Iter1 &) { } + Iter1 operator ++() { return *this; } + Iter1 operator --() { return *this; } + bool operator <(Iter1 a) { return true; } + bool operator >=(Iter1 a) { return false; } +}; +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) { return a; } +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; + // expected-error@+2 {{variable must be of integer or random access iterator type}} + #pragma omp simd + for (GoodIter &I = begin; I < end; ++I) + ++I; + #pragma omp simd + for (GoodIter I = begin; I >= end; --I) + ++I; + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (GoodIter I(begin); I < end; ++I) + ++I; + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (GoodIter I(nullptr); I < end; ++I) + ++I; + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (GoodIter I(0); I < end; ++I) + ++I; + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #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 clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}} + #pragma omp simd + for (++begin; begin < end; ++begin) + ++begin; + #pragma omp simd + for (begin = end; begin < end; ++begin) + ++begin; + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}} + #pragma omp simd + for (GoodIter I = begin; I - I; ++I) + ++I; + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}} + #pragma omp simd + for (GoodIter I = begin; begin < end; ++I) + ++I; + // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}} + #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 OpenMP for 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-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}} + #pragma omp simd + for (GoodIter I = begin; I >= end; 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 OpenMP for loop}} + #pragma omp simd + for (GoodIter I = begin; I >= end; I = 2 + I) + ++I; + // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}} + #pragma omp simd + for (GoodIter I = begin; I >= end; I = 2 - I) + ++I; + #pragma omp simd + for (Iter0 I = begin0; I < end0; ++I) + ++I; + // Initializer is constructor without params. + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (Iter0 I; I < end0; ++I) + ++I; + Iter1 begin1, end1; + #pragma omp simd + for (Iter1 I = begin1; I < end1; ++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 OpenMP for loop}} + #pragma omp simd + for (Iter1 I = begin1; I >= end1; ++I) + ++I; + // Initializer is constructor with all default params. + // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}} + #pragma omp simd + for (Iter1 I; I < end1; ++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 OpenMP for 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 OpenMP for loop}} + #pragma omp simd + for (IT I = begin; I <= end; I += ST) { + ++I; + } + #pragma omp simd + for (IT I = begin; I < end; ++I) { + ++I; + } + } + + static IT step() { + return IT(ST); + } +}; +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 OpenMP for 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 OpenMP for loop}} + #pragma omp simd + for (IT I = begin; I >= end; I += ST) { + ++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 OpenMP for loop}} + #pragma omp simd + for (IT I = begin; I >= end; ++I) { + ++I; + } + + #pragma omp simd + for (IT I = begin; I < end; I+=TC::step()) { + ++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 {{'break' statement cannot be used in OpenMP for loop}} + + if (c[i] > 11) + break; // expected-error {{'break' statement cannot be used in OpenMP for loop}} + } + + #pragma omp simd + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + c[i] = a[i] + b[i]; + if (c[i] > 10) { + if (c[i] < 20) { + break; // OK + } + } + } + } +} + +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 {{'try' statement cannot be used in OpenMP simd region}} + for (int j = 0; j < 10; ++j) { + if (a[i] > b[j]) + throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}} + } + throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}} + } + catch (float f) { + if (f > 0.1) + throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}} + return; // expected-error {{cannot return from OpenMP region}} + } + switch(i) { + case 1: + b[i]++; + break; + default: + break; + } + for (int j = 0; j < 10; j++) { + if (c[i] > 10) + throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}} + } + } + if (c[9] > 10) + throw c[9]; // OK + + #pragma omp simd + for (int i = 0; i < 10; ++i) { + struct S { + void g() { throw 0; } + }; + } +} + Index: cfe/trunk/test/OpenMP/simd_misc_messages.c =================================================================== --- cfe/trunk/test/OpenMP/simd_misc_messages.c +++ cfe/trunk/test/OpenMP/simd_misc_messages.c @@ -414,3 +414,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]; + } +} +