ABataev retitled this revision from "[OPENMP] Initial support for array sections (OpenMP 4.0)." to "[OPENMP 4.0] Initial support for array sections.".
Added array type for ArraySectionExpr and new array size modifier - ArraySection http://reviews.llvm.org/D10732 Files: include/clang-c/Index.h include/clang/AST/DataRecursiveASTVisitor.h include/clang/AST/Expr.h include/clang/AST/RecursiveASTVisitor.h include/clang/AST/Type.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/StmtNodes.td include/clang/Parse/Parser.h include/clang/Sema/Sema.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTDumper.cpp lib/AST/Expr.cpp lib/AST/ExprClassification.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseOpenMP.cpp lib/Parse/Parser.cpp lib/Parse/RAIIObjectsForParser.h lib/Sema/SemaChecking.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOpenMP.cpp lib/Sema/SemaOverload.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/OpenMP/task_ast_print.cpp test/OpenMP/task_depend_messages.cpp tools/libclang/CIndex.cpp tools/libclang/CXCursor.cpp
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/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/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/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/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/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/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: 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/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<ArraySectionExpr>(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<UnaryOperator>(S); 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/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/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/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/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<CXXDefaultArgExpr>(Call->getArg(i))) { 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/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/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -492,6 +492,17 @@ // Standard Promotions and Conversions //===----------------------------------------------------------------------===// +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; +} + /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { // Handle any placeholder expressions which made it here. @@ -504,6 +515,7 @@ QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); + Ty = getNonArraySectionType(Ty); if (Ty->isFunctionType()) { // If we are here, we are not calling a function but taking // its address (which is not allowed in OpenCL v1.0 s6.8.a.3). @@ -3991,6 +4003,176 @@ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc); } +ExprResult Sema::ActOnArraySectionExpr(Scope *S, Expr *Base, + SourceLocation LBLoc, Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length, + SourceLocation RBLoc) { + // Since this might be a postfix expression, get rid of ParenListExprs. + if (isa<ParenListExpr>(Base)) { + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + } + + // 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. + ExprResult Result = DefaultFunctionArrayLvalueConversion(Base); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + + QualType ResultType; + QualType BaseTy = getNonArraySectionType(Base->getType()); + if (const PointerType *PTy = BaseTy->getAs<PointerType>()) { + ResultType = PTy->getPointeeType(); + } else if (BaseTy->isArrayType()) { + // If we see an array that wasn't promoted by + // DefaultFunctionArrayLvalueConversion, it must be an array that wasn't + // promoted because of the C90 rule that doesn't allow promoting non-lvalue + // arrays. Warn, then force the promotion here. + Diag(Base->getLocStart(), diag::ext_subscript_non_lvalue) + << Base->getSourceRange(); + Base = ImpCastExprToType(Base, Context.getArrayDecayedType(BaseTy), + CK_ArrayToPointerDecay) + .get(); + ResultType = BaseTy->getAs<PointerType>()->getPointeeType(); + } 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 (ResultType->isFunctionType()) { + Diag(Base->getExprLoc(), diag::err_section_function_type) + << ResultType << Base->getSourceRange(); + return ExprError(); + } + + if (RequireCompleteType(Base->getExprLoc(), ResultType, + 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 { + // OpenMP 4.0, [2.4 Array Sections] + // When the size of the array dimension is not known, the length must be + // specified explicitly. + if (BaseTy.isNull() || + (!BaseTy->isConstantArrayType() && !BaseTy->isVariableArrayType())) { + Diag(ColonLoc, diag::err_section_length_undefined); + return ExprError(); + } + } + + Expr *LengthExpr = Length; + if (!LengthExpr) { + if (auto *CAT = + dyn_cast<ConstantArrayType>(BaseTy->getAsArrayTypeUnsafe())) { + llvm::APInt SizeVal = CAT->getSize(); + LengthExpr = IntegerLiteral::Create(Context, SizeVal, + Context.getIntPtrType(), RBLoc); + } else { + auto *VAT = cast<VariableArrayType>(BaseTy->getAsArrayTypeUnsafe()); + LengthExpr = VAT->getSizeExpr(); + } + if (LowerBound) { + LengthExpr = BuildBinOp(S, RBLoc, BO_Sub, LengthExpr, LowerBound).get(); + if (!LengthExpr) + return ExprError(); + } + } + ResultType = Context.getVariableArrayType( + ResultType, LengthExpr, ArrayType::ArraySection, /*IndexTypeQuals=*/0, + SourceRange(LBLoc, RBLoc)); + return new (Context) + ArraySectionExpr(Base, LowerBound, Length, ResultType, VK_LValue, + OK_Ordinary, ColonLoc, RBLoc); +} + ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -4019,6 +4201,8 @@ // and index from the expression types. Expr *BaseExpr, *IndexExpr; QualType ResultType; + LHSTy = getNonArraySectionType(LHSTy); + RHSTy = getNonArraySectionType(RHSTy); if (LHSTy->isDependentType() || RHSTy->isDependentType()) { BaseExpr = LHSExp; IndexExpr = RHSExp; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -5750,6 +5750,10 @@ return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl); } + case Stmt::ArraySectionExprClass: { + return EvalAddr(cast<ArraySectionExpr>(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<ArraySectionExpr>(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<UnaryOperator>(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/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/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -6536,10 +6536,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<DeclRefExpr>(SimpleExpr); - ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE) || - (DE && !isa<VarDecl>(DE->getDecl())) || + auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + auto *ASecE = dyn_cast<ArraySectionExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (!ASE && !DE && !ASecE) || (DE && !isa<VarDecl>(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 @@ -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 <typename Derived> +ExprResult +TreeTransform<Derived>::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<typename Derived> ExprResult TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -4056,6 +4056,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; 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/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: 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/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2232,6 +2232,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/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2200,6 +2200,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 @@ -2400,7 +2400,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: /// ElementType - The element type of the array. Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -2142,6 +2142,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<Expr>(SubExprs[BASE]); } + const Expr *getBase() const { return cast<Expr>(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<Expr>(SubExprs[LOWER_BOUND]); } + const Expr *getLowerBound() const { + return cast_or_null<Expr>(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<Expr>(SubExprs[LENGTH]); } + const Expr *getLength() const { return cast_or_null<Expr>(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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3787,6 +3787,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/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4892,6 +4892,21 @@ def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, InGroup<CharSubscript>, 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<CharSubscript>, 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<Expr>; def UnaryExprOrTypeTraitExpr : DStmt<Expr>; def ArraySubscriptExpr : DStmt<Expr>; +def ArraySectionExpr : DStmt<Expr>; def CallExpr : DStmt<Expr>; def MemberExpr : DStmt<Expr>; def CastExpr : DStmt<Expr, 1>; Index: test/OpenMP/task_ast_print.cpp =================================================================== --- test/OpenMP/task_ast_print.cpp +++ test/OpenMP/task_ast_print.cpp @@ -33,7 +33,7 @@ T b = argc, c, d, e, f, g; static T a; S<T> s; -#pragma omp task untied depend(in : argc) +#pragma omp task untied depend(in : argc, argv[b:argc]) a = 2; #pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) foo(); @@ -46,7 +46,7 @@ // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; // CHECK-NEXT: S<int> s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc]) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) // CHECK-NEXT: foo() @@ -56,7 +56,7 @@ // CHECK-NEXT: long b = argc, c, d, e, f, g; // CHECK-NEXT: static long a; // CHECK-NEXT: S<long> s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc]) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) // CHECK-NEXT: foo() @@ -66,7 +66,7 @@ // CHECK-NEXT: T b = argc, c, d, e, f, g; // CHECK-NEXT: static T a; // CHECK-NEXT: S<T> s; -// CHECK-NEXT: #pragma omp task untied depend(in : argc) +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc]) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) // CHECK-NEXT: foo() @@ -86,8 +86,8 @@ // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[1]) 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]) + // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc]) foo(); // CHECK-NEXT: foo(); return tmain<int, 5>(b, &b) + tmain<long, 1>(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;
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits