// 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">;
"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<
"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<OpenMPLoopForm>;
+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 {
/// \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;
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; }
/// \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,
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, 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()
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.
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;
} 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)
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())
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<Expr>(S))
+ S = E->IgnoreParens();
+ if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ if (BO->getOpcode() == BO_Assign)
+ if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS());
+ } else if (auto DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl()) {
+ if (auto Var = dyn_cast_or_null<VarDecl>(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<CXXOperatorCallExpr>(S))
+ if (CE->getOperator() == OO_Equal)
+ if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
+ return SetVarAndLB(dyn_cast<VarDecl>(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<CXXConstructExpr>(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<DeclRefExpr>(E);
+ if (!DRE)
+ return nullptr;
+ return dyn_cast<VarDecl>(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<BinaryOperator>(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<CXXOperatorCallExpr>(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<BinaryOperator>(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<CXXOperatorCallExpr>(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<UnaryOperator>(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<BinaryOperator>(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<CXXOperatorCallExpr>(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<ForStmt>(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<CapturedStmt>(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<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ else if (auto CS = dyn_cast_or_null<CompoundStmt>(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<ForStmt>(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<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
- Stmt *CStmt = AStmt;
- while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(CStmt))
- CStmt = CS->getCapturedStmt();
- while (AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(CStmt))
- CStmt = AS->getSubStmt();
- ForStmt *For = dyn_cast<ForStmt>(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);
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();
!NumThreads->containsUnexpandedParameterPack()) {
SourceLocation NumThreadsLoc = NumThreads->getLocStart();
ExprResult Val =
- PerformImplicitIntegerConversion(NumThreadsLoc, NumThreads);
+ PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads);
if (Val.isInvalid())
return nullptr;
!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();
// 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);
}
!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.");
--- /dev/null
+// 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 <class Iter> struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::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 <typename IT, int ST> 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 <typename IT, int ST=0> 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<int,ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' 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; }
+ };
+ }
+}
+
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];
+ }
+}
+