Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -1982,7 +1982,11 @@ */ CXCursor_ObjCSelfExpr = 146, - CXCursor_LastExpr = CXCursor_ObjCSelfExpr, + /** \brief OpenMP 4.0 [2.4, Array Section]. + */ + CXCursor_OMPArraySectionExpr = 147, + + CXCursor_LastExpr = CXCursor_OMPArraySectionExpr, /* Statements */ CXCursor_FirstStmt = 200, Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -838,6 +838,7 @@ CanQualType OCLImage2dTy, OCLImage2dArrayTy; CanQualType OCLImage3dTy; CanQualType OCLSamplerTy, OCLEventTy; + CanQualType OMPArraySectionTy; // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. mutable QualType AutoDeductTy; // Deduction against 'auto'. Index: include/clang/AST/BuiltinTypes.def =================================================================== --- include/clang/AST/BuiltinTypes.def +++ include/clang/AST/BuiltinTypes.def @@ -227,8 +227,11 @@ // context. PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) +// A placeholder type for OpenMP array sections. +PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) + #ifdef LAST_BUILTIN_TYPE -LAST_BUILTIN_TYPE(ARCUnbridgedCast) +LAST_BUILTIN_TYPE(OMPArraySection) #undef LAST_BUILTIN_TYPE #endif Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -24,6 +24,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" @@ -2203,6 +2204,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. Index: include/clang/AST/ExprOpenMP.h =================================================================== --- include/clang/AST/ExprOpenMP.h +++ include/clang/AST/ExprOpenMP.h @@ -0,0 +1,140 @@ +//===--- ExprOpenMP.h - Classes for representing expressions ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Expr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPROPENMP_H +#define LLVM_CLANG_AST_EXPROPENMP_H + +#include "clang/AST/Expr.h" + +namespace clang { +/// \brief OpenMP 4.0 [2.4, Array Sections]. +/// To specify an array section in an OpenMP construct, array subscript +/// expressions are extended with the following syntax: +/// \code +/// [ lower-bound : length ] +/// [ lower-bound : ] +/// [ : length ] +/// [ : ] +/// \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 +/// they represent a set of integer values as follows: +/// \code +/// { lower-bound, lower-bound + 1, lower-bound + 2,... , lower-bound + length - +/// 1 } +/// \endcode +/// The lower-bound and length must evaluate to non-negative integers. +/// 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. +class OMPArraySectionExpr : public Expr { + enum { BASE, LOWER_BOUND, LENGTH, UPPER_BOUND, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + SourceLocation ColonLoc; + SourceLocation RBracketLoc; + +public: + OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, + Expr *UpperBound, QualType Type, ExprValueKind VK, + ExprObjectKind OK, SourceLocation ColonLoc, + SourceLocation RBracketLoc) + : Expr( + OMPArraySectionExprClass, Type, VK, OK, + Base->isTypeDependent() || + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent()) || + (UpperBound && UpperBound->isTypeDependent()), + Base->isValueDependent() || + (LowerBound && LowerBound->isValueDependent()) || + (Length && Length->isValueDependent()) || + (UpperBound && UpperBound->isValueDependent()), + Base->isInstantiationDependent() || + (LowerBound && LowerBound->isInstantiationDependent()) || + (Length && Length->isInstantiationDependent()) || + (UpperBound && UpperBound->isInstantiationDependent()), + Base->containsUnexpandedParameterPack() || + (LowerBound && LowerBound->containsUnexpandedParameterPack()) || + (Length && Length->containsUnexpandedParameterPack()) || + (UpperBound && UpperBound->containsUnexpandedParameterPack())), + ColonLoc(ColonLoc), RBracketLoc(RBracketLoc) { + SubExprs[BASE] = Base; + SubExprs[LOWER_BOUND] = LowerBound; + SubExprs[LENGTH] = Length; + SubExprs[UPPER_BOUND] = UpperBound; + } + + /// \brief Create an empty array section expression. + explicit OMPArraySectionExpr(EmptyShell Shell) + : Expr(OMPArraySectionExprClass, Shell) {} + + /// An array section can be written only as Base[LowerBound:Length]. + + /// \brief Get base of the array section. + Expr *getBase() { return cast(SubExprs[BASE]); } + const Expr *getBase() const { return cast(SubExprs[BASE]); } + /// \brief Set base of the array section. + void setBase(Expr *E) { SubExprs[BASE] = E; } + + /// \brief Get lower bound of array section. + Expr *getLowerBound() { return cast_or_null(SubExprs[LOWER_BOUND]); } + const Expr *getLowerBound() const { + return cast_or_null(SubExprs[LOWER_BOUND]); + } + /// \brief Set lower bound of the array section. + void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } + + /// \brief Get length of array section. + Expr *getLength() { return cast_or_null(SubExprs[LENGTH]); } + const Expr *getLength() const { return cast_or_null(SubExprs[LENGTH]); } + /// \brief Set length of the array section. + void setLength(Expr *E) { SubExprs[LENGTH] = E; } + + /// \brief Get calculated upper bound of array section. + Expr *getUpperBound() { return cast_or_null(SubExprs[UPPER_BOUND]); } + const Expr *getUpperBound() const { + return cast_or_null(SubExprs[UPPER_BOUND]); + } + /// \brief Set lower bound of the array section. + void setUpperBound(Expr *E) { SubExprs[UPPER_BOUND] = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPArraySectionExprClass; + } + + child_range children() { + return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); + } +}; +} // end namespace clang + +#endif Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -24,6 +24,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" @@ -2235,6 +2236,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. Index: include/clang/AST/StmtVisitor.h =================================================================== --- include/clang/AST/StmtVisitor.h +++ include/clang/AST/StmtVisitor.h @@ -16,6 +16,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7663,6 +7663,22 @@ "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be nowait">; def err_omp_parent_cancel_region_ordered : Error< "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be ordered">; +def err_omp_array_section_use : Error<"OpenMP array section 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_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'">, + InGroup, DefaultIgnore; +def err_omp_section_incomplete_type : Error< + "section of pointer to incomplete type %0">; +def err_omp_section_negative : Error< + "section %select{lower bound|length}0 is evaluated to a negative value %1">; +def err_omp_section_length_undefined : Error< + "section length is unspecified, but subscripted value is not an array">; + } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -62,6 +62,7 @@ def OffsetOfExpr : DStmt; def UnaryExprOrTypeTraitExpr : DStmt; def ArraySubscriptExpr : DStmt; +def OMPArraySectionExpr : DStmt; def CallExpr : DStmt; def MemberExpr : DStmt; def CastExpr : DStmt; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3788,6 +3788,10 @@ Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); + ExprResult ActOnOMPArraySectionExpr(Scope *S, Expr *Base, + SourceLocation LBLoc, Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length, + SourceLocation RBLoc); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -780,7 +780,9 @@ /// \brief OpenCL event type. PREDEF_TYPE_EVENT_ID = 44, /// \brief OpenCL sampler type. - PREDEF_TYPE_SAMPLER_ID = 45 + PREDEF_TYPE_SAMPLER_ID = 45, + /// \brief The placeholder type for OpenMP array section. + PREDEF_TYPE_OMP_ARRAY_SECTION = 46, }; /// \brief The number of predefined type IDs that are reserved for @@ -1405,6 +1407,7 @@ STMT_OMP_TASKGROUP_DIRECTIVE, STMT_OMP_CANCELLATION_POINT_DIRECTIVE, STMT_OMP_CANCEL_DIRECTIVE, + EXPR_OMP_ARRAY_SECTION, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1043,6 +1043,9 @@ // Placeholder type for builtin functions. InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn); + // Placeholder type for OMP array sections. + InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3020,6 +3020,7 @@ case ParenExprClass: case ArraySubscriptExprClass: + case OMPArraySectionExprClass: case MemberExprClass: case ConditionalOperatorClass: case BinaryConditionalOperatorClass: Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -136,6 +136,7 @@ case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: case Expr::MSPropertyRefExprClass: + case Expr::OMPArraySectionExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8677,6 +8677,7 @@ case Expr::ImaginaryLiteralClass: case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: + case Expr::OMPArraySectionExprClass: case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2700,6 +2700,7 @@ case Expr::LambdaExprClass: case Expr::MSPropertyRefExprClass: case Expr::TypoExprClass: // This should no longer exist in the AST by now. + case Expr::OMPArraySectionExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. Index: lib/AST/NSAPI.cpp =================================================================== --- lib/AST/NSAPI.cpp +++ lib/AST/NSAPI.cpp @@ -461,6 +461,7 @@ case BuiltinType::Half: case BuiltinType::PseudoObject: case BuiltinType::BuiltinFn: + case BuiltinType::OMPArraySection: break; } Index: lib/AST/Stmt.cpp =================================================================== --- lib/AST/Stmt.cpp +++ lib/AST/Stmt.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/CharInfo.h" @@ -1271,6 +1272,17 @@ OS << "]"; } +void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { + PrintExpr(Node->getBase()); + OS << "["; + if (Node->getLowerBound()) + PrintExpr(Node->getLowerBound()); + OS << ":"; + if (Node->getLength()) + PrintExpr(Node->getLength()); + OS << "]"; +} + void StmtPrinter::PrintCallArgs(CallExpr *Call) { for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { if (isa(Call->getArg(i))) { Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/FoldingSet.h" using namespace clang; @@ -650,6 +651,10 @@ VisitExpr(S); } +void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -2516,6 +2516,7 @@ case OCLImage3d: return "image3d_t"; case OCLSampler: return "sampler_t"; case OCLEvent: return "event_t"; + case OMPArraySection: return ""; } llvm_unreachable("Invalid builtin type."); @@ -3421,6 +3422,7 @@ case BuiltinType::OCLEvent: case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: + case BuiltinType::OMPArraySection: return false; } Index: lib/AST/TypeLoc.cpp =================================================================== --- lib/AST/TypeLoc.cpp +++ lib/AST/TypeLoc.cpp @@ -342,6 +342,7 @@ case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::BuiltinFn: + case BuiltinType::OMPArraySection: return TST_unspecified; } Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1396,21 +1396,44 @@ BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Loc = T.getOpenLocation(); - ExprResult Idx; + ExprResult Idx, Length; + bool OMPArraySectionIsFound = false; + SourceLocation ColonLoc; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); - } else - Idx = ParseExpression(); + } else { + ColonProtectionRAIIObject RAII(*this); + // Parse [: or [ expr or [ expr : + if (!Tok.is(tok::colon)) { + // [ expr + Idx = ParseExpression(); + } + if (Tok.is(tok::colon)) { + // Consume ':' + OMPArraySectionIsFound = true; + ColonLoc = ConsumeToken(); + if (Tok.isNot(tok::r_square)) + Length = ParseExpression(); + } + } SourceLocation RLoc = Tok.getLocation(); - if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) { - LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, - Idx.get(), RLoc); + if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && + Tok.is(tok::r_square)) { + if (OMPArraySectionIsFound) { + LHS = Actions.ActOnOMPArraySectionExpr(getCurScope(), LHS.get(), Loc, + Idx.get(), ColonLoc, + Length.get(), RLoc); + } else { + LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, + Idx.get(), RLoc); + } } else { (void)Actions.CorrectDelayedTyposInExpr(LHS); (void)Actions.CorrectDelayedTyposInExpr(Idx); + (void)Actions.CorrectDelayedTyposInExpr(Length); LHS = ExprError(); Idx = ExprError(); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/Analysis/Analyses/FormatString.h" @@ -5750,6 +5751,11 @@ return EvalAddr(cast(E)->getBase(), refVars,ParentDecl); } + case Stmt::OMPArraySectionExprClass: { + return EvalAddr(cast(E)->getBase(), refVars, + ParentDecl); + } + case Stmt::ConditionalOperatorClass: { // For conditional operators we need to see if either the LHS or RHS are // non-NULL Expr's. If one is non-NULL, we return it. @@ -8462,6 +8468,15 @@ AllowOnePastEnd > 0); return; } + case Stmt::OMPArraySectionExprClass: { + const OMPArraySectionExpr *ASE = cast(expr); + if (ASE->getLowerBound()) + CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), + /*ASE=*/nullptr, AllowOnePastEnd > 0); + CheckArrayAccess(ASE->getBase(), ASE->getUpperBound(), + /*ASE=*/nullptr, AllowOnePastEnd > 0); + return; + } case Stmt::UnaryOperatorClass: { // Only unwrap the * and & unary operators const UnaryOperator *UO = cast(expr); Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1060,6 +1060,7 @@ // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: + case Expr::OMPArraySectionExprClass: case Expr::BinaryOperatorClass: case Expr::CompoundAssignOperatorClass: case Expr::CStyleCastExprClass: Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" @@ -3943,6 +3944,10 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, Expr *idx, SourceLocation rbLoc) { + if (base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection)) + return ActOnOMPArraySectionExpr(S, base, lbLoc, idx, SourceLocation(), + /*Length=*/nullptr, rbLoc); + // Since this might be a postfix expression, get rid of ParenListExprs. if (isa(base)) { ExprResult result = MaybeConvertParenListExprToParenExpr(S, base); @@ -3991,6 +3996,192 @@ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc); } +static QualType getNonOMPArraySectionType(Expr *Base) { + unsigned ArraySectionCount = 0; + while (auto *OASE = dyn_cast(Base)) { + Base = OASE->getBase(); + ++ArraySectionCount; + } + auto OriginalTy = Base->getType(); + for (unsigned i = 0; i < ArraySectionCount; ++i) { + if (OriginalTy->isAnyPointerType()) + OriginalTy = OriginalTy->getPointeeType(); + else { + assert (OriginalTy->isArrayType()); + OriginalTy = OriginalTy->castAsArrayTypeUnsafe()->getElementType(); + } + } + return OriginalTy; +} + +ExprResult Sema::ActOnOMPArraySectionExpr(Scope *S, Expr *Base, + SourceLocation LBLoc, + Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length, + SourceLocation RBLoc) { + // Handle any non-overload placeholder types in the base and index + // expressions. We can't handle overloads here because the other + // operand might be an overloadable type, in which case the overload + // resolution for the operator overload should get the first crack + // at the overload. + if (Base->getType()->isNonOverloadPlaceholderType() && + !Base->getType()->isSpecificPlaceholderType( + BuiltinType::OMPArraySection)) { + ExprResult Result = CheckPlaceholderExpr(Base); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + } + if (LowerBound && LowerBound->getType()->isNonOverloadPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(LowerBound); + if (Result.isInvalid()) + return ExprError(); + LowerBound = Result.get(); + } + if (Length && Length->getType()->isNonOverloadPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Length); + if (Result.isInvalid()) + return ExprError(); + Length = Result.get(); + } + + // Build an unanalyzed expression if either operand is type-dependent. + if (Base->isTypeDependent() || Base->isValueDependent() || + (LowerBound && + (LowerBound->isTypeDependent() || LowerBound->isValueDependent())) || + (Length && (Length->isTypeDependent() || Length->isValueDependent()))) { + return new (Context) OMPArraySectionExpr( + Base, LowerBound, Length, /*UpperBound=*/nullptr, Context.DependentTy, + VK_LValue, OK_Ordinary, ColonLoc, RBLoc); + } + + // Perform default conversions. + QualType OriginalTy = getNonOMPArraySectionType(Base); + QualType ResultTy; + if (OriginalTy->isAnyPointerType()) { + ResultTy = OriginalTy->getPointeeType(); + } else if (OriginalTy->isArrayType()) { + ResultTy = OriginalTy->getAsArrayTypeUnsafe()->getElementType(); + } else { + return ExprError( + Diag(Base->getExprLoc(), diag::err_omp_typecheck_section_value) + << Base->getSourceRange()); + } + // C99 6.5.2.1p1 + if (LowerBound) { + if (!LowerBound->getType()->isIntegerType()) + return ExprError(Diag(LowerBound->getExprLoc(), + diag::err_omp_typecheck_section_not_integer) + << 0 << LowerBound->getSourceRange()); + + if (LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || + LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) + Diag(LowerBound->getExprLoc(), diag::warn_omp_section_is_char) + << 0 << LowerBound->getSourceRange(); + } + if (Length) { + if (!Length->getType()->isIntegerType()) + return ExprError( + Diag(Length->getExprLoc(), diag::err_omp_typecheck_section_not_integer) + << 1 << Length->getSourceRange()); + + if (Length->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || + Length->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) + Diag(Length->getExprLoc(), diag::warn_omp_section_is_char) + << 1 << Length->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 + // type. Note that Functions are not objects, and that (in C99 parlance) + // incomplete types are not object types. + if (ResultTy->isFunctionType()) { + Diag(Base->getExprLoc(), diag::err_omp_section_function_type) + << ResultTy << Base->getSourceRange(); + return ExprError(); + } + + if (RequireCompleteType(Base->getExprLoc(), ResultTy, + diag::err_omp_section_incomplete_type, Base)) + return ExprError(); + + if (LowerBound) { + llvm::APSInt LowerBoundValue; + if (LowerBound->EvaluateAsInt(LowerBoundValue, Context)) { + // OpenMP 4.0, [2.4 Array Sections] + // The lower-bound and length must evaluate to non-negative integers. + if (LowerBoundValue.isNegative()) { + Diag(LowerBound->getExprLoc(), diag::err_omp_section_negative) + << 0 << LowerBoundValue.toString(/*Radix=*/10, /*Signed=*/true) + << LowerBound->getSourceRange(); + return ExprError(); + } + } + } + + if (Length) { + llvm::APSInt LengthValue; + if (Length->EvaluateAsInt(LengthValue, Context)) { + // OpenMP 4.0, [2.4 Array Sections] + // The lower-bound and length must evaluate to non-negative integers. + if (LengthValue.isNegative()) { + Diag(Length->getExprLoc(), diag::err_omp_section_negative) + << 1 << LengthValue.toString(/*Radix=*/10, /*Signed=*/true) + << Length->getSourceRange(); + return ExprError(); + } + } + } else if (ColonLoc.isValid() && + (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && + !OriginalTy->isVariableArrayType()))) { + // OpenMP 4.0, [2.4 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); + return ExprError(); + } + + Expr *LengthExpr = Length; + if (!LengthExpr) { + if (ColonLoc.isInvalid()) { + LengthExpr = ActOnIntegerConstant(SourceLocation(), /*Val=*/1).get(); + } else { + if (auto *CAT = + dyn_cast(OriginalTy->getAsArrayTypeUnsafe())) { + llvm::APInt SizeVal = CAT->getSize(); + LengthExpr = IntegerLiteral::Create(Context, SizeVal, + Context.getIntPtrType(), RBLoc); + } else { + auto *VAT = cast(OriginalTy->getAsArrayTypeUnsafe()); + LengthExpr = VAT->getSizeExpr(); + } + if (LowerBound) { + LengthExpr = BuildBinOp(S, RBLoc, BO_Sub, LengthExpr, LowerBound).get(); + if (!LengthExpr) + return ExprError(); + } + } + } + // Build upper bound expression. + ExprResult UpperBound = LengthExpr; + if (LowerBound) + UpperBound = BuildBinOp(S, RBLoc, BO_Add, LengthExpr, LowerBound); + if (UpperBound.isInvalid()) + return ExprError(); + UpperBound = + BuildBinOp(S, RBLoc, BO_Sub, UpperBound.get(), + ActOnIntegerConstant(SourceLocation(), /*Val=*/1).get()); + if (UpperBound.isInvalid()) + return ExprError(); + UpperBound = ActOnFinishFullExpr(UpperBound.get()); + if (UpperBound.isInvalid()) + return ExprError(); + + return new (Context) OMPArraySectionExpr( + Base, LowerBound, Length, UpperBound.get(), Context.OMPArraySectionTy, + VK_LValue, OK_Ordinary, ColonLoc, RBLoc); +} + ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -4623,7 +4814,9 @@ // These are always invalid as call arguments and should be reported. case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: + case BuiltinType::OMPArraySection: return true; + } llvm_unreachable("bad builtin type kind"); } @@ -14235,6 +14428,11 @@ return ExprError(); } + // Expressions of unknown type. + case BuiltinType::OMPArraySection: + Diag(E->getLocStart(), diag::err_omp_array_section_use); + return ExprError(); + // Everything else should be impossible. #define BUILTIN_TYPE(Id, SingletonId) \ case BuiltinType::Id: Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -6588,10 +6588,11 @@ // structure) but is not an array element or an array section cannot appear // in a depend clause. auto *SimpleExpr = RefExpr->IgnoreParenCasts(); - DeclRefExpr *DE = dyn_cast(SimpleExpr); - ArraySubscriptExpr *ASE = dyn_cast(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE) || - (DE && !isa(DE->getDecl())) || + auto *DE = dyn_cast(SimpleExpr); + auto *ASE = dyn_cast(SimpleExpr); + auto *OASE = dyn_cast(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (!ASE && !DE && !OASE) || (DE && !isa(DE->getDecl())) || (ASE && !ASE->getBase()->getType()->isAnyPointerType() && !ASE->getBase()->getType()->isArrayType())) { Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -21,6 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -1857,6 +1858,19 @@ RBracketLoc); } + /// \brief Build a new array section expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc, + Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length, + SourceLocation RBracketLoc) { + return getSema().ActOnOMPArraySectionExpr(/*Scope=*/nullptr, Base, + LBracketLoc, LowerBound, ColonLoc, + Length, RBracketLoc); + } + /// \brief Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -7840,6 +7854,36 @@ E->getRBracketLoc()); } +template +ExprResult +TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + ExprResult LowerBound; + if (E->getLowerBound()) { + LowerBound = getDerived().TransformExpr(E->getLowerBound()); + if (LowerBound.isInvalid()) + return ExprError(); + } + + ExprResult Length; + if (E->getLength()) { + Length = getDerived().TransformExpr(E->getLength()); + if (Length.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()->getLocEnd(), LowerBound.get(), E->getColonLoc(), + Length.get(), E->getRBracketLoc()); +} + template ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { Index: lib/Serialization/ASTCommon.cpp =================================================================== --- lib/Serialization/ASTCommon.cpp +++ lib/Serialization/ASTCommon.cpp @@ -72,6 +72,7 @@ case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break; case BuiltinType::BuiltinFn: ID = PREDEF_TYPE_BUILTIN_FN; break; + case BuiltinType::OMPArraySection: ID = PREDEF_TYPE_OMP_ARRAY_SECTION; break; } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5775,6 +5775,10 @@ case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; + + case PREDEF_TYPE_OMP_ARRAY_SECTION: + T = Context.OMPArraySectionTy; + break; } assert(!T.isNull() && "Unknown predefined type"); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -589,6 +589,16 @@ E->setRBracketLoc(ReadSourceLocation(Record, Idx)); } +void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + E->setBase(Reader.ReadSubExpr()); + E->setLowerBound(Reader.ReadSubExpr()); + E->setLength(Reader.ReadSubExpr()); + E->setUpperBound(Reader.ReadSubExpr()); + E->setColonLoc(ReadSourceLocation(Record, Idx)); + E->setRBracketLoc(ReadSourceLocation(Record, Idx)); +} + void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); E->setNumArgs(Reader.getContext(), Record[Idx++]); @@ -2499,6 +2509,10 @@ S = new (Context) ArraySubscriptExpr(Empty); break; + case EXPR_OMP_ARRAY_SECTION: + S = new (Context) OMPArraySectionExpr(Empty); + break; + case EXPR_CALL: S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty); break; Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -511,6 +511,17 @@ Code = serialization::EXPR_ARRAY_SUBSCRIPT; } +void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getBase()); + Writer.AddStmt(E->getLowerBound()); + Writer.AddStmt(E->getLength()); + Writer.AddStmt(E->getUpperBound()); + Writer.AddSourceLocation(E->getColonLoc(), Record); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = serialization::EXPR_OMP_ARRAY_SECTION; +} + void ASTStmtWriter::VisitCallExpr(CallExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); Index: lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -14,6 +14,7 @@ #include "ClangSACheckers.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -130,6 +131,14 @@ os << " results in a null pointer dereference"; break; } + case Stmt::OMPArraySectionExprClass: { + os << "Array access"; + const OMPArraySectionExpr *AE = cast(S); + AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), + State.get(), N->getLocationContext()); + os << " results in a null pointer dereference"; + break; + } case Stmt::UnaryOperatorClass: { os << "Dereference of null pointer"; const UnaryOperator *U = cast(S); Index: lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -332,6 +332,7 @@ return false; case Stmt::CallExprClass: case Stmt::ArraySubscriptExprClass: + case Stmt::OMPArraySectionExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ParenExprClass: case Stmt::BreakStmtClass: Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -902,7 +902,8 @@ case Stmt::ObjCStringLiteralClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: - case Stmt::CXXNullPtrLiteralExprClass: { + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::OMPArraySectionExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); Index: test/OpenMP/task_ast_print.cpp =================================================================== --- test/OpenMP/task_ast_print.cpp +++ test/OpenMP/task_ast_print.cpp @@ -33,7 +33,8 @@ T b = argc, c, d, e, f, g; static T a; S s; -#pragma omp task untied depend(in : argc) + T arr[argc]; +#pragma omp task untied depend(in : argc, argv[b:argc], arr[:]) a = 2; #pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S::TS > 0) foo(); @@ -46,7 +47,8 @@ // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; // CHECK-NEXT: S s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: int arr[argc]; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) // 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) // CHECK-NEXT: foo() @@ -56,7 +58,8 @@ // CHECK-NEXT: long b = argc, c, d, e, f, g; // CHECK-NEXT: static long a; // CHECK-NEXT: S s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: long arr[argc]; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) // 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) // CHECK-NEXT: foo() @@ -66,7 +69,8 @@ // CHECK-NEXT: T b = argc, c, d, e, f, g; // CHECK-NEXT: static T a; // CHECK-NEXT: S s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: T arr[argc]; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) // 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) // CHECK-NEXT: foo() @@ -79,15 +83,16 @@ long x; int b = argc, c, d, e, f, g; static int a; + int arr[10]; #pragma omp threadprivate(a) Enum ee; // CHECK: Enum ee; -#pragma omp task untied mergeable depend(out:argv[1]) - // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[1]) +#pragma omp task untied mergeable depend(out:argv[1], arr[0:]) + // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[1],arr[0:]) a = 2; // CHECK-NEXT: a = 2; -#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a) - // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a) +#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) + // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) foo(); // CHECK-NEXT: foo(); return tmain(b, &b) + tmain(x, &x); Index: test/OpenMP/task_depend_messages.cpp =================================================================== --- test/OpenMP/task_depend_messages.cpp +++ test/OpenMP/task_depend_messages.cpp @@ -33,6 +33,20 @@ #pragma omp task depend (in : ) // expected-error {{expected expression}} #pragma omp task depend (in : main) // expected-error {{expected variable name, array element or array section}} #pragma omp task depend(in : a[0]) // expected-error{{expected variable name, 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 '('}} + #pragma omp task depend (in : argv[:] // expected-error {{section length is unspecified, but subscripted value is not an array}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task depend (in : argv[argc: // 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[argc:argc] // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task depend (in : argv[0:-1]) // expected-error {{section length is evaluated to a negative value -1}} + #pragma omp task depend (in : argv[-1:0]) // expected-error {{section lower bound is evaluated to a negative value -1}} + #pragma omp task depend (in : argv[:]) // expected-error {{section length is unspecified, but subscripted value is not an array}} + #pragma omp task depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}} + #pragma omp task depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}} + #pragma omp task depend(in:argv[argv[:2]:1]) // expected-error {{OpenMP array section is not allowed here}} + #pragma omp task depend(in:argv[0:][:]) // expected-error {{section length is unspecified, but subscripted value is not an array}} + #pragma omp task depend(in : argv[ : argc][1 : argc - 1]) foo(); return 0; Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -4077,6 +4077,8 @@ return cxstring::createRef("UnaryOperator"); case CXCursor_ArraySubscriptExpr: return cxstring::createRef("ArraySubscriptExpr"); + case CXCursor_OMPArraySectionExpr: + return cxstring::createRef("OMPArraySectionExpr"); case CXCursor_BinaryOperator: return cxstring::createRef("BinaryOperator"); case CXCursor_CompoundAssignOperator: Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -328,6 +328,10 @@ K = CXCursor_ArraySubscriptExpr; break; + case Stmt::OMPArraySectionExprClass: + K = CXCursor_OMPArraySectionExpr; + break; + case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break;