[OPENMP50]Add basic support for array-shaping operation.

Summary:
Added basic representation and parsing/sema handling of array-shaping
operations. Array shaping expression is an expression of form ([s0]..[sn])base,
where s0, ..., sn must be a positive integer, base - a pointer. This
expression is a kind of cast operation that converts pointer expression
into an array-like kind of expression.

Reviewers: rjmccall, rsmith, jdoerfert

Subscribers: guansong, arphaman, cfe-commits, caomhin, kkwli0

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74144
This commit is contained in:
Alexey Bataev 2020-02-05 09:33:05 -05:00
parent 01ba2ad9ef
commit 7ac9efb0c3
39 changed files with 456 additions and 23 deletions

View File

@ -2176,7 +2176,11 @@ enum CXCursorKind {
*/
CXCursor_FixedPointLiteral = 149,
CXCursor_LastExpr = CXCursor_FixedPointLiteral,
/** OpenMP 5.0 [2.1.4, Array Shaping].
*/
CXCursor_OMPArrayShapingExpr = 150,
CXCursor_LastExpr = CXCursor_OMPArrayShapingExpr,
/* Statements */
CXCursor_FirstStmt = 200,

View File

@ -970,7 +970,7 @@ public:
#include "clang/Basic/OpenCLImageTypes.def"
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType OMPArraySectionTy;
CanQualType OMPArraySectionTy, OMPArrayShapingTy;
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
CanQualType Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"

View File

@ -313,8 +313,11 @@ PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
// A placeholder type for OpenMP array sections.
PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy)
// A placeholder type for OpenMP array shaping operation.
PLACEHOLDER_TYPE(OMPArrayShaping, OMPArrayShapingTy)
#ifdef LAST_BUILTIN_TYPE
LAST_BUILTIN_TYPE(OMPArraySection)
LAST_BUILTIN_TYPE(OMPArrayShaping)
#undef LAST_BUILTIN_TYPE
#endif

View File

@ -87,6 +87,7 @@ class ParenListExpr;
class PseudoObjectExpr;
class AtomicExpr;
class OMPArraySectionExpr;
class OMPArrayShapingExpr;
class ObjCArrayLiteral;
class ObjCDictionaryLiteral;
class ObjCBoxedExpr;
@ -172,6 +173,7 @@ ExprDependence computeDependence(PseudoObjectExpr *E);
ExprDependence computeDependence(AtomicExpr *E);
ExprDependence computeDependence(OMPArraySectionExpr *E);
ExprDependence computeDependence(OMPArrayShapingExpr *E);
ExprDependence computeDependence(ObjCArrayLiteral *E);
ExprDependence computeDependence(ObjCDictionaryLiteral *E);

View File

@ -116,6 +116,95 @@ public:
return const_child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
}
};
/// An explicit cast in C or a C-style cast in C++, which uses the syntax
/// ([s1][s2]...[sn])expr. For example: @c ([3][3])f.
class OMPArrayShapingExpr final
: public Expr,
private llvm::TrailingObjects<OMPArrayShapingExpr, Expr *, SourceRange> {
friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
/// Base node.
SourceLocation LPLoc; /// The location of the left paren
SourceLocation RPLoc; /// The location of the right paren
unsigned NumDims = 0; /// Number of dimensions in the shaping expression.
/// Construct full expression.
OMPArrayShapingExpr(QualType ExprTy, Expr *Op, SourceLocation L,
SourceLocation R, ArrayRef<Expr *> Dims);
/// Construct an empty expression.
explicit OMPArrayShapingExpr(EmptyShell Shell, unsigned NumDims)
: Expr(OMPArrayShapingExprClass, Shell), NumDims(NumDims) {}
/// Sets the dimensions for the array shaping.
void setDimensions(ArrayRef<Expr *> Dims);
/// Sets the base expression for array shaping operation.
void setBase(Expr *Op) { getTrailingObjects<Expr *>()[NumDims] = Op; }
/// Sets source ranges for the brackets in the array shaping operation.
void setBracketsRanges(ArrayRef<SourceRange> BR);
unsigned numTrailingObjects(OverloadToken<Expr *>) const {
// Add an extra one for the base expression.
return NumDims + 1;
}
unsigned numTrailingObjects(OverloadToken<SourceRange>) const {
return NumDims;
}
public:
static OMPArrayShapingExpr *Create(const ASTContext &Context, QualType T,
Expr *Op, SourceLocation L,
SourceLocation R, ArrayRef<Expr *> Dims,
ArrayRef<SourceRange> BracketRanges);
static OMPArrayShapingExpr *CreateEmpty(const ASTContext &Context,
unsigned NumDims);
SourceLocation getLParenLoc() const { return LPLoc; }
void setLParenLoc(SourceLocation L) { LPLoc = L; }
SourceLocation getRParenLoc() const { return RPLoc; }
void setRParenLoc(SourceLocation L) { RPLoc = L; }
SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; }
SourceLocation getEndLoc() const LLVM_READONLY {
return getBase()->getEndLoc();
}
/// Fetches the dimensions for array shaping expression.
ArrayRef<Expr *> getDimensions() const {
return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumDims);
}
/// Fetches source ranges for the brackets os the array shaping expression.
ArrayRef<SourceRange> getBracketsRanges() const {
return llvm::makeArrayRef(getTrailingObjects<SourceRange>(), NumDims);
}
/// Fetches base expression of array shaping expression.
Expr *getBase() { return getTrailingObjects<Expr *>()[NumDims]; }
const Expr *getBase() const { return getTrailingObjects<Expr *>()[NumDims]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPArrayShapingExprClass;
}
// Iterators
child_range children() {
Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
return child_range(Begin, Begin + NumDims + 1);
}
const_child_range children() const {
Stmt *const *Begin =
reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
return const_child_range(Begin, Begin + NumDims + 1);
}
};
} // end namespace clang
#endif

View File

@ -2551,6 +2551,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
DEF_TRAVERSE_STMT(AddrLabelExpr, {})
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
DEF_TRAVERSE_STMT(OMPArraySectionExpr, {})
DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {})
DEF_TRAVERSE_STMT(BlockExpr, {
TRY_TO(TraverseDecl(S->getBlockDecl()));

View File

@ -9685,7 +9685,7 @@ def err_omp_expected_var_name_member_expr : Error<
def err_omp_expected_var_name_member_expr_or_array_item : Error<
"expected variable name%select{|, data member of current class}0, array element or array section">;
def err_omp_expected_addressable_lvalue_or_array_item : Error<
"expected addressable lvalue expression, array element or array section%select{| of non 'omp_depend_t' type}0">;
"expected addressable lvalue expression, array element%select{ or array section|, array section or array shaping expression}0%select{| of non 'omp_depend_t' type}1">;
def err_omp_expected_named_var_member_or_array_expression: Error<
"expected expression containing only member accesses and/or array sections based on named variables">;
def err_omp_bit_fields_forbidden_in_clause : Error<
@ -9952,10 +9952,15 @@ def err_omp_declare_mapper_redefinition : Error<
def err_omp_invalid_mapper: Error<
"cannot find a valid user-defined mapper for type %0 with name %1">;
def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">;
def err_omp_array_shaping_use : Error<"OpenMP array shaping operation is not allowed here">;
def err_omp_typecheck_section_value : Error<
"subscripted value is not an array or pointer">;
def err_omp_typecheck_section_not_integer : Error<
"array section %select{lower bound|length}0 is not an integer">;
def err_omp_typecheck_shaping_not_integer : Error<
"array shaping operation dimension is not an integer">;
def err_omp_shaping_dimension_not_positive : Error<
"array shaping dimension is evaluated to a non-positive value %0">;
def err_omp_section_function_type : Error<
"section of pointer to function type %0">;
def warn_omp_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">,
@ -10190,14 +10195,15 @@ def err_omp_flush_order_clause_and_list : Error<
def note_omp_flush_order_clause_here : Note<
"memory order clause '%0' is specified here">;
def err_omp_non_lvalue_in_map_or_motion_clauses: Error<
"expected addressable lvalue in '%0' clause"
>;
"expected addressable lvalue in '%0' clause">;
def err_omp_event_var_expected : Error<
"expected variable of the 'omp_event_handle_t' type%select{|, not %1}0">;
def warn_nested_declare_variant
: Warning<"nesting `omp begin/end declare variant` is not supported yet; "
"nested context ignored">,
InGroup<SourceUsesOpenMP>;
def err_omp_non_pointer_type_array_shaping_base : Error<
"expected pointer type expression as a base of an array shaping operation">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {

View File

@ -81,6 +81,7 @@ def BinaryConditionalOperator : StmtNode<AbstractConditionalOperator>;
def ImplicitCastExpr : StmtNode<CastExpr>;
def ExplicitCastExpr : StmtNode<CastExpr, 1>;
def CStyleCastExpr : StmtNode<ExplicitCastExpr>;
def OMPArrayShapingExpr : StmtNode<Expr>;
def CompoundLiteralExpr : StmtNode<Expr>;
def ExtVectorElementExpr : StmtNode<Expr>;
def InitListExpr : StmtNode<Expr>;

View File

@ -3010,6 +3010,10 @@ private:
DeclarationName &Name,
AccessSpecifier AS = AS_none);
/// Tries to parse cast part of OpenMP array shaping operation:
/// '[' expression ']' { '[' expression ']' } ')'.
bool tryParseOpenMPArrayShapingCastPart();
/// Parses simple list of variables.
///
/// \param Kind Kind of the directive.

View File

@ -4899,6 +4899,10 @@ public:
ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
Expr *LowerBound, SourceLocation ColonLoc,
Expr *Length, SourceLocation RBLoc);
ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
SourceLocation RParenLoc,
ArrayRef<Expr *> Dims,
ArrayRef<SourceRange> Brackets);
// This struct is for use by ActOnMemberAccess to allow
// BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after

View File

@ -1016,6 +1016,9 @@ namespace serialization {
/// \brief The '_Sat unsigned long _Fract' type
PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69,
/// The placeholder type for OpenMP array shaping operation.
PREDEF_TYPE_OMP_ARRAY_SHAPING = 70,
/// OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
@ -1868,6 +1871,7 @@ namespace serialization {
STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE,
STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE,
EXPR_OMP_ARRAY_SECTION,
EXPR_OMP_ARRAY_SHAPING,
// ARC
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr

View File

@ -1386,8 +1386,10 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn);
// Placeholder type for OMP array sections.
if (LangOpts.OpenMP)
if (LangOpts.OpenMP) {
InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection);
InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping);
}
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);

View File

@ -363,6 +363,15 @@ ExprDependence clang::computeDependence(OMPArraySectionExpr *E) {
return D;
}
ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) {
auto D = E->getBase()->getDependence() |
toExprDependence(E->getType()->getDependence());
for (Expr *Dim: E->getDimensions())
if (Dim)
D |= Dim->getDependence();
return D;
}
/// Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.

View File

@ -3398,6 +3398,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ParenExprClass:
case ArraySubscriptExprClass:
case OMPArraySectionExprClass:
case OMPArrayShapingExprClass:
case MemberExprClass:
case ConditionalOperatorClass:
case BinaryConditionalOperatorClass:
@ -4569,3 +4570,50 @@ RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs) {
alignof(RecoveryExpr));
return new (Mem) RecoveryExpr(EmptyShell());
}
void OMPArrayShapingExpr::setDimensions(ArrayRef<Expr *> Dims) {
assert(
NumDims == Dims.size() &&
"Preallocated number of dimensions is different from the provided one.");
llvm::copy(Dims, getTrailingObjects<Expr *>());
}
void OMPArrayShapingExpr::setBracketsRanges(ArrayRef<SourceRange> BR) {
assert(
NumDims == BR.size() &&
"Preallocated number of dimensions is different from the provided one.");
llvm::copy(BR, getTrailingObjects<SourceRange>());
}
OMPArrayShapingExpr::OMPArrayShapingExpr(QualType ExprTy, Expr *Op,
SourceLocation L, SourceLocation R,
ArrayRef<Expr *> Dims)
: Expr(OMPArrayShapingExprClass, ExprTy, VK_LValue, OK_Ordinary), LPLoc(L),
RPLoc(R), NumDims(Dims.size()) {
setBase(Op);
setDimensions(Dims);
setDependence(computeDependence(this));
}
OMPArrayShapingExpr *
OMPArrayShapingExpr::Create(const ASTContext &Context, QualType T, Expr *Op,
SourceLocation L, SourceLocation R,
ArrayRef<Expr *> Dims,
ArrayRef<SourceRange> BracketRanges) {
assert(Dims.size() == BracketRanges.size() &&
"Different number of dimensions and brackets ranges.");
void *Mem = Context.Allocate(
totalSizeToAlloc<Expr *, SourceRange>(Dims.size() + 1, Dims.size()),
alignof(OMPArrayShapingExpr));
auto *E = new (Mem) OMPArrayShapingExpr(T, Op, L, R, Dims);
E->setBracketsRanges(BracketRanges);
return E;
}
OMPArrayShapingExpr *OMPArrayShapingExpr::CreateEmpty(const ASTContext &Context,
unsigned NumDims) {
void *Mem = Context.Allocate(
totalSizeToAlloc<Expr *, SourceRange>(NumDims + 1, NumDims),
alignof(OMPArrayShapingExpr));
return new (Mem) OMPArrayShapingExpr(EmptyShell(), NumDims);
}

View File

@ -140,6 +140,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::MSPropertyRefExprClass:
case Expr::MSPropertySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.

View File

@ -14180,6 +14180,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::StringLiteralClass:
case Expr::ArraySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::MemberExprClass:
case Expr::CompoundAssignOperatorClass:
case Expr::CompoundLiteralExprClass:

View File

@ -3714,6 +3714,7 @@ recurse:
case Expr::TypoExprClass: // This should no longer exist in the AST by now.
case Expr::RecoveryExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::CXXInheritedCtorInitExprClass:
llvm_unreachable("unexpected statement kind");

View File

@ -483,6 +483,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::PseudoObject:
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
break;
}

View File

@ -1350,6 +1350,17 @@ void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) {
OS << "]";
}
void StmtPrinter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *Node) {
OS << "(";
for (Expr *E : Node->getDimensions()) {
OS << "[";
PrintExpr(E);
OS << "]";
}
OS << ")";
PrintExpr(Node->getBase());
}
void StmtPrinter::PrintCallArgs(CallExpr *Call) {
for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {

View File

@ -1194,6 +1194,10 @@ void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitOMPArrayShapingExpr(const OMPArrayShapingExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitCallExpr(const CallExpr *S) {
VisitExpr(S);
}

View File

@ -2908,6 +2908,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
return "reserve_id_t";
case OMPArraySection:
return "<OpenMP array section type>";
case OMPArrayShaping:
return "<OpenMP array shaping type>";
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case Id: \
return #ExtType;
@ -3914,6 +3916,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
return false;
}
llvm_unreachable("unknown builtin type");

View File

@ -404,6 +404,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
return TST_unspecified;
}

View File

@ -2648,6 +2648,33 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
return ParsePostfixExpressionSuffix(Res.get());
}
bool Parser::tryParseOpenMPArrayShapingCastPart() {
assert(Tok.is(tok::l_square) && "Expected open bracket");
bool ErrorFound = true;
TentativeParsingAction TPA(*this);
do {
if (Tok.isNot(tok::l_square))
break;
// Consume '['
ConsumeBracket();
// Skip inner expression.
while (!SkipUntil(tok::r_square, tok::annot_pragma_openmp_end,
StopAtSemi | StopBeforeMatch))
;
if (Tok.isNot(tok::r_square))
break;
// Consume ']'
ConsumeBracket();
// Found ')' - done.
if (Tok.is(tok::r_paren)) {
ErrorFound = false;
break;
}
} while (Tok.isNot(tok::annot_pragma_openmp_end));
TPA.Revert();
return !ErrorFound;
}
/// ParseParenExpression - This parses the unit that starts with a '(' token,
/// based on what is allowed by ExprType. The actual thing parsed is returned
/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type,
@ -2672,6 +2699,8 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
/// '(' '...' fold-operator cast-expression ')'
/// '(' cast-expression fold-operator '...'
/// fold-operator cast-expression ')'
/// [OPENMP] Array shaping operation
/// '(' '[' expression ']' { '[' expression ']' } cast-expression
/// \endverbatim
ExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
@ -2948,6 +2977,38 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
ArgExprs);
}
} else if (getLangOpts().OpenMP >= 50 && OpenMPDirectiveParsing &&
ExprType == CastExpr && Tok.is(tok::l_square) &&
tryParseOpenMPArrayShapingCastPart()) {
bool ErrorFound = false;
SmallVector<Expr *, 4> OMPDimensions;
SmallVector<SourceRange, 4> OMPBracketsRanges;
do {
BalancedDelimiterTracker TS(*this, tok::l_square);
TS.consumeOpen();
ExprResult NumElements =
Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (!NumElements.isUsable()) {
ErrorFound = true;
while (!SkipUntil(tok::r_square, tok::r_paren,
StopAtSemi | StopBeforeMatch))
;
}
TS.consumeClose();
OMPDimensions.push_back(NumElements.get());
OMPBracketsRanges.push_back(TS.getRange());
} while (Tok.isNot(tok::r_paren));
// Match the ')'.
T.consumeClose();
RParenLoc = T.getCloseLocation();
Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (ErrorFound) {
Result = ExprError();
} else if (!Result.isInvalid()) {
Result = Actions.ActOnOMPArrayShapingExpr(
Result.get(), OpenLoc, RParenLoc, OMPDimensions, OMPBracketsRanges);
}
return Result;
} else {
InMessageExpressionRAIIObject InMessage(*this, false);

View File

@ -1299,6 +1299,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::BinaryOperatorClass:
case Expr::DependentCoawaitExprClass:
case Expr::CompoundAssignOperatorClass:

View File

@ -4798,6 +4798,75 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
}
ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
SourceLocation RParenLoc,
ArrayRef<Expr *> Dims,
ArrayRef<SourceRange> Brackets) {
if (Base->getType()->isPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(Base);
if (Result.isInvalid())
return ExprError();
Base = Result.get();
}
QualType BaseTy = Base->getType();
// Delay analysis of the types/expressions if instantiation/specialization is
// required.
if (!BaseTy->isPointerType() && Base->isTypeDependent())
return OMPArrayShapingExpr::Create(Context, Context.DependentTy, Base,
LParenLoc, RParenLoc, Dims, Brackets);
if (!BaseTy->isPointerType())
return ExprError(Diag(Base->getExprLoc(),
diag::err_omp_non_pointer_type_array_shaping_base)
<< Base->getSourceRange());
SmallVector<Expr *, 4> NewDims;
bool ErrorFound = false;
for (Expr *Dim : Dims) {
if (Dim->getType()->isPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(Dim);
if (Result.isInvalid()) {
ErrorFound = true;
continue;
}
Result = DefaultLvalueConversion(Result.get());
if (Result.isInvalid()) {
ErrorFound = true;
continue;
}
Dim = Result.get();
}
if (!Dim->isTypeDependent()) {
ExprResult Result =
PerformOpenMPImplicitIntegerConversion(Dim->getExprLoc(), Dim);
if (Result.isInvalid()) {
ErrorFound = true;
Diag(Dim->getExprLoc(), diag::err_omp_typecheck_shaping_not_integer)
<< Dim->getSourceRange();
continue;
}
Dim = Result.get();
Expr::EvalResult EvResult;
if (!Dim->isValueDependent() && Dim->EvaluateAsInt(EvResult, Context)) {
// OpenMP 5.0, [2.1.4 Array Shaping]
// Each si is an integral type expression that must evaluate to a
// positive integer.
llvm::APSInt Value = EvResult.Val.getInt();
if (!Value.isStrictlyPositive()) {
Diag(Dim->getExprLoc(), diag::err_omp_shaping_dimension_not_positive)
<< Value.toString(/*Radix=*/10, /*Signed=*/true)
<< Dim->getSourceRange();
ErrorFound = true;
continue;
}
}
}
NewDims.push_back(Dim);
}
if (ErrorFound)
return ExprError();
return OMPArrayShapingExpr::Create(Context, Context.OMPArrayShapingTy, Base,
LParenLoc, RParenLoc, NewDims, Brackets);
}
ExprResult
Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@ -5558,6 +5627,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
case BuiltinType::BoundMember:
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
return true;
}
@ -18433,6 +18503,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
Diag(E->getBeginLoc(), diag::err_omp_array_section_use);
return ExprError();
// Expressions of unknown type.
case BuiltinType::OMPArrayShaping:
return ExprError(Diag(E->getBeginLoc(), diag::err_omp_array_shaping_use));
// Everything else should be impossible.
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:

View File

@ -15824,7 +15824,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
(OMPDependTFound &&
DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< 1 << RefExpr->getSourceRange();
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << 1
<< RefExpr->getSourceRange();
continue;
}
@ -15837,6 +15838,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
->isPointerType() &&
!ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
continue;
}
@ -15847,8 +15849,10 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
RefExpr->IgnoreParenImpCasts());
}
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
!isa<OMPArrayShapingExpr>(SimpleExpr)) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
continue;
}

View File

@ -2379,6 +2379,18 @@ public:
ColonLoc, Length, RBracketLoc);
}
/// Build a new array shaping expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
SourceLocation RParenLoc,
ArrayRef<Expr *> Dims,
ArrayRef<SourceRange> BracketsRanges) {
return getSema().ActOnOMPArrayShapingExpr(Base, LParenLoc, RParenLoc, Dims,
BracketsRanges);
}
/// Build a new call expression.
///
/// By default, performs semantic analysis to build the new expression.
@ -10017,6 +10029,31 @@ TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) {
Length.get(), E->getRBracketLoc());
}
template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
ExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return ExprError();
SmallVector<Expr *, 4> Dims;
bool ErrorFound = false;
for (Expr *Dim : E->getDimensions()) {
ExprResult DimRes = getDerived().TransformExpr(Dim);
if (DimRes.isInvalid()) {
ErrorFound = true;
continue;
}
Dims.push_back(DimRes.get());
}
if (ErrorFound)
return ExprError();
return getDerived().RebuildOMPArrayShapingExpr(Base.get(), E->getLParenLoc(),
E->getRParenLoc(), Dims,
E->getBracketsRanges());
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {

View File

@ -243,6 +243,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::OMPArraySection:
ID = PREDEF_TYPE_OMP_ARRAY_SECTION;
break;
case BuiltinType::OMPArrayShaping:
ID = PREDEF_TYPE_OMP_ARRAY_SHAPING;
break;
}
return TypeIdx(ID);

View File

@ -6957,6 +6957,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_OMP_ARRAY_SECTION:
T = Context.OMPArraySectionTy;
break;
case PREDEF_TYPE_OMP_ARRAY_SHAPING:
T = Context.OMPArraySectionTy;
break;
#define SVE_TYPE(Name, Id, SingletonId) \
case PREDEF_TYPE_##Id##_ID: \
T = Context.SingletonId; \

View File

@ -911,6 +911,22 @@ void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
VisitExpr(E);
unsigned NumDims = Record.readInt();
E->setBase(Record.readSubExpr());
SmallVector<Expr *, 4> Dims(NumDims);
for (unsigned I = 0; I < NumDims; ++I)
Dims[I] = Record.readSubExpr();
E->setDimensions(Dims);
SmallVector<SourceRange, 4> SRs(NumDims);
for (unsigned I = 0; I < NumDims; ++I)
SRs[I] = readSourceRange();
E->setBracketsRanges(SRs);
E->setLParenLoc(readSourceLocation());
E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
unsigned NumArgs = Record.readInt();
@ -2866,6 +2882,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) OMPArraySectionExpr(Empty);
break;
case EXPR_OMP_ARRAY_SHAPING:
S = OMPArrayShapingExpr::CreateEmpty(
Context, Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CALL:
S = CallExpr::CreateEmpty(
Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty);

View File

@ -774,6 +774,19 @@ void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
Code = serialization::EXPR_OMP_ARRAY_SECTION;
}
void ASTStmtWriter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
VisitExpr(E);
Record.push_back(E->getDimensions().size());
Record.AddStmt(E->getBase());
for (Expr *Dim : E->getDimensions())
Record.AddStmt(Dim);
for (SourceRange SR : E->getBracketsRanges())
Record.AddSourceRange(SR);
Record.AddSourceLocation(E->getLParenLoc());
Record.AddSourceLocation(E->getRParenLoc());
Code = serialization::EXPR_OMP_ARRAY_SHAPING;
}
void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());

View File

@ -351,6 +351,7 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
case Stmt::CallExprClass:
case Stmt::ArraySubscriptExprClass:
case Stmt::OMPArraySectionExprClass:
case Stmt::OMPArrayShapingExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::ParenExprClass:
case Stmt::BreakStmtClass:

View File

@ -1413,6 +1413,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass:
case Stmt::OMPArraySectionExprClass:
case Stmt::OMPArrayShapingExprClass:
case Stmt::TypeTraitExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet preVisit;

View File

@ -158,7 +158,7 @@ label1 : {
#pragma omp depend(out:x) depobj(x) // expected-error {{expected an OpenMP directive}}
#pragma omp destroy depobj(x) // expected-error {{expected an OpenMP directive}}
#pragma omp update(out) depobj(x) // expected-error {{expected an OpenMP directive}}
#pragma omp depobj depend(in:x) (x) // expected-error {{expected depobj expression}} expected-warning {{extra tokens at the end of '#pragma omp depobj' are ignored}} expected-error {{expected addressable lvalue expression, array element or array section of non 'omp_depend_t' type}}
#pragma omp depobj depend(in:x) (x) // expected-error {{expected depobj expression}} expected-warning {{extra tokens at the end of '#pragma omp depobj' are ignored}} expected-error {{expected addressable lvalue expression, array element, array section or array shaping expression of non 'omp_depend_t' type}}
#pragma omp depobj destroy (x) // expected-error {{expected depobj expression}} expected-warning {{extra tokens at the end of '#pragma omp depobj' are ignored}}
#pragma omp depobj update(in) (x) // expected-error {{expected depobj expression}} expected-warning {{extra tokens at the end of '#pragma omp depobj' are ignored}}
return tmain(argc); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}}

View File

@ -2,7 +2,7 @@
int incomplete[];
void test() {
void test(int *p) {
int a;
#pragma omp parallel reduction( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}}
;
@ -16,7 +16,7 @@ void test() {
;
#pragma omp parallel reduction(inscan, + : a) // expected-error {{'inscan' modifier can be used only in 'omp for', 'omp simd', 'omp for simd', 'omp parallel for', or 'omp parallel for simd' directive}}
;
#pragma omp parallel reduction(+ : incomplete) // expected-error {{a reduction list item with incomplete type 'int []'}}
#pragma omp parallel reduction(+ : incomplete, ([10])p) // expected-error {{a reduction list item with incomplete type 'int []'}} expected-error {{expected variable name, array element or array section}}
;
}

View File

@ -99,7 +99,7 @@ T tmain(T argc, T *argv) {
T arr[argc];
omp_depend_t x;
omp_event_handle_t evt;
#pragma omp task untied depend(in : argc, argv[b:argc], arr[:]) if (task : argc > 0) depend(depobj: x) detach(evt)
#pragma omp task untied depend(in : argc, argv[b:argc], arr[:], ([argc][sizeof(T)])argv) if (task : argc > 0) depend(depobj: x) detach(evt)
a = 2;
#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) priority(argc)
foo();
@ -116,7 +116,7 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: T arr[argc];
// CHECK-NEXT: omp_depend_t x;
// CHECK-NEXT: omp_event_handle_t evt;
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(T)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
@ -130,7 +130,7 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: int arr[argc];
// CHECK-NEXT: omp_depend_t x;
// CHECK-NEXT: omp_event_handle_t evt;
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(int)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
@ -144,7 +144,7 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: long arr[argc];
// CHECK-NEXT: omp_depend_t x;
// CHECK-NEXT: omp_event_handle_t evt;
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(long)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
@ -164,14 +164,14 @@ int main(int argc, char **argv) {
#pragma omp threadprivate(a)
Enum ee;
// CHECK: Enum ee;
#pragma omp task untied mergeable depend(out:argv[:a][1], (arr)[0:]) if(task: argc > 0) priority(f) depend(depobj:y)
// CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[:a][1],(arr)[0:]) if(task: argc > 0) priority(f) depend(depobj : y)
#pragma omp task untied mergeable depend(out:argv[:a][1], (arr)[0:],([argc][10])argv) if(task: argc > 0) priority(f) depend(depobj:y)
// CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[:a][1],(arr)[0:],([argc][10])argv) if(task: argc > 0) priority(f) depend(depobj : y)
a = 2;
// CHECK-NEXT: a = 2;
#pragma omp taskgroup task_reduction(min: arr1)
#pragma omp task default(none), private(argc, b) firstprivate(argv, evt) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1), detach(evt)
#pragma omp task default(none), private(argc, b) firstprivate(argv, evt) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a], ([10][argc])argv) priority(23) in_reduction(min: arr1), detach(evt)
// CHECK-NEXT: #pragma omp taskgroup task_reduction(min: arr1)
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv,evt) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1) detach(evt)
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv,evt) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a],([10][argc])argv) priority(23) in_reduction(min: arr1) detach(evt)
foo();
// CHECK-NEXT: foo();
#pragma omp taskgroup task_reduction(min: arr1)

View File

@ -35,14 +35,14 @@ int main(int argc, char **argv, char *env[]) {
#pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}}
#pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
#pragma omp task depend (out: ) // expected-error {{expected expression}}
#pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
#pragma omp task depend (inout : foobool(argc)), depend (in, argc) // omp50-error {{expected addressable lvalue expression, array element, array section or array shaping expression}} omp45-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
#pragma omp task depend (out :S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp task depend(in : argv[1][1] = '2')
#pragma omp task depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend (in : vec[1]) // omp50-error {{expected addressable lvalue expression, array element, array section or array shaping expression}} omp45-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend (in : argv[0])
#pragma omp task depend (in : ) // expected-error {{expected expression}}
#pragma omp task depend (in : main)
#pragma omp task depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend(in : a[0]) // omp50-error {{expected addressable lvalue expression, array element, array section or array shaping expression}} omp45-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
#pragma omp task depend (in : argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
#pragma omp task depend (in : argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
@ -62,6 +62,14 @@ int main(int argc, char **argv, char *env[]) {
#pragma omp task depend(depobj:argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected lvalue expression of 'omp_depend_t' type, not 'int'}}
#pragma omp task depend(depobj : argv[ : argc][1 : argc - 1]) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected lvalue expression of 'omp_depend_t' type, not '<OpenMP array section type>'}}
#pragma omp task depend(depobj : arr[0]) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}}
#pragma omp task depend(in : ([ // expected-error {{expected variable name or 'this' in lambda capture list}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp task depend(in : ([] // expected-error {{expected body of lambda expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp task depend(in : ([]) // omp45-error {{expected body of lambda expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp50-error 2 {{expected expression}}
#pragma omp task depend(in : ([])a // omp45-error {{expected body of lambda expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp50-error {{expected expression}}
#pragma omp task depend(in : ([])a) // omp45-error {{expected body of lambda expression}} omp50-error {{expected expression}}
#pragma omp task depend(in : ([a])a) // omp45-error {{expected body of lambda expression}} omp50-error {{expected pointer type expression as a base of an array shaping operation}}
#pragma omp task depend(in : ([a])argc) // omp45-error {{expected body of lambda expression}} omp50-error {{expected pointer type expression as a base of an array shaping operation}}
#pragma omp task depend(in : ([-1][0])argv) // omp45-error {{expected variable name or 'this' in lambda capture list}} omp45-error {{expected ')'}} omp45-note {{to match this '('}} omp50-error {{array shaping dimension is evaluated to a non-positive value -1}} omp50-error {{array shaping dimension is evaluated to a non-positive value 0}}
foo();
return 0;

View File

@ -5183,6 +5183,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("ArraySubscriptExpr");
case CXCursor_OMPArraySectionExpr:
return cxstring::createRef("OMPArraySectionExpr");
case CXCursor_OMPArrayShapingExpr:
return cxstring::createRef("OMPArrayShapingExpr");
case CXCursor_BinaryOperator:
return cxstring::createRef("BinaryOperator");
case CXCursor_CompoundAssignOperator:

View File

@ -423,6 +423,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_OMPArraySectionExpr;
break;
case Stmt::OMPArrayShapingExprClass:
K = CXCursor_OMPArrayShapingExpr;
break;
case Stmt::BinaryOperatorClass:
K = CXCursor_BinaryOperator;
break;