diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2176,7 +2176,11 @@ */ 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, diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -970,7 +970,7 @@ #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" diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -313,8 +313,11 @@ // 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 diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -87,6 +87,7 @@ class PseudoObjectExpr; class AtomicExpr; class OMPArraySectionExpr; +class OMPArrayShapingExpr; class ObjCArrayLiteral; class ObjCDictionaryLiteral; class ObjCBoxedExpr; @@ -172,6 +173,7 @@ ExprDependence computeDependence(AtomicExpr *E); ExprDependence computeDependence(OMPArraySectionExpr *E); +ExprDependence computeDependence(OMPArrayShapingExpr *E); ExprDependence computeDependence(ObjCArrayLiteral *E); ExprDependence computeDependence(ObjCDictionaryLiteral *E); diff --git a/clang/include/clang/AST/ExprOpenMP.h b/clang/include/clang/AST/ExprOpenMP.h --- a/clang/include/clang/AST/ExprOpenMP.h +++ b/clang/include/clang/AST/ExprOpenMP.h @@ -116,6 +116,95 @@ 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 { + 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 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 Dims); + + /// Sets the base expression for array shaping operation. + void setBase(Expr *Op) { getTrailingObjects()[NumDims] = Op; } + + /// Sets source ranges for the brackets in the array shaping operation. + void setBracketsRanges(ArrayRef BR); + + unsigned numTrailingObjects(OverloadToken) const { + // Add an extra one for the base expression. + return NumDims + 1; + } + + unsigned numTrailingObjects(OverloadToken) const { + return NumDims; + } + +public: + static OMPArrayShapingExpr *Create(const ASTContext &Context, QualType T, + Expr *Op, SourceLocation L, + SourceLocation R, ArrayRef Dims, + ArrayRef 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 getDimensions() const { + return llvm::makeArrayRef(getTrailingObjects(), NumDims); + } + + /// Fetches source ranges for the brackets os the array shaping expression. + ArrayRef getBracketsRanges() const { + return llvm::makeArrayRef(getTrailingObjects(), NumDims); + } + + /// Fetches base expression of array shaping expression. + Expr *getBase() { return getTrailingObjects()[NumDims]; } + const Expr *getBase() const { return getTrailingObjects()[NumDims]; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPArrayShapingExprClass; + } + + // Iterators + child_range children() { + Stmt **Begin = reinterpret_cast(getTrailingObjects()); + return child_range(Begin, Begin + NumDims + 1); + } + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast(getTrailingObjects()); + return const_child_range(Begin, Begin + NumDims + 1); + } +}; } // end namespace clang #endif diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2551,6 +2551,7 @@ 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())); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9685,7 +9685,7 @@ 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_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 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; +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 { diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -81,6 +81,7 @@ def ImplicitCastExpr : StmtNode; def ExplicitCastExpr : StmtNode; def CStyleCastExpr : StmtNode; +def OMPArrayShapingExpr : StmtNode; def CompoundLiteralExpr : StmtNode; def ExtVectorElementExpr : StmtNode; def InitListExpr : StmtNode; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3010,6 +3010,10 @@ 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. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4899,6 +4899,10 @@ ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); + ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef Dims, + ArrayRef Brackets); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1016,6 +1016,9 @@ /// \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 @@ 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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1386,8 +1386,10 @@ 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); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -363,6 +363,15 @@ 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. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3398,6 +3398,7 @@ case ParenExprClass: case ArraySubscriptExprClass: case OMPArraySectionExprClass: + case OMPArrayShapingExprClass: case MemberExprClass: case ConditionalOperatorClass: case BinaryConditionalOperatorClass: @@ -4569,3 +4570,50 @@ alignof(RecoveryExpr)); return new (Mem) RecoveryExpr(EmptyShell()); } + +void OMPArrayShapingExpr::setDimensions(ArrayRef Dims) { + assert( + NumDims == Dims.size() && + "Preallocated number of dimensions is different from the provided one."); + llvm::copy(Dims, getTrailingObjects()); +} + +void OMPArrayShapingExpr::setBracketsRanges(ArrayRef BR) { + assert( + NumDims == BR.size() && + "Preallocated number of dimensions is different from the provided one."); + llvm::copy(BR, getTrailingObjects()); +} + +OMPArrayShapingExpr::OMPArrayShapingExpr(QualType ExprTy, Expr *Op, + SourceLocation L, SourceLocation R, + ArrayRef 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 Dims, + ArrayRef BracketRanges) { + assert(Dims.size() == BracketRanges.size() && + "Different number of dimensions and brackets ranges."); + void *Mem = Context.Allocate( + totalSizeToAlloc(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(NumDims + 1, NumDims), + alignof(OMPArrayShapingExpr)); + return new (Mem) OMPArrayShapingExpr(EmptyShell(), NumDims); +} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -140,6 +140,7 @@ 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. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14180,6 +14180,7 @@ case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3714,6 +3714,7 @@ 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"); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -483,6 +483,7 @@ case BuiltinType::PseudoObject: case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: break; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1350,6 +1350,17 @@ 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(Call->getArg(i))) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1194,6 +1194,10 @@ VisitExpr(S); } +void StmtProfiler::VisitOMPArrayShapingExpr(const OMPArrayShapingExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2908,6 +2908,8 @@ return "reserve_id_t"; case OMPArraySection: return ""; + case OMPArrayShaping: + return ""; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case Id: \ return #ExtType; @@ -3914,6 +3916,7 @@ case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: return false; } llvm_unreachable("unknown builtin type"); diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -404,6 +404,7 @@ #include "clang/Basic/AArch64SVEACLETypes.def" case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: return TST_unspecified; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2648,6 +2648,33 @@ 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 @@ /// '(' '...' 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 @@ 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 OMPDimensions; + SmallVector 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); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1299,6 +1299,7 @@ // 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: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4798,6 +4798,75 @@ VK_LValue, OK_Ordinary, ColonLoc, RBLoc); } +ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef Dims, + ArrayRef 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 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 @@ case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: return true; } @@ -18433,6 +18503,10 @@ 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: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -15824,7 +15824,8 @@ (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 @@ ->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 @@ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); } - if (!Res.isUsable() && !isa(SimpleExpr)) { + if (!Res.isUsable() && !isa(SimpleExpr) && + !isa(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; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2379,6 +2379,18 @@ 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 Dims, + ArrayRef 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 @@ Length.get(), E->getRBracketLoc()); } +template +ExprResult +TreeTransform::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + SmallVector 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 ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -243,6 +243,9 @@ case BuiltinType::OMPArraySection: ID = PREDEF_TYPE_OMP_ARRAY_SECTION; break; + case BuiltinType::OMPArrayShaping: + ID = PREDEF_TYPE_OMP_ARRAY_SHAPING; + break; } return TypeIdx(ID); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6957,6 +6957,9 @@ 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; \ diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -911,6 +911,22 @@ E->setRBracketLoc(readSourceLocation()); } +void ASTStmtReader::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + VisitExpr(E); + unsigned NumDims = Record.readInt(); + E->setBase(Record.readSubExpr()); + SmallVector Dims(NumDims); + for (unsigned I = 0; I < NumDims; ++I) + Dims[I] = Record.readSubExpr(); + E->setDimensions(Dims); + SmallVector 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 @@ 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); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -774,6 +774,19 @@ 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()); diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -351,6 +351,7 @@ case Stmt::CallExprClass: case Stmt::ArraySubscriptExprClass: case Stmt::OMPArraySectionExprClass: + case Stmt::OMPArrayShapingExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ParenExprClass: case Stmt::BreakStmtClass: diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1413,6 +1413,7 @@ case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: case Stmt::OMPArraySectionExprClass: + case Stmt::OMPArrayShapingExprClass: case Stmt::TypeTraitExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; diff --git a/clang/test/OpenMP/depobj_messages.cpp b/clang/test/OpenMP/depobj_messages.cpp --- a/clang/test/OpenMP/depobj_messages.cpp +++ b/clang/test/OpenMP/depobj_messages.cpp @@ -158,7 +158,7 @@ #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' requested here}} diff --git a/clang/test/OpenMP/parallel_reduction_messages.c b/clang/test/OpenMP/parallel_reduction_messages.c --- a/clang/test/OpenMP/parallel_reduction_messages.c +++ b/clang/test/OpenMP/parallel_reduction_messages.c @@ -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 @@ ; #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}} ; } diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -99,7 +99,7 @@ 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::TS > 0) priority(argc) foo(); @@ -116,7 +116,7 @@ // 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::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -130,7 +130,7 @@ // 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::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -144,7 +144,7 @@ // 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::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -164,14 +164,14 @@ #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) diff --git a/clang/test/OpenMP/task_depend_messages.cpp b/clang/test/OpenMP/task_depend_messages.cpp --- a/clang/test/OpenMP/task_depend_messages.cpp +++ b/clang/test/OpenMP/task_depend_messages.cpp @@ -35,14 +35,14 @@ #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 @@ #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 ''}} #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; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5183,6 +5183,8 @@ 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: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -423,6 +423,10 @@ K = CXCursor_OMPArraySectionExpr; break; + case Stmt::OMPArrayShapingExprClass: + K = CXCursor_OMPArrayShapingExpr; + break; + case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break;