forked from OSchip/llvm-project
[OPENMP50] extend array section for stride (Parsing/Sema/AST)
Reviewers: ABataev, jdoerfert Reviewed By: ABataev Subscribers: yaxunl, guansong, arphaman, sstefan1, cfe-commits, sandoval, dreachem Tags: #clang Differential Revision: https://reviews.llvm.org/D82800
This commit is contained in:
parent
cfb3675410
commit
2da9572a9b
|
@ -2167,7 +2167,7 @@ enum CXCursorKind {
|
|||
*/
|
||||
CXCursor_ObjCSelfExpr = 147,
|
||||
|
||||
/** OpenMP 4.0 [2.4, Array Section].
|
||||
/** OpenMP 5.0 [2.1.5, Array Section].
|
||||
*/
|
||||
CXCursor_OMPArraySectionExpr = 148,
|
||||
|
||||
|
|
|
@ -17,46 +17,61 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
|
||||
namespace clang {
|
||||
/// OpenMP 4.0 [2.4, Array Sections].
|
||||
/// OpenMP 5.0 [2.1.5, Array Sections].
|
||||
/// To specify an array section in an OpenMP construct, array subscript
|
||||
/// expressions are extended with the following syntax:
|
||||
/// \code
|
||||
/// [ lower-bound : length : stride ]
|
||||
/// [ lower-bound : length : ]
|
||||
/// [ lower-bound : length ]
|
||||
/// [ lower-bound : : stride ]
|
||||
/// [ lower-bound : : ]
|
||||
/// [ lower-bound : ]
|
||||
/// [ : length : stride ]
|
||||
/// [ : length : ]
|
||||
/// [ : length ]
|
||||
/// [ : : stride ]
|
||||
/// [ : : ]
|
||||
/// [ : ]
|
||||
/// \endcode
|
||||
/// The array section must be a subset of the original array.
|
||||
/// Array sections are allowed on multidimensional arrays. Base language array
|
||||
/// subscript expressions can be used to specify length-one dimensions of
|
||||
/// multidimensional array sections.
|
||||
/// The lower-bound and length are integral type expressions. When evaluated
|
||||
/// Each of the lower-bound, length, and stride expressions if specified must be
|
||||
/// an integral type expressions of the base language. When evaluated
|
||||
/// they represent a set of integer values as follows:
|
||||
/// \code
|
||||
/// { lower-bound, lower-bound + 1, lower-bound + 2,... , lower-bound + length -
|
||||
/// 1 }
|
||||
/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... ,
|
||||
/// lower-bound + ((length - 1) * stride) }
|
||||
/// \endcode
|
||||
/// The lower-bound and length must evaluate to non-negative integers.
|
||||
/// The stride must evaluate to a positive integer.
|
||||
/// When the size of the array dimension is not known, the length must be
|
||||
/// specified explicitly.
|
||||
/// When the length is absent, it defaults to the size of the array dimension
|
||||
/// minus the lower-bound.
|
||||
/// When the lower-bound is absent it defaults to 0.
|
||||
/// When the stride is absent it defaults to 1.
|
||||
/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉,
|
||||
/// where size is the size of the array dimension. When the lower-bound is
|
||||
/// absent it defaults to 0.
|
||||
class OMPArraySectionExpr : public Expr {
|
||||
enum { BASE, LOWER_BOUND, LENGTH, END_EXPR };
|
||||
enum { BASE, LOWER_BOUND, LENGTH, STRIDE, END_EXPR };
|
||||
Stmt *SubExprs[END_EXPR];
|
||||
SourceLocation ColonLoc;
|
||||
SourceLocation ColonLocFirst;
|
||||
SourceLocation ColonLocSecond;
|
||||
SourceLocation RBracketLoc;
|
||||
|
||||
public:
|
||||
OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation ColonLoc, SourceLocation RBracketLoc)
|
||||
: Expr(OMPArraySectionExprClass, Type, VK, OK), ColonLoc(ColonLoc),
|
||||
OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride,
|
||||
QualType Type, ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation ColonLocFirst,
|
||||
SourceLocation ColonLocSecond, SourceLocation RBracketLoc)
|
||||
: Expr(OMPArraySectionExprClass, Type, VK, OK),
|
||||
ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond),
|
||||
RBracketLoc(RBracketLoc) {
|
||||
SubExprs[BASE] = Base;
|
||||
SubExprs[LOWER_BOUND] = LowerBound;
|
||||
SubExprs[LENGTH] = Length;
|
||||
SubExprs[STRIDE] = Stride;
|
||||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
|
@ -89,13 +104,22 @@ public:
|
|||
/// Set length of the array section.
|
||||
void setLength(Expr *E) { SubExprs[LENGTH] = E; }
|
||||
|
||||
/// Get stride of array section.
|
||||
Expr *getStride() { return cast_or_null<Expr>(SubExprs[STRIDE]); }
|
||||
const Expr *getStride() const { return cast_or_null<Expr>(SubExprs[STRIDE]); }
|
||||
/// Set length of the array section.
|
||||
void setStride(Expr *E) { SubExprs[STRIDE] = E; }
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY {
|
||||
return getBase()->getBeginLoc();
|
||||
}
|
||||
SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; }
|
||||
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
void setColonLoc(SourceLocation L) { ColonLoc = L; }
|
||||
SourceLocation getColonLocFirst() const { return ColonLocFirst; }
|
||||
void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; }
|
||||
|
||||
SourceLocation getColonLocSecond() const { return ColonLocSecond; }
|
||||
void setColonLocSecond(SourceLocation L) { ColonLocSecond = L; }
|
||||
|
||||
SourceLocation getRBracketLoc() const { return RBracketLoc; }
|
||||
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
|
||||
|
|
|
@ -10064,6 +10064,8 @@ def err_omp_section_not_subset_of_array : Error<
|
|||
"array section must be a subset of the original array">;
|
||||
def err_omp_section_length_negative : Error<
|
||||
"section length is evaluated to a negative value %0">;
|
||||
def err_omp_section_stride_non_positive : Error<
|
||||
"section stride is evaluated to a non-positive value %0">;
|
||||
def err_omp_section_length_undefined : Error<
|
||||
"section length is unspecified and cannot be inferred because subscripted value is %select{not an array|an array of unknown bound}0">;
|
||||
def err_omp_wrong_linear_modifier : Error<
|
||||
|
|
|
@ -241,6 +241,9 @@ class Parser : public CodeCompletionHandler {
|
|||
/// The "depth" of the template parameters currently being parsed.
|
||||
unsigned TemplateParameterDepth;
|
||||
|
||||
/// Current kind of OpenMP clause
|
||||
OpenMPClauseKind OMPClauseKind = llvm::omp::OMPC_unknown;
|
||||
|
||||
/// RAII class that manages the template parameter depth.
|
||||
class TemplateParameterDepthRAII {
|
||||
unsigned &Depth;
|
||||
|
|
|
@ -4971,8 +4971,11 @@ public:
|
|||
SourceLocation RBLoc);
|
||||
|
||||
ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
||||
Expr *LowerBound, SourceLocation ColonLoc,
|
||||
Expr *Length, SourceLocation RBLoc);
|
||||
Expr *LowerBound,
|
||||
SourceLocation ColonLocFirst,
|
||||
SourceLocation ColonLocSecond,
|
||||
Expr *Length, Expr *Stride,
|
||||
SourceLocation RBLoc);
|
||||
ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc,
|
||||
ArrayRef<Expr *> Dims,
|
||||
|
|
|
@ -1343,11 +1343,16 @@ void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) {
|
|||
OS << "[";
|
||||
if (Node->getLowerBound())
|
||||
PrintExpr(Node->getLowerBound());
|
||||
if (Node->getColonLoc().isValid()) {
|
||||
if (Node->getColonLocFirst().isValid()) {
|
||||
OS << ":";
|
||||
if (Node->getLength())
|
||||
PrintExpr(Node->getLength());
|
||||
}
|
||||
if (Node->getColonLocSecond().isValid()) {
|
||||
OS << ":";
|
||||
if (Node->getStride())
|
||||
PrintExpr(Node->getStride());
|
||||
}
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
|
|
|
@ -3849,7 +3849,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
|
|||
else
|
||||
ResultExprTy = BaseTy->getPointeeType();
|
||||
llvm::Value *Idx = nullptr;
|
||||
if (IsLowerBound || E->getColonLoc().isInvalid()) {
|
||||
if (IsLowerBound || E->getColonLocFirst().isInvalid()) {
|
||||
// Requesting lower bound or upper bound, but without provided length and
|
||||
// without ':' symbol for the default length -> length = 1.
|
||||
// Idx = LowerBound ?: 0;
|
||||
|
|
|
@ -7175,7 +7175,7 @@ private:
|
|||
// If there is no length associated with the expression and lower bound is
|
||||
// not specified too, that means we are using the whole length of the
|
||||
// base.
|
||||
if (!OAE->getLength() && OAE->getColonLoc().isValid() &&
|
||||
if (!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
|
||||
!OAE->getLowerBound())
|
||||
return CGF.getTypeSize(BaseTy);
|
||||
|
||||
|
@ -7190,7 +7190,7 @@ private:
|
|||
|
||||
// If we don't have a length at this point, that is because we have an
|
||||
// array section with a single element.
|
||||
if (!OAE->getLength() && OAE->getColonLoc().isInvalid())
|
||||
if (!OAE->getLength() && OAE->getColonLocFirst().isInvalid())
|
||||
return ElemSize;
|
||||
|
||||
if (const Expr *LenExpr = OAE->getLength()) {
|
||||
|
@ -7200,7 +7200,7 @@ private:
|
|||
LenExpr->getExprLoc());
|
||||
return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
|
||||
}
|
||||
assert(!OAE->getLength() && OAE->getColonLoc().isValid() &&
|
||||
assert(!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
|
||||
OAE->getLowerBound() && "expected array_section[lb:].");
|
||||
// Size = sizetype - lb * elemtype;
|
||||
llvm::Value *LengthVal = CGF.getTypeSize(BaseTy);
|
||||
|
@ -7273,7 +7273,7 @@ private:
|
|||
return false;
|
||||
|
||||
// An array section with no colon always refer to a single element.
|
||||
if (OASE->getColonLoc().isInvalid())
|
||||
if (OASE->getColonLocFirst().isInvalid())
|
||||
return false;
|
||||
|
||||
const Expr *Length = OASE->getLength();
|
||||
|
|
|
@ -1909,8 +1909,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
|||
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||
T.consumeOpen();
|
||||
Loc = T.getOpenLocation();
|
||||
ExprResult Idx, Length;
|
||||
SourceLocation ColonLoc;
|
||||
ExprResult Idx, Length, Stride;
|
||||
SourceLocation ColonLocFirst, ColonLocSecond;
|
||||
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
|
||||
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
||||
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
||||
|
@ -1924,10 +1924,22 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
|||
}
|
||||
if (Tok.is(tok::colon)) {
|
||||
// Consume ':'
|
||||
ColonLoc = ConsumeToken();
|
||||
if (Tok.isNot(tok::r_square))
|
||||
ColonLocFirst = ConsumeToken();
|
||||
if (Tok.isNot(tok::r_square) &&
|
||||
(getLangOpts().OpenMP < 50 ||
|
||||
((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50))))
|
||||
Length = ParseExpression();
|
||||
}
|
||||
if (getLangOpts().OpenMP >= 50 &&
|
||||
(OMPClauseKind == llvm::omp::Clause::OMPC_to ||
|
||||
OMPClauseKind == llvm::omp::Clause::OMPC_from) &&
|
||||
Tok.is(tok::colon)) {
|
||||
// Consume ':'
|
||||
ColonLocSecond = ConsumeToken();
|
||||
if (Tok.isNot(tok::r_square)) {
|
||||
Stride = ParseExpression();
|
||||
}
|
||||
}
|
||||
} else
|
||||
Idx = ParseExpression();
|
||||
|
||||
|
@ -1937,10 +1949,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
|||
Idx = Actions.CorrectDelayedTyposInExpr(Idx);
|
||||
Length = Actions.CorrectDelayedTyposInExpr(Length);
|
||||
if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() &&
|
||||
Tok.is(tok::r_square)) {
|
||||
if (ColonLoc.isValid()) {
|
||||
LHS = Actions.ActOnOMPArraySectionExpr(LHS.get(), Loc, Idx.get(),
|
||||
ColonLoc, Length.get(), RLoc);
|
||||
!Stride.isInvalid() && Tok.is(tok::r_square)) {
|
||||
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
|
||||
LHS = Actions.ActOnOMPArraySectionExpr(
|
||||
LHS.get(), Loc, Idx.get(), ColonLocFirst, ColonLocSecond,
|
||||
Length.get(), Stride.get(), RLoc);
|
||||
} else {
|
||||
LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
|
||||
Idx.get(), RLoc);
|
||||
|
|
|
@ -2498,6 +2498,7 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
|
|||
///
|
||||
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
||||
OpenMPClauseKind CKind, bool FirstClause) {
|
||||
OMPClauseKind = CKind;
|
||||
OMPClause *Clause = nullptr;
|
||||
bool ErrorFound = false;
|
||||
bool WrongDirective = false;
|
||||
|
|
|
@ -4562,7 +4562,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
|
|||
if (base && !base->getType().isNull() &&
|
||||
base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection))
|
||||
return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(),
|
||||
/*Length=*/nullptr, rbLoc);
|
||||
SourceLocation(), /*Length*/ nullptr,
|
||||
/*Stride=*/nullptr, rbLoc);
|
||||
|
||||
// Since this might be a postfix expression, get rid of ParenListExprs.
|
||||
if (isa<ParenListExpr>(base)) {
|
||||
|
@ -4812,7 +4813,9 @@ void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) {
|
|||
|
||||
ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
||||
Expr *LowerBound,
|
||||
SourceLocation ColonLoc, Expr *Length,
|
||||
SourceLocation ColonLocFirst,
|
||||
SourceLocation ColonLocSecond,
|
||||
Expr *Length, Expr *Stride,
|
||||
SourceLocation RBLoc) {
|
||||
if (Base->getType()->isPlaceholderType() &&
|
||||
!Base->getType()->isSpecificPlaceholderType(
|
||||
|
@ -4840,15 +4843,25 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
return ExprError();
|
||||
Length = Result.get();
|
||||
}
|
||||
if (Stride && Stride->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult Result = CheckPlaceholderExpr(Stride);
|
||||
if (Result.isInvalid())
|
||||
return ExprError();
|
||||
Result = DefaultLvalueConversion(Result.get());
|
||||
if (Result.isInvalid())
|
||||
return ExprError();
|
||||
Stride = Result.get();
|
||||
}
|
||||
|
||||
// Build an unanalyzed expression if either operand is type-dependent.
|
||||
if (Base->isTypeDependent() ||
|
||||
(LowerBound &&
|
||||
(LowerBound->isTypeDependent() || LowerBound->isValueDependent())) ||
|
||||
(Length && (Length->isTypeDependent() || Length->isValueDependent()))) {
|
||||
return new (Context)
|
||||
OMPArraySectionExpr(Base, LowerBound, Length, Context.DependentTy,
|
||||
VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
|
||||
(Length && (Length->isTypeDependent() || Length->isValueDependent())) ||
|
||||
(Stride && (Stride->isTypeDependent() || Stride->isValueDependent()))) {
|
||||
return new (Context) OMPArraySectionExpr(
|
||||
Base, LowerBound, Length, Stride, Context.DependentTy, VK_LValue,
|
||||
OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
|
||||
}
|
||||
|
||||
// Perform default conversions.
|
||||
|
@ -4892,6 +4905,20 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
Diag(Length->getExprLoc(), diag::warn_omp_section_is_char)
|
||||
<< 1 << Length->getSourceRange();
|
||||
}
|
||||
if (Stride) {
|
||||
ExprResult Res =
|
||||
PerformOpenMPImplicitIntegerConversion(Stride->getExprLoc(), Stride);
|
||||
if (Res.isInvalid())
|
||||
return ExprError(Diag(Stride->getExprLoc(),
|
||||
diag::err_omp_typecheck_section_not_integer)
|
||||
<< 1 << Stride->getSourceRange());
|
||||
Stride = Res.get();
|
||||
|
||||
if (Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
|
||||
Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
|
||||
Diag(Stride->getExprLoc(), diag::warn_omp_section_is_char)
|
||||
<< 1 << Stride->getSourceRange();
|
||||
}
|
||||
|
||||
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
|
||||
// C++ [expr.sub]p1: The type "T" shall be a completely-defined object
|
||||
|
@ -4910,7 +4937,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
if (LowerBound && !OriginalTy->isAnyPointerType()) {
|
||||
Expr::EvalResult Result;
|
||||
if (LowerBound->EvaluateAsInt(Result, Context)) {
|
||||
// OpenMP 4.5, [2.4 Array Sections]
|
||||
// OpenMP 5.0, [2.1.5 Array Sections]
|
||||
// The array section must be a subset of the original array.
|
||||
llvm::APSInt LowerBoundValue = Result.Val.getInt();
|
||||
if (LowerBoundValue.isNegative()) {
|
||||
|
@ -4924,7 +4951,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
if (Length) {
|
||||
Expr::EvalResult Result;
|
||||
if (Length->EvaluateAsInt(Result, Context)) {
|
||||
// OpenMP 4.5, [2.4 Array Sections]
|
||||
// OpenMP 5.0, [2.1.5 Array Sections]
|
||||
// The length must evaluate to non-negative integers.
|
||||
llvm::APSInt LengthValue = Result.Val.getInt();
|
||||
if (LengthValue.isNegative()) {
|
||||
|
@ -4934,17 +4961,32 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
return ExprError();
|
||||
}
|
||||
}
|
||||
} else if (ColonLoc.isValid() &&
|
||||
} else if (ColonLocFirst.isValid() &&
|
||||
(OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() &&
|
||||
!OriginalTy->isVariableArrayType()))) {
|
||||
// OpenMP 4.5, [2.4 Array Sections]
|
||||
// OpenMP 5.0, [2.1.5 Array Sections]
|
||||
// When the size of the array dimension is not known, the length must be
|
||||
// specified explicitly.
|
||||
Diag(ColonLoc, diag::err_omp_section_length_undefined)
|
||||
Diag(ColonLocFirst, diag::err_omp_section_length_undefined)
|
||||
<< (!OriginalTy.isNull() && OriginalTy->isArrayType());
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (Stride) {
|
||||
Expr::EvalResult Result;
|
||||
if (Stride->EvaluateAsInt(Result, Context)) {
|
||||
// OpenMP 5.0, [2.1.5 Array Sections]
|
||||
// The stride must evaluate to a positive integer.
|
||||
llvm::APSInt StrideValue = Result.Val.getInt();
|
||||
if (!StrideValue.isStrictlyPositive()) {
|
||||
Diag(Stride->getExprLoc(), diag::err_omp_section_stride_non_positive)
|
||||
<< StrideValue.toString(/*Radix=*/10, /*Signed=*/true)
|
||||
<< Stride->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Base->getType()->isSpecificPlaceholderType(
|
||||
BuiltinType::OMPArraySection)) {
|
||||
ExprResult Result = DefaultFunctionArrayLvalueConversion(Base);
|
||||
|
@ -4952,9 +4994,9 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
|
|||
return ExprError();
|
||||
Base = Result.get();
|
||||
}
|
||||
return new (Context)
|
||||
OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy,
|
||||
VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
|
||||
return new (Context) OMPArraySectionExpr(
|
||||
Base, LowerBound, Length, Stride, Context.OMPArraySectionTy, VK_LValue,
|
||||
OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
|
||||
|
|
|
@ -14692,7 +14692,7 @@ static bool checkOMPArraySectionConstantForReduction(
|
|||
if (Length == nullptr) {
|
||||
// For array sections of the form [1:] or [:], we would need to analyze
|
||||
// the lower bound...
|
||||
if (OASE->getColonLoc().isValid())
|
||||
if (OASE->getColonLocFirst().isValid())
|
||||
return false;
|
||||
|
||||
// This is an array subscript which has implicit length 1!
|
||||
|
@ -14718,7 +14718,7 @@ static bool checkOMPArraySectionConstantForReduction(
|
|||
if (Length == nullptr) {
|
||||
// For array sections of the form [1:] or [:], we would need to analyze
|
||||
// the lower bound...
|
||||
if (OASE->getColonLoc().isValid())
|
||||
if (OASE->getColonLocFirst().isValid())
|
||||
return false;
|
||||
|
||||
// This is an array subscript which has implicit length 1!
|
||||
|
@ -16475,7 +16475,8 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
|
|||
// If this is an array subscript, it refers to the whole size if the size of
|
||||
// the dimension is constant and equals 1. Also, an array section assumes the
|
||||
// format of an array subscript if no colon is used.
|
||||
if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
|
||||
if (isa<ArraySubscriptExpr>(E) ||
|
||||
(OASE && OASE->getColonLocFirst().isInvalid())) {
|
||||
if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
|
||||
return ATy->getSize().getSExtValue() != 1;
|
||||
// Size can't be evaluated statically.
|
||||
|
@ -16531,7 +16532,8 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
|
|||
|
||||
// An array subscript always refer to a single element. Also, an array section
|
||||
// assumes the format of an array subscript if no colon is used.
|
||||
if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
|
||||
if (isa<ArraySubscriptExpr>(E) ||
|
||||
(OASE && OASE->getColonLocFirst().isInvalid()))
|
||||
return false;
|
||||
|
||||
assert(OASE && "Expecting array section if not an array subscript.");
|
||||
|
@ -16575,7 +16577,7 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
|
|||
//
|
||||
// We want to retrieve the member expression 'this->S';
|
||||
|
||||
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
|
||||
// OpenMP 5.0 [2.19.7.1, map Clause, Restrictions, p.2]
|
||||
// If a list item is an array section, it must specify contiguous storage.
|
||||
//
|
||||
// For this restriction it is sufficient that we make sure only references
|
||||
|
|
|
@ -2436,10 +2436,13 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc,
|
||||
Expr *LowerBound,
|
||||
SourceLocation ColonLoc, Expr *Length,
|
||||
SourceLocation ColonLocFirst,
|
||||
SourceLocation ColonLocSecond,
|
||||
Expr *Length, Expr *Stride,
|
||||
SourceLocation RBracketLoc) {
|
||||
return getSema().ActOnOMPArraySectionExpr(Base, LBracketLoc, LowerBound,
|
||||
ColonLoc, Length, RBracketLoc);
|
||||
ColonLocFirst, ColonLocSecond,
|
||||
Length, Stride, RBracketLoc);
|
||||
}
|
||||
|
||||
/// Build a new array shaping expression.
|
||||
|
@ -10337,13 +10340,21 @@ TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) {
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
ExprResult Stride;
|
||||
if (Expr *Str = E->getStride()) {
|
||||
Stride = getDerived().TransformExpr(Str);
|
||||
if (Stride.isInvalid())
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
|
||||
LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength())
|
||||
return E;
|
||||
|
||||
return getDerived().RebuildOMPArraySectionExpr(
|
||||
Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), E->getColonLoc(),
|
||||
Length.get(), E->getRBracketLoc());
|
||||
Base.get(), E->getBase()->getEndLoc(), LowerBound.get(),
|
||||
E->getColonLocFirst(), E->getColonLocSecond(), Length.get(), Stride.get(),
|
||||
E->getRBracketLoc());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
|
|
|
@ -937,7 +937,9 @@ void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
|
|||
E->setBase(Record.readSubExpr());
|
||||
E->setLowerBound(Record.readSubExpr());
|
||||
E->setLength(Record.readSubExpr());
|
||||
E->setColonLoc(readSourceLocation());
|
||||
E->setStride(Record.readSubExpr());
|
||||
E->setColonLocFirst(readSourceLocation());
|
||||
E->setColonLocSecond(readSourceLocation());
|
||||
E->setRBracketLoc(readSourceLocation());
|
||||
}
|
||||
|
||||
|
|
|
@ -797,7 +797,9 @@ void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
|
|||
Record.AddStmt(E->getBase());
|
||||
Record.AddStmt(E->getLowerBound());
|
||||
Record.AddStmt(E->getLength());
|
||||
Record.AddSourceLocation(E->getColonLoc());
|
||||
Record.AddStmt(E->getStride());
|
||||
Record.AddSourceLocation(E->getColonLocFirst());
|
||||
Record.AddSourceLocation(E->getColonLocSecond());
|
||||
Record.AddSourceLocation(E->getRBracketLoc());
|
||||
Code = serialization::EXPR_OMP_ARRAY_SECTION;
|
||||
}
|
||||
|
|
|
@ -45,5 +45,12 @@ int main(int argc, char **argv) {
|
|||
{
|
||||
foo();
|
||||
}
|
||||
|
||||
const int b = 5;
|
||||
int marr[10][10], iarr[5];
|
||||
#pragma omp target data map(to: marr[10][0:2:2]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
#pragma omp target data map(alloc: iarr[:2:b]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
foo();
|
||||
#pragma omp target depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
|
|
@ -76,7 +76,7 @@ int tmain(T argc, S **argv, R *env[]) {
|
|||
foo();
|
||||
#pragma omp target enter data map(to: i) depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target enter data map(to: i) depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target enter data map(to : i) depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target enter data map(to: i) depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
@ -149,9 +149,9 @@ int main(int argc, char **argv, char *env[]) {
|
|||
foo();
|
||||
#pragma omp target enter data map(to: i) depend (in : argv[-1:0]) // expected-error {{zero-length array section is not allowed in 'depend' clause}}
|
||||
foo();
|
||||
#pragma omp target enter data map(to: i) depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
#pragma omp target enter data map(to: i) depend(in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target enter data map(to: i) depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target enter data map(to : i) depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target enter data map(to: i) depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
|
|
@ -76,7 +76,7 @@ int tmain(T argc, S **argv, R *env[]) {
|
|||
foo();
|
||||
#pragma omp target exit data map(from: i) depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target exit data map(from: i) depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target exit data map(from : i) depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target exit data map(from: i) depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
@ -151,7 +151,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
foo();
|
||||
#pragma omp target exit data map(from: i) depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target exit data map(from: i) depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target exit data map(from : i) depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target exit data map(from: i) depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
|
|
@ -550,6 +550,12 @@ T tmain(T argc) {
|
|||
#pragma omp target data map(tofrom, close: x) // expected-error {{incorrect map type modifier, expected 'always', 'close', or 'mapper'}} expected-error {{missing map type}}
|
||||
#pragma omp target data map(close, tofrom: close, tofrom, x)
|
||||
foo();
|
||||
|
||||
T marr[10][10], iarr[5];
|
||||
#pragma omp target data map(marr[10][0:2:2]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
#pragma omp target data map(iarr[:2:d]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -737,6 +743,13 @@ int main(int argc, char **argv) {
|
|||
#pragma omp target map(release: a) // expected-error {{map type 'release' is not allowed for '#pragma omp target'}}
|
||||
{}
|
||||
|
||||
int marr[10][10], iarr[5];
|
||||
|
||||
#pragma omp target map(marr[10][0:2:2]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
#pragma omp target map(iarr[:2:d]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
{}
|
||||
|
||||
return tmain<int, 3>(argc)+tmain<from, 4>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 3>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<int, 4>' requested here}}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -74,7 +74,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
foo();
|
||||
#pragma omp target parallel depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target parallel depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target parallel depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target parallel depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target parallel for depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for simd depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for simd depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target parallel for simd depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target parallel for simd depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target simd depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target simd depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target simd depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target simd depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -74,7 +74,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
foo();
|
||||
#pragma omp target teams depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
foo();
|
||||
#pragma omp target teams depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target teams depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
foo();
|
||||
#pragma omp target teams depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
foo();
|
||||
|
|
|
@ -78,7 +78,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target teams distribute depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -79,7 +79,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target teams distribute parallel for depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -79,7 +79,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for simd depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for simd depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target teams distribute parallel for simd depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute parallel for simd depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -78,7 +78,7 @@ int main(int argc, char **argv, char *env[]) {
|
|||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute simd depend (in : argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute simd depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
#pragma omp target teams distribute simd depend(in : argv [3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
#pragma omp target teams distribute simd depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
|
||||
for (i = 0; i < argc; ++i) foo();
|
||||
|
|
|
@ -20,6 +20,11 @@ T foo(T targ, U uarg) {
|
|||
#pragma omp target update to(([a][targ])p, a) if(l>5) device(l) nowait depend(inout:l)
|
||||
|
||||
#pragma omp target update from(b, ([a][targ])p) if(l<5) device(l-1) nowait depend(inout:l)
|
||||
|
||||
int arr[100][100];
|
||||
#pragma omp target update to(arr[2][0:1:2])
|
||||
|
||||
#pragma omp target update from(arr[2][0:1:2])
|
||||
return a + targ + (T)b;
|
||||
}
|
||||
// CHECK: static T a, *p;
|
||||
|
@ -37,6 +42,9 @@ T foo(T targ, U uarg) {
|
|||
// CHECK-NEXT: int l;
|
||||
// CHECK-NEXT: #pragma omp target update to(([a][targ])p,a) if(l > 5) device(l) nowait depend(inout : l)
|
||||
// CHECK-NEXT: #pragma omp target update from(b,([a][targ])p) if(l < 5) device(l - 1) nowait depend(inout : l)
|
||||
// CHECK: int arr[100][100];
|
||||
// CHECK-NEXT: #pragma omp target update to(arr[2][0:1:2])
|
||||
// CHECK-NEXT: #pragma omp target update from(arr[2][0:1:2])
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static int a;
|
||||
|
@ -50,6 +58,11 @@ int main(int argc, char **argv) {
|
|||
// CHECK-NEXT: #pragma omp target update to(a) if(f > 0.) device(n) nowait depend(in : n)
|
||||
#pragma omp target update from(f) if(f<0.0) device(n+1) nowait depend(in:n)
|
||||
// CHECK-NEXT: #pragma omp target update from(f) if(f < 0.) device(n + 1) nowait depend(in : n)
|
||||
#pragma omp target update to(argv[2][0:1:2])
|
||||
// CHECK-NEXT: #pragma omp target update to(argv[2][0:1:2])
|
||||
#pragma omp target update from(argv[2][0:1:2])
|
||||
// CHECK-NEXT: #pragma omp target update from(argv[2][0:1:2])
|
||||
|
||||
return foo(argc, f) + foo(argv[0][0], f) + a;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
|
||||
|
||||
void xxx(int argc) {
|
||||
int x; // expected-note {{initialize the variable 'x' to silence this warning}}
|
||||
|
@ -36,5 +38,11 @@ int main(int argc, char **argv) {
|
|||
{
|
||||
foo();
|
||||
}
|
||||
|
||||
int iarr[5][5];
|
||||
#pragma omp target update to(iarr[0:][1:2:-1]) // omp50-error {{section stride is evaluated to a non-positive value -1}} omp45-error {{expected ']'}} omp45-note {{to match this '['}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
|
||||
{}
|
||||
#pragma omp target update from(iarr[0:][1:2:-1]) // omp50-error {{section stride is evaluated to a non-positive value -1}} omp45-error {{expected ']'}} omp45-note {{to match this '['}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
|
||||
|
||||
return tmain(argc, argv);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue