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_ArraySectionExpr = 147, + + CXCursor_LastExpr = CXCursor_ArraySectionExpr, /* Statements */ CXCursor_FirstStmt = 200, Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2203,6 +2203,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(ArraySectionExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -2143,6 +2143,110 @@ } }; +/// \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 ArraySectionExpr : public Expr { + enum { BASE, LOWER_BOUND, LENGTH, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + SourceLocation ColonLoc; + SourceLocation RBracketLoc; + +public: + ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type, + ExprValueKind VK, ExprObjectKind OK, SourceLocation ColonLoc, + SourceLocation RBracketLoc) + : Expr( + ArraySectionExprClass, Type, VK, OK, + Base->isTypeDependent() || + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent()), + Base->isValueDependent() || + (LowerBound && LowerBound->isValueDependent()) || + (Length && Length->isValueDependent()), + Base->isInstantiationDependent() || + (LowerBound && LowerBound->isInstantiationDependent()) || + (Length && Length->isInstantiationDependent()), + Base->containsUnexpandedParameterPack() || + (LowerBound && LowerBound->containsUnexpandedParameterPack()) || + (Length && Length->containsUnexpandedParameterPack())), + ColonLoc(ColonLoc), RBracketLoc(RBracketLoc) { + SubExprs[BASE] = Base; + SubExprs[LOWER_BOUND] = LowerBound; + SubExprs[LENGTH] = Length; + } + + /// \brief Create an empty array section expression. + explicit ArraySectionExpr(EmptyShell Shell) + : Expr(ArraySectionExprClass, 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; } + + 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() == ArraySectionExprClass; + } + + child_range children() { + return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); + } +}; /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). /// CallExpr itself represents a normal function call, e.g., "f(x, 2)", Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2235,6 +2235,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(ArraySectionExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -2398,7 +2398,7 @@ /// with a star size (e.g. int X[*]). /// 'static' is only allowed on function parameters. enum ArraySizeModifier { - Normal, Static, Star + Normal, Static, Star, ArraySection }; private: /// The element type of the array. Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4902,6 +4902,21 @@ def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, InGroup, DefaultIgnore; +def err_typecheck_section_value : Error< + "subscripted value is not an array or pointer">; +def err_typecheck_section_not_integer : Error< + "array section %select{lower bound|length}0 is not an integer">; +def err_section_function_type : Error< + "section of pointer to function type %0">; +def warn_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">, + InGroup, DefaultIgnore; +def err_section_incomplete_type : Error< + "section of pointer to incomplete type %0">; +def err_section_negative : Error< + "section %select{lower bound|length}0 is evaluated to a negative value">; +def err_section_length_undefined : Error< + "section length is undefined, but subscripted value is not a sized array">; + def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_no_member_overloaded_arrow : Error< 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 ArraySectionExpr : DStmt; def CallExpr : DStmt; def MemberExpr : DStmt; def CastExpr : DStmt; Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -57,6 +57,7 @@ friend class ColonProtectionRAIIObject; friend class InMessageExpressionRAIIObject; friend class PoisonSEHIdentifiersRAIIObject; + friend class ArraySectionExpressionRAIIObject; friend class ObjCDeclContextSwitch; friend class ParenBraceBracketBalancer; friend class BalancedDelimiterTracker; @@ -181,6 +182,11 @@ /// ColonProtectionRAIIObject RAII object. bool ColonIsSacred; + /// \brief If true, parsing of array sections is supported. Otherwise, only + /// array subscripts are allowed. This is managed by the + /// ArraySectionExpressionRAIIObject RAII object. + bool ArraySectionAllowed; + /// \brief When true, we are directly inside an Objective-C message /// send expression. /// Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3788,6 +3788,9 @@ Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); + ExprResult ActOnArraySectionExpr(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 @@ -1401,6 +1401,7 @@ STMT_OMP_TASKGROUP_DIRECTIVE, STMT_OMP_CANCELLATION_POINT_DIRECTIVE, STMT_OMP_CANCEL_DIRECTIVE, + EXPR_ARRAY_SECTION, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -270,6 +270,7 @@ case ArrayType::Normal: break; case ArrayType::Static: OS << " static"; break; case ArrayType::Star: OS << " *"; break; + case ArrayType::ArraySection: OS << " array section"; break; } OS << " " << T->getIndexTypeQualifiers().getAsString(); dumpTypeAsChild(T->getElementType()); Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3012,6 +3012,7 @@ case ParenExprClass: case ArraySubscriptExprClass: + case ArraySectionExprClass: 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::ArraySectionExprClass: 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::ArraySectionExprClass: 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::ArraySectionExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1266,6 +1266,17 @@ OS << "]"; } +void StmtPrinter::VisitArraySectionExpr(ArraySectionExpr *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 @@ -646,6 +646,10 @@ VisitExpr(S); } +void StmtProfiler::VisitArraySectionExpr(const ArraySectionExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1396,21 +1396,46 @@ BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Loc = T.getOpenLocation(); - ExprResult Idx; + ExprResult Idx, Length; + bool ArraySectionIsFound = 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 { + bool MayArraySection = ArraySectionAllowed; + ArraySectionExpressionRAIIObject RAII(*this, /*Value=*/false); + // Parse [: or [ expr or [ expr : + if (!MayArraySection || !Tok.is(tok::colon)) { + // [ expr + Idx = ParseExpression(); + } + if (MayArraySection && Tok.is(tok::colon)) { + // Consume ':' + ArraySectionIsFound = 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 (ArraySectionIsFound) { + LHS = Actions.ActOnArraySectionExpr(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/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -764,7 +764,9 @@ const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { - ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); + ArraySectionExpressionRAIIObject RAII(*this, Kind == OMPC_depend); + ColonProtectionRAIIObject ColonRAII(*this, + Kind == OMPC_depend || MayHaveTail); // Parse variable ExprResult VarExpr = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -69,10 +69,10 @@ } Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) - : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), ColonIsSacred(false), - InMessageExpression(false), TemplateParameterDepth(0), - ParsingInObjCContainer(false) { + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true), ColonIsSacred(false), + ArraySectionAllowed(false), InMessageExpression(false), + TemplateParameterDepth(0), ParsingInObjCContainer(false) { SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; Tok.startToken(); Tok.setKind(tok::eof); Index: lib/Parse/RAIIObjectsForParser.h =================================================================== --- lib/Parse/RAIIObjectsForParser.h +++ lib/Parse/RAIIObjectsForParser.h @@ -286,7 +286,27 @@ restore(); } }; - + + /// \brief This sets the Parser::ArraySectionAllowed bool and + /// restores it when destroyed. It it also manages Parser::ColonIsSacred for + /// correct parsing of array sections. + class ArraySectionExpressionRAIIObject { + Parser &P; + bool OldVal; + + public: + ArraySectionExpressionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ArraySectionAllowed) { + P.ArraySectionAllowed = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { P.ArraySectionAllowed = OldVal; } + + ~ArraySectionExpressionRAIIObject() { restore(); } + }; + /// \brief RAII object that makes '>' behave either as an operator /// or as the closing angle bracket for a template argument list. class GreaterThanIsOperatorScope { Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -5750,6 +5750,10 @@ return EvalAddr(cast(E)->getBase(), refVars,ParentDecl); } + case Stmt::ArraySectionExprClass: { + 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 +8466,13 @@ AllowOnePastEnd > 0); return; } + case Stmt::ArraySectionExprClass: { + const ArraySectionExpr *ASE = cast(expr); + if (ASE->getLowerBound()) + CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), + /**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 @@ -1059,6 +1059,7 @@ // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: + case Expr::ArraySectionExprClass: case Expr::BinaryOperatorClass: case Expr::CompoundAssignOperatorClass: case Expr::CStyleCastExprClass: Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -492,6 +492,33 @@ // Standard Promotions and Conversions //===----------------------------------------------------------------------===// +static bool isArraySectionType(QualType Ty) { + return !Ty.isNull() && Ty->isArrayType() && + Ty->getAsArrayTypeUnsafe()->getSizeModifier() == + ArrayType::ArraySection; +} + +static QualType getNonArraySectionType(QualType Ty) { + while (isArraySectionType(Ty)) + Ty = Ty->getAsArrayTypeUnsafe()->getElementType(); + return Ty; +} + +static QualType createArraySectionType(ASTContext &C, QualType OriginalTy, + QualType ResultTy, Expr *Size, + SourceRange Brackets) { + if (isArraySectionType(OriginalTy)) { + auto *VAT = C.getAsVariableArrayType(OriginalTy); + return C.getVariableArrayType( + createArraySectionType(C, VAT->getElementType(), ResultTy, Size, + Brackets), + VAT->getSizeExpr(), VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange()); + } + return C.getVariableArrayType(ResultTy, Size, ArrayType::ArraySection, + /*IndexTypeQuals=*/0, Brackets); +} + /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { // Handle any placeholder expressions which made it here. @@ -513,7 +540,7 @@ } E = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).get(); - } else if (Ty->isArrayType()) { + } else if (Ty->isArrayType() && !isArraySectionType(Ty)) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has // type 'array of type' is converted to an expression that has type 'pointer @@ -3943,6 +3970,13 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, Expr *idx, SourceLocation rbLoc) { + if (isArraySectionType(base->IgnoreImpCasts()->getType())) + return ActOnArraySectionExpr(S, base, lbLoc, idx, SourceLocation(), + /*Length=*/nullptr, rbLoc); + else if (isArraySectionType(idx->IgnoreImpCasts()->getType())) + return ActOnArraySectionExpr(S, idx, lbLoc, base, 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 +4025,156 @@ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc); } +ExprResult Sema::ActOnArraySectionExpr(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()) { + 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() || + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent())) { + return new (Context) + ArraySectionExpr(Base, LowerBound, Length, Context.DependentTy, + VK_LValue, OK_Ordinary, ColonLoc, RBLoc); + } + + // Perform default conversions. + QualType OriginalTy = getNonArraySectionType(Base->getType()); + QualType ResultTy; + if (OriginalTy->isAnyPointerType()) { + ResultTy = OriginalTy->getPointeeType(); + } else if (OriginalTy->isArrayType()) { + ResultTy = OriginalTy->getAsArrayTypeUnsafe()->getElementType(); + } else { + return ExprError(Diag(Base->getExprLoc(), diag::err_typecheck_section_value) + << Base->getSourceRange()); + } + // C99 6.5.2.1p1 + if (LowerBound) { + if (!LowerBound->getType()->isIntegerType()) + return ExprError(Diag(LowerBound->getExprLoc(), + diag::err_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_section_is_char) + << 0 << LowerBound->getSourceRange(); + } + if (Length) { + if (!Length->getType()->isIntegerType()) + return ExprError( + Diag(Length->getExprLoc(), diag::err_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_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_section_function_type) + << ResultTy << Base->getSourceRange(); + return ExprError(); + } + + if (RequireCompleteType(Base->getExprLoc(), ResultTy, + diag::err_section_incomplete_type, Base)) + return ExprError(); + + if (LowerBound) { + llvm::APSInt LowerBoundValue; + if (LowerBound->EvaluateAsInt(LowerBoundValue, Context, + Expr::SE_AllowSideEffects)) { + // 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_section_negative) + << 0 << LowerBound->getSourceRange(); + return ExprError(); + } + } + } + + if (Length) { + llvm::APSInt LengthValue; + if (Length->EvaluateAsInt(LengthValue, Context, + Expr::SE_AllowSideEffects)) { + // 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_section_negative) + << 1 << 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_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(); + } + } + } + ResultTy = createArraySectionType(Context, Base->getType(), ResultTy, + LengthExpr, SourceRange(LBLoc, RBLoc)); + return new (Context) + ArraySectionExpr(Base, LowerBound, Length, ResultTy, VK_LValue, + OK_Ordinary, ColonLoc, RBLoc); +} + ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -6573,10 +6573,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 *ASecE = dyn_cast(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (!ASE && !DE && !ASecE) || (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/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -1388,6 +1388,17 @@ StandardConversionSequence &SCS, bool CStyle); +static QualType getNonArraySectionType(QualType Ty) { + if (!Ty.isNull() && Ty->isArrayType()) { + while (!Ty.isNull() && Ty->isArrayType() && + Ty->getAsArrayTypeUnsafe()->getSizeModifier() == + ArrayType::ArraySection) { + Ty = Ty->getAsArrayTypeUnsafe()->getElementType(); + } + } + return Ty; +} + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -1478,6 +1489,7 @@ // A glvalue (3.10) of a non-function, non-array type T can // be converted to a prvalue. bool argIsLValue = From->isGLValue(); + FromType = getNonArraySectionType(FromType); if (argIsLValue && !FromType->isFunctionType() && !FromType->isArrayType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1857,6 +1857,18 @@ 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 RebuildArraySectionExpr(Expr *Base, SourceLocation LBracketLoc, + Expr *LowerBound, SourceLocation ColonLoc, + Expr *Length, SourceLocation RBracketLoc) { + return getSema().ActOnArraySectionExpr(/*Scope=*/nullptr, Base, LBracketLoc, + LowerBound, ColonLoc, Length, + RBracketLoc); + } + /// \brief Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -7829,6 +7841,36 @@ E->getRBracketLoc()); } +template +ExprResult +TreeTransform::TransformArraySectionExpr(ArraySectionExpr *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().RebuildArraySectionExpr( + Base.get(), E->getBase()->getLocEnd(), LowerBound.get(), E->getColonLoc(), + Length.get(), E->getRBracketLoc()); +} + template ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -589,6 +589,15 @@ E->setRBracketLoc(ReadSourceLocation(Record, Idx)); } +void ASTStmtReader::VisitArraySectionExpr(ArraySectionExpr *E) { + VisitExpr(E); + E->setBase(Reader.ReadSubExpr()); + E->setLowerBound(Reader.ReadSubExpr()); + E->setLength(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++]); @@ -2493,6 +2502,10 @@ S = new (Context) ArraySubscriptExpr(Empty); break; + case EXPR_ARRAY_SECTION: + S = new (Context) ArraySectionExpr(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,16 @@ Code = serialization::EXPR_ARRAY_SUBSCRIPT; } +void ASTStmtWriter::VisitArraySectionExpr(ArraySectionExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getBase()); + Writer.AddStmt(E->getLowerBound()); + Writer.AddStmt(E->getLength()); + Writer.AddSourceLocation(E->getColonLoc(), Record); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = serialization::EXPR_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 @@ -130,6 +130,14 @@ os << " results in a null pointer dereference"; break; } + case Stmt::ArraySectionExprClass: { + os << "Array access"; + const ArraySectionExpr *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::ArraySectionExprClass: 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 @@ -901,7 +901,8 @@ case Stmt::ObjCStringLiteralClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: - case Stmt::CXXNullPtrLiteralExprClass: { + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::ArraySectionExprClass: { 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 undefined, but subscripted value is not a sized 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}} + #pragma omp task depend (in : argv[-1:0]) // expected-error {{section lower bound is evaluated to a negative value}} + #pragma omp task depend (in : argv[:]) // expected-error {{section length is undefined, but subscripted value is not a sized 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[:]:1]) // expected-error {{expected expression}} expected-error {{expected ']'}} expected-note {{to match this '['}} + #pragma omp task depend(in:argv[0:][:]) // expected-error {{section length is undefined, but subscripted value is not a sized 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 @@ -4071,6 +4071,8 @@ return cxstring::createRef("UnaryOperator"); case CXCursor_ArraySubscriptExpr: return cxstring::createRef("ArraySubscriptExpr"); + case CXCursor_ArraySectionExpr: + return cxstring::createRef("ArraySectionExpr"); 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::ArraySectionExprClass: + K = CXCursor_ArraySectionExpr; + break; + case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break;