Author: Alexey Bataev Date: 2020-04-01T12:53:55-04:00 New Revision: f08df464ae89972a777c0a7e299a2c153a9829d8
URL: https://github.com/llvm/llvm-project/commit/f08df464ae89972a777c0a7e299a2c153a9829d8 DIFF: https://github.com/llvm/llvm-project/commit/f08df464ae89972a777c0a7e299a2c153a9829d8.diff LOG: [OPENMP50]Add initial support for OpenMP 5.0 iterator. Added basic parsing/semantic analysis/(de)serialization support for iterator expression introduced in OpenMP 5.0. Added: Modified: clang/include/clang-c/Index.h clang/include/clang/AST/ASTContext.h clang/include/clang/AST/BuiltinTypes.def clang/include/clang/AST/ComputeDependence.h clang/include/clang/AST/ExprOpenMP.h clang/include/clang/AST/OpenMPClause.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/StmtNodes.td clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ComputeDependence.cpp clang/lib/AST/Expr.cpp clang/lib/AST/ExprClassification.cpp clang/lib/AST/ExprConstant.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/NSAPI.cpp clang/lib/AST/OpenMPClause.cpp clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/AST/Type.cpp clang/lib/AST/TypeLoc.cpp clang/lib/Parse/ParseOpenMP.cpp clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/OpenMP/depobj_messages.cpp clang/test/OpenMP/task_ast_print.cpp clang/test/OpenMP/task_depend_messages.cpp clang/tools/libclang/CIndex.cpp clang/tools/libclang/CXCursor.cpp Removed: ################################################################################ diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 641f058dafaa..0acd50021ed8 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2180,7 +2180,12 @@ enum CXCursorKind { */ CXCursor_OMPArrayShapingExpr = 150, - CXCursor_LastExpr = CXCursor_OMPArrayShapingExpr, + /** + * OpenMP 5.0 [2.1.6 Iterators] + */ + CXCursor_OMPIteratorExpr = 151, + + CXCursor_LastExpr = CXCursor_OMPIteratorExpr, /* Statements */ CXCursor_FirstStmt = 200, diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index ebb5ca593843..6813ab58874e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -970,7 +970,7 @@ class ASTContext : public RefCountedBase<ASTContext> { #include "clang/Basic/OpenCLImageTypes.def" CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLReserveIDTy; - CanQualType OMPArraySectionTy, OMPArrayShapingTy; + CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ CanQualType Id##Ty; #include "clang/Basic/OpenCLExtensionTypes.def" diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index f42503773945..f8eb4ec19c8f 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -316,8 +316,11 @@ PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) // A placeholder type for OpenMP array shaping operation. PLACEHOLDER_TYPE(OMPArrayShaping, OMPArrayShapingTy) +// A placeholder type for OpenMP iterators. +PLACEHOLDER_TYPE(OMPIterator, OMPIteratorTy) + #ifdef LAST_BUILTIN_TYPE -LAST_BUILTIN_TYPE(OMPArrayShaping) +LAST_BUILTIN_TYPE(OMPIterator) #undef LAST_BUILTIN_TYPE #endif diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 63947eaff73b..ab742c9b70dd 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -88,6 +88,7 @@ class PseudoObjectExpr; class AtomicExpr; class OMPArraySectionExpr; class OMPArrayShapingExpr; +class OMPIteratorExpr; class ObjCArrayLiteral; class ObjCDictionaryLiteral; class ObjCBoxedExpr; @@ -174,6 +175,7 @@ ExprDependence computeDependence(AtomicExpr *E); ExprDependence computeDependence(OMPArraySectionExpr *E); ExprDependence computeDependence(OMPArrayShapingExpr *E); +ExprDependence computeDependence(OMPIteratorExpr *E); ExprDependence computeDependence(ObjCArrayLiteral *E); ExprDependence computeDependence(ObjCDictionaryLiteral *E); diff --git a/clang/include/clang/AST/ExprOpenMP.h b/clang/include/clang/AST/ExprOpenMP.h index 4a0cd07f1dab..6059df8b33e7 100644 --- a/clang/include/clang/AST/ExprOpenMP.h +++ b/clang/include/clang/AST/ExprOpenMP.h @@ -205,6 +205,173 @@ class OMPArrayShapingExpr final return const_child_range(Begin, Begin + NumDims + 1); } }; + +/// OpenMP 5.0 [2.1.6 Iterators] +/// Iterators are identifiers that expand to multiple values in the clause on +/// which they appear. +/// The syntax of the iterator modifier is as follows: +/// \code +/// iterator(iterators-definition) +/// \endcode +/// where iterators-definition is one of the following: +/// \code +/// iterator-specifier [, iterators-definition ] +/// \endcode +/// where iterator-specifier is one of the following: +/// \code +/// [ iterator-type ] identifier = range-specification +/// \endcode +/// where identifier is a base language identifier. +/// iterator-type is a type name. +/// range-specification is of the form begin:end[:step], where begin and end are +/// expressions for which their types can be converted to iterator-type and step +/// is an integral expression. +/// In an iterator-specifier, if the iterator-type is not specified then the +/// type of that iterator is of int type. +/// The iterator-type must be an integral or pointer type. +/// The iterator-type must not be const qualified. +class OMPIteratorExpr final + : public Expr, + private llvm::TrailingObjects<OMPIteratorExpr, Decl *, Expr *, + SourceLocation> { +public: + /// Iterator range representation begin:end[:step]. + struct IteratorRange { + Expr *Begin = nullptr; + Expr *End = nullptr; + Expr *Step = nullptr; + }; + /// Iterator definition representation. + struct IteratorDefinition { + Decl *IteratorDecl = nullptr; + IteratorRange Range; + SourceLocation AssignmentLoc; + SourceLocation ColonLoc, SecondColonLoc; + }; + +private: + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + /// Offset in the list of expressions for subelements of the ranges. + enum class RangeExprOffset { + Begin = 0, + End = 1, + Step = 2, + Total = 3, + }; + /// Offset in the list of locations for subelements of colon symbols + /// locations. + enum class RangeLocOffset { + AssignLoc = 0, + FirstColonLoc = 1, + SecondColonLoc = 2, + Total = 3, + }; + /// Location of 'iterator' keyword. + SourceLocation IteratorKwLoc; + /// Location of '('. + SourceLocation LPLoc; + /// Location of ')'. + SourceLocation RPLoc; + /// Number of iterator definitions. + unsigned NumIterators = 0; + + OMPIteratorExpr(QualType ExprTy, SourceLocation IteratorKwLoc, + SourceLocation L, SourceLocation R, + ArrayRef<OMPIteratorExpr::IteratorDefinition> Data); + + /// Construct an empty expression. + explicit OMPIteratorExpr(EmptyShell Shell, unsigned NumIterators) + : Expr(OMPIteratorExprClass, Shell), NumIterators(NumIterators) {} + + /// Sets basic declaration for the specified iterator definition. + void setIteratorDeclaration(unsigned I, Decl *D); + + /// Sets the location of the assignment symbol for the specified iterator + /// definition. + void setAssignmentLoc(unsigned I, SourceLocation Loc); + + /// Sets begin, end and optional step expressions for specified iterator + /// definition. + void setIteratorRange(unsigned I, Expr *Begin, SourceLocation ColonLoc, + Expr *End, SourceLocation SecondColonLoc, Expr *Step); + + unsigned numTrailingObjects(OverloadToken<Decl *>) const { + return NumIterators; + } + + unsigned numTrailingObjects(OverloadToken<Expr *>) const { + return NumIterators * static_cast<int>(RangeExprOffset::Total); + } + + unsigned numTrailingObjects(OverloadToken<SourceRange>) const { + return NumIterators * static_cast<int>(RangeLocOffset::Total); + } + +public: + static OMPIteratorExpr *Create(const ASTContext &Context, QualType T, + SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, + ArrayRef<IteratorDefinition> Data); + + static OMPIteratorExpr *CreateEmpty(const ASTContext &Context, + unsigned NumIterators); + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + SourceLocation getIteratorKwLoc() const { return IteratorKwLoc; } + void setIteratorKwLoc(SourceLocation L) { IteratorKwLoc = L; } + SourceLocation getBeginLoc() const LLVM_READONLY { return IteratorKwLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RPLoc; } + + /// Gets the iterator declaration for the given iterator. + Decl *getIteratorDecl(unsigned I); + const Decl *getIteratorDecl(unsigned I) const { + return const_cast<OMPIteratorExpr *>(this)->getIteratorDecl(I); + } + + /// Gets the iterator range for the given iterator. + IteratorRange getIteratorRange(unsigned I); + const IteratorRange getIteratorRange(unsigned I) const { + return const_cast<OMPIteratorExpr *>(this)->getIteratorRange(I); + } + + /// Gets the location of '=' for the given iterator definition. + SourceLocation getAssignLoc(unsigned I) const; + /// Gets the location of the first ':' in the range for the given iterator + /// definition. + SourceLocation getColonLoc(unsigned I) const; + /// Gets the location of the second ':' (if any) in the range for the given + /// iteratori definition. + SourceLocation getSecondColonLoc(unsigned I) const; + + /// Returns number of iterator definitions. + unsigned numOfIterators() const { return NumIterators; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPIteratorExprClass; + } + + // Iterators + child_range children() { + Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>()); + return child_range( + Begin, Begin + NumIterators * static_cast<int>(RangeExprOffset::Total)); + } + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>()); + return const_child_range( + Begin, Begin + NumIterators * static_cast<int>(RangeExprOffset::Total)); + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 0d4b69911f19..028af6ac9a72 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -4372,6 +4372,9 @@ class OMPDependClause final /// Set colon location. void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// Sets optional dependency modifier. + void setModifier(Expr *DepModifier); + public: /// Creates clause with a list of variables \a VL. /// @@ -4387,7 +4390,7 @@ class OMPDependClause final /// clause. static OMPDependClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, + SourceLocation EndLoc, Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL, unsigned NumLoops); @@ -4404,6 +4407,12 @@ class OMPDependClause final /// Get dependency type. OpenMPDependClauseKind getDependencyKind() const { return DepKind; } + /// Return optional depend modifier. + Expr *getModifier(); + const Expr *getModifier() const { + return const_cast<OMPDependClause *>(this)->getModifier(); + } + /// Get dependency type location. SourceLocation getDependencyLoc() const { return DepLoc; } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 46661e59f181..345333849659 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2552,6 +2552,7 @@ DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {}) +DEF_TRAVERSE_STMT(OMPIteratorExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index b08d1e482be8..0fb4baf0ca4d 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -274,6 +274,7 @@ class TextNodeDumper void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); + void VisitOMPIteratorExpr(const OMPIteratorExpr *Node); void VisitRValueReferenceType(const ReferenceType *T); void VisitArrayType(const ArrayType *T); diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 6eb320a85a30..f3741531c8b5 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1220,6 +1220,10 @@ def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; def err_omp_expected_reduction_identifier : Error< "expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'">; +def err_omp_expected_equal_in_iterator : Error< + "expected '=' in iterator specifier">; +def err_omp_expected_punc_after_iterator : Error< + "expected ',' or ')' after iterator specifier">; def err_omp_decl_in_declare_simd_variant : Error< "function declaration is expected after 'declare %select{simd|variant}0' directive">; def err_omp_unknown_map_type : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 951a955984f6..901ac758b383 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9760,6 +9760,14 @@ def note_omp_conversion_here : Note< def err_omp_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; +def err_omp_iterator_not_integral_or_pointer : Error< + "expected integral or pointer type as the iterator-type, not %0">; +def err_omp_iterator_constant : Error< + "expected non-constant type as the iterator-type, constant %0 is provided">; +def err_omp_iterator_step_not_integral : Error< + "iterator step expression %0 is not the integral expression">; +def err_omp_iterator_step_constant_zero : Error< + "iterator step expression %0 evaluates to 0">; def err_omp_required_access : Error< "%0 variable must be %1">; def err_omp_const_variable : Error< @@ -9953,6 +9961,7 @@ def err_omp_invalid_mapper: Error< "cannot find a valid user-defined mapper for type %0 with name %1">; def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">; def err_omp_array_shaping_use : Error<"OpenMP array shaping operation is not allowed here">; +def err_omp_iterator_use : Error<"OpenMP iterator 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< @@ -10031,6 +10040,10 @@ def err_omp_depend_sink_source_not_allowed : Error< "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; def err_omp_depend_zero_length_array_section_not_allowed : Error< "zero-length array section is not allowed in 'depend' clause">; +def err_omp_depend_sink_source_with_modifier : Error< + "depend modifier cannot be used with 'sink' or 'source' depend type">; +def err_omp_depend_modifier_not_iterator : Error< + "expected iterator specification as depend modifier">; def err_omp_linear_ordered : Error< "'linear' clause cannot be specified along with 'ordered' clause with a parameter">; def err_omp_unexpected_schedule_modifier : Error< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index ba1b5ebd6305..aecf24f89033 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -70,6 +70,7 @@ def OffsetOfExpr : StmtNode<Expr>; def UnaryExprOrTypeTraitExpr : StmtNode<Expr>; def ArraySubscriptExpr : StmtNode<Expr>; def OMPArraySectionExpr : StmtNode<Expr>; +def OMPIteratorExpr : StmtNode<Expr>; def CallExpr : StmtNode<Expr>; def MemberExpr : StmtNode<Expr>; def CastExpr : StmtNode<Expr, 1>; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 290da0006116..ca0a5fd68994 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3086,6 +3086,11 @@ class Parser : public CodeCompletionHandler { OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly); + /// Parses and creates OpenMP 5.0 iterators expression: + /// <iterators> = 'iterator' '(' { [ <iterator-type> ] identifier = + /// <range-specification> }+ ')' + ExprResult ParseOpenMPIteratorsExpr(); + public: /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. @@ -3095,7 +3100,7 @@ class Parser : public CodeCompletionHandler { /// Data used for parsing list of variables in OpenMP clauses. struct OpenMPVarListDataTy { - Expr *TailExpr = nullptr; + Expr *DepModOrTailExpr = nullptr; SourceLocation ColonLoc; SourceLocation RLoc; CXXScopeSpec ReductionOrMapperIdScopeSpec; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9a41356ddb70..e1365e84a0b3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" @@ -4904,6 +4905,21 @@ class Sema final { ArrayRef<Expr *> Dims, ArrayRef<SourceRange> Brackets); + /// Data structure for iterator expression. + struct OMPIteratorData { + IdentifierInfo *DeclIdent = nullptr; + SourceLocation DeclIdentLoc; + ParsedType Type; + OMPIteratorExpr::IteratorRange Range; + SourceLocation AssignLoc; + SourceLocation ColonLoc; + SourceLocation SecColonLoc; + }; + + ExprResult ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<OMPIteratorData> Data); + // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after // changing the access operator from a '.' to a '->' (to see if that is the @@ -10572,7 +10588,7 @@ class Sema final { SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, @@ -10670,10 +10686,10 @@ class Sema final { SourceLocation EndLoc); /// Called on well-formed 'depend' clause. OMPClause * - ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc); + ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, Expr *Device, SourceLocation StartLoc, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 68bcb26b6df5..e6e9c8570cc8 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1019,6 +1019,9 @@ namespace serialization { /// The placeholder type for OpenMP array shaping operation. PREDEF_TYPE_OMP_ARRAY_SHAPING = 70, + /// The placeholder type for OpenMP iterator expression. + PREDEF_TYPE_OMP_ITERATOR = 71, + /// OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, @@ -1872,6 +1875,7 @@ namespace serialization { STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, EXPR_OMP_ARRAY_SECTION, EXPR_OMP_ARRAY_SHAPING, + EXPR_OMP_ITERATOR, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8bee34e65754..1e81e0a67b4d 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1389,6 +1389,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, if (LangOpts.OpenMP) { InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping); + InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); } // C99 6.2.5p11. diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index a023ed173184..3a326f62a2ec 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -372,6 +372,22 @@ ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) { return D; } +ExprDependence clang::computeDependence(OMPIteratorExpr *E) { + auto D = toExprDependence(E->getType()->getDependence()); + for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { + if (auto *VD = cast_or_null<ValueDecl>(E->getIteratorDecl(I))) + D |= toExprDependence(VD->getType()->getDependence()); + OMPIteratorExpr::IteratorRange IR = E->getIteratorRange(I); + if (Expr *BE = IR.Begin) + D |= BE->getDependence(); + if (Expr *EE = IR.End) + D |= EE->getDependence(); + if (Expr *SE = IR.Step) + D |= SE->getDependence(); + } + return D; +} + /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index fb63897d871f..53ec3b7a93db 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3399,6 +3399,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ArraySubscriptExprClass: case OMPArraySectionExprClass: case OMPArrayShapingExprClass: + case OMPIteratorExprClass: case MemberExprClass: case ConditionalOperatorClass: case BinaryConditionalOperatorClass: @@ -4617,3 +4618,118 @@ OMPArrayShapingExpr *OMPArrayShapingExpr::CreateEmpty(const ASTContext &Context, alignof(OMPArrayShapingExpr)); return new (Mem) OMPArrayShapingExpr(EmptyShell(), NumDims); } + +void OMPIteratorExpr::setIteratorDeclaration(unsigned I, Decl *D) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects<Decl *>()[I] = D; +} + +void OMPIteratorExpr::setAssignmentLoc(unsigned I, SourceLocation Loc) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::AssignLoc)] = Loc; +} + +void OMPIteratorExpr::setIteratorRange(unsigned I, Expr *Begin, + SourceLocation ColonLoc, Expr *End, + SourceLocation SecondColonLoc, + Expr *Step) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects<Expr *>()[I * static_cast<int>(RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::Begin)] = + Begin; + getTrailingObjects<Expr *>()[I * static_cast<int>(RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::End)] = End; + getTrailingObjects<Expr *>()[I * static_cast<int>(RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::Step)] = Step; + getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::FirstColonLoc)] = + ColonLoc; + getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::SecondColonLoc)] = + SecondColonLoc; +} + +Decl *OMPIteratorExpr::getIteratorDecl(unsigned I) { + return getTrailingObjects<Decl *>()[I]; +} + +OMPIteratorExpr::IteratorRange OMPIteratorExpr::getIteratorRange(unsigned I) { + IteratorRange Res; + Res.Begin = + getTrailingObjects<Expr *>()[I * static_cast<int>( + RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::Begin)]; + Res.End = + getTrailingObjects<Expr *>()[I * static_cast<int>( + RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::End)]; + Res.Step = + getTrailingObjects<Expr *>()[I * static_cast<int>( + RangeExprOffset::Total) + + static_cast<int>(RangeExprOffset::Step)]; + return Res; +} + +SourceLocation OMPIteratorExpr::getAssignLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::AssignLoc)]; +} + +SourceLocation OMPIteratorExpr::getColonLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::FirstColonLoc)]; +} + +SourceLocation OMPIteratorExpr::getSecondColonLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast<int>(RangeLocOffset::Total) + + static_cast<int>(RangeLocOffset::SecondColonLoc)]; +} + +OMPIteratorExpr::OMPIteratorExpr( + QualType ExprTy, SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, ArrayRef<OMPIteratorExpr::IteratorDefinition> Data) + : Expr(OMPIteratorExprClass, ExprTy, VK_LValue, OK_Ordinary), + IteratorKwLoc(IteratorKwLoc), LPLoc(L), RPLoc(R), + NumIterators(Data.size()) { + for (unsigned I = 0, End = Data.size(); I < End; ++I) { + const IteratorDefinition &D = Data[I]; + setIteratorDeclaration(I, D.IteratorDecl); + setIteratorRange(I, D.Range.Begin, D.ColonLoc, D.Range.End, + D.SecondColonLoc, D.Range.Step); + } + setDependence(computeDependence(this)); +} + +OMPIteratorExpr * +OMPIteratorExpr::Create(const ASTContext &Context, QualType T, + SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, + ArrayRef<OMPIteratorExpr::IteratorDefinition> Data) { + void *Mem = Context.Allocate( + totalSizeToAlloc<Decl *, Expr *, SourceLocation>( + Data.size(), Data.size() * static_cast<int>(RangeExprOffset::Total), + Data.size() * static_cast<int>(RangeLocOffset::Total)), + alignof(OMPIteratorExpr)); + auto *E = new (Mem) OMPIteratorExpr(T, IteratorKwLoc, L, R, Data); + return E; +} + +OMPIteratorExpr *OMPIteratorExpr::CreateEmpty(const ASTContext &Context, + unsigned NumIterators) { + void *Mem = Context.Allocate( + totalSizeToAlloc<Decl *, Expr *, SourceLocation>( + NumIterators, NumIterators * static_cast<int>(RangeExprOffset::Total), + NumIterators * static_cast<int>(RangeLocOffset::Total)), + alignof(OMPIteratorExpr)); + return new (Mem) OMPIteratorExpr(EmptyShell(), NumIterators); +} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 4505626bb61f..8587a476a5d9 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -141,6 +141,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::MSPropertySubscriptExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4a11c846f4ab..c6e1cc7b67df 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14181,6 +14181,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 4c05990ee410..cb7bd61574ef 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3715,6 +3715,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::RecoveryExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::CXXInheritedCtorInitExprClass: llvm_unreachable("unexpected statement kind"); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 2bfe977a5ba5..3bb3605ea936 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -484,6 +484,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: break; } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 4b7ebbb3c26d..eeb690750fb7 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -900,16 +900,19 @@ OMPDepobjClause *OMPDepobjClause::CreateEmpty(const ASTContext &C) { OMPDependClause * OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, - OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef<Expr *> VL, - unsigned NumLoops) { - void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + NumLoops)); + Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VL, unsigned NumLoops) { + void *Mem = C.Allocate( + totalSizeToAlloc<Expr *>(VL.size() + /*depend-modifier*/ 1 + NumLoops), + alignof(OMPDependClause)); OMPDependClause *Clause = new (Mem) OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops); Clause->setVarRefs(VL); Clause->setDependencyKind(DepKind); Clause->setDependencyLoc(DepLoc); Clause->setColonLoc(ColonLoc); + Clause->setModifier(DepModifier); for (unsigned I = 0 ; I < NumLoops; ++I) Clause->setLoopData(I, nullptr); return Clause; @@ -917,7 +920,9 @@ OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N, unsigned NumLoops) { - void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + NumLoops)); + void *Mem = + C.Allocate(totalSizeToAlloc<Expr *>(N + /*depend-modifier*/ 1 + NumLoops), + alignof(OMPDependClause)); return new (Mem) OMPDependClause(N, NumLoops); } @@ -927,7 +932,7 @@ void OMPDependClause::setLoopData(unsigned NumLoop, Expr *Cnt) { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + auto *It = std::next(getVarRefs().end(), NumLoop + 1); *It = Cnt; } @@ -937,7 +942,7 @@ Expr *OMPDependClause::getLoopData(unsigned NumLoop) { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + auto *It = std::next(getVarRefs().end(), NumLoop + 1); return *It; } @@ -947,10 +952,15 @@ const Expr *OMPDependClause::getLoopData(unsigned NumLoop) const { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + const auto *It = std::next(getVarRefs().end(), NumLoop + 1); return *It; } +void OMPDependClause::setModifier(Expr *DepModifier) { + *getVarRefs().end() = DepModifier; +} +Expr *OMPDependClause::getModifier() { return *getVarRefs().end(); } + unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber( MappableExprComponentListsRef ComponentLists) { unsigned TotalNum = 0u; @@ -1727,6 +1737,10 @@ void OMPClausePrinter::VisitOMPDepobjClause(OMPDepobjClause *Node) { void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) { OS << "depend("; + if (Expr *DepModifier = Node->getModifier()) { + DepModifier->printPretty(OS, nullptr, Policy); + OS << ", "; + } OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Node->getDependencyKind()); if (!Node->varlist_empty()) { diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 3d03f3902d61..26e1a5009565 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1361,6 +1361,24 @@ void StmtPrinter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *Node) { PrintExpr(Node->getBase()); } +void StmtPrinter::VisitOMPIteratorExpr(OMPIteratorExpr *Node) { + OS << "iterator("; + for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) { + auto *VD = cast<ValueDecl>(Node->getIteratorDecl(I)); + VD->getType().print(OS, Policy); + const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I); + OS << " " << VD->getName() << " = "; + PrintExpr(Range.Begin); + OS << ":"; + PrintExpr(Range.End); + if (Node->getSecondColonLoc(I).isValid()) + PrintExpr(Range.Step); + if (I < E - 1) + OS << ", "; + } + OS << ")"; +} + void StmtPrinter::PrintCallArgs(CallExpr *Call) { for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { if (isa<CXXDefaultArgExpr>(Call->getArg(i))) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 054276a98424..fec12ac98b4e 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1198,6 +1198,12 @@ void StmtProfiler::VisitOMPArrayShapingExpr(const OMPArrayShapingExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitOMPIteratorExpr(const OMPIteratorExpr *S) { + VisitExpr(S); + for (unsigned I = 0, E = S->numOfIterators(); I < E; ++I) + VisitDecl(S->getIteratorDecl(I)); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 6a6d8692228a..dc0dd92f09df 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1086,6 +1086,23 @@ void TextNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); } +void TextNodeDumper::VisitOMPIteratorExpr(const OMPIteratorExpr *Node) { + OS << " "; + for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) { + Visit(Node->getIteratorDecl(I)); + OS << " = "; + const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I); + OS << " begin "; + Visit(Range.Begin); + OS << " end "; + Visit(Range.End); + if (Range.Step) { + OS << " step "; + Visit(Range.Step); + } + } +} + void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) { if (T->isSpelledAsLValue()) OS << " written as lvalue reference"; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index f90eb5cb9c92..3428437c3146 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2910,6 +2910,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "<OpenMP array section type>"; case OMPArrayShaping: return "<OpenMP array shaping type>"; + case OMPIterator: + return "<OpenMP iterator type>"; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case Id: \ return #ExtType; @@ -3917,6 +3919,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case BuiltinType::NullPtr: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return false; } llvm_unreachable("unknown builtin type"); diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index dd48ae3fc262..50391dba2a05 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -405,6 +405,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return TST_unspecified; } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 147d1b271d0c..42083b8b921e 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -755,7 +755,8 @@ static bool parseDeclareSimdClauses( getOpenMPClauseKind(ClauseName), *Vars, Data)) IsError = true; if (CKind == OMPC_aligned) { - Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); + Alignments.append(Aligneds.size() - Alignments.size(), + Data.DepModOrTailExpr); } else if (CKind == OMPC_linear) { assert(0 <= Data.ExtraModifier && Data.ExtraModifier <= OMPC_LINEAR_unknown && @@ -766,7 +767,7 @@ static bool parseDeclareSimdClauses( Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), Data.ExtraModifier); - Steps.append(Linears.size() - Steps.size(), Data.TailExpr); + Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr); } } else // TODO: add parsing of other clauses. @@ -3054,6 +3055,114 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { P.ConsumeToken(); } +/// Parses simple expression in parens for single-expression clauses of OpenMP +/// constructs. +/// \param RLoc Returned location of right paren. +ExprResult Parser::ParseOpenMPIteratorsExpr() { + assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" && + "Expected 'iterator' token."); + SourceLocation IteratorKwLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator")) + return ExprError(); + + SourceLocation LLoc = T.getOpenLocation(); + SmallVector<Sema::OMPIteratorData, 4> Data; + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { + // Check if the type parsing is required. + ParsedType IteratorType; + if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) { + // identifier '=' is not found - parse type. + TypeResult TR = ParseTypeName(); + if (TR.isInvalid()) { + T.skipToEnd(); + return ExprError(); + } + IteratorType = TR.get(); + } + + // Parse identifier. + IdentifierInfo *II = nullptr; + SourceLocation IdLoc; + if (Tok.is(tok::identifier)) { + II = Tok.getIdentifierInfo(); + IdLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_unqualified_id) << 0; + } + + // Parse '='. + SourceLocation AssignLoc; + if (Tok.is(tok::equal)) + AssignLoc = ConsumeToken(); + else + Diag(Tok, diag::err_omp_expected_equal_in_iterator); + + // Parse range-specification - <begin> ':' <end> [ ':' <step> ] + ColonProtectionRAIIObject ColonRAII(*this); + // Parse <begin> + SourceLocation Loc = Tok.getLocation(); + ExprResult LHS = ParseCastExpression(AnyCastExpr); + ExprResult Begin = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc, + /*DiscardedValue=*/false); + // Parse ':'. + SourceLocation ColonLoc; + if (Tok.is(tok::colon)) + ColonLoc = ConsumeToken(); + + // Parse <end> + Loc = Tok.getLocation(); + LHS = ParseCastExpression(AnyCastExpr); + ExprResult End = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + End = Actions.ActOnFinishFullExpr(End.get(), Loc, + /*DiscardedValue=*/false); + + SourceLocation SecColonLoc; + ExprResult Step; + // Parse optional step. + if (Tok.is(tok::colon)) { + // Parse ':' + ColonLoc = ConsumeToken(); + // Parse <step> + Loc = Tok.getLocation(); + LHS = ParseCastExpression(AnyCastExpr); + Step = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Step = Actions.ActOnFinishFullExpr(Step.get(), Loc, + /*DiscardedValue=*/false); + } + + // Parse ',' or ')' + if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren)) + Diag(Tok, diag::err_omp_expected_punc_after_iterator); + if (Tok.is(tok::comma)) + ConsumeToken(); + + Sema::OMPIteratorData &D = Data.emplace_back(); + D.DeclIdent = II; + D.DeclIdentLoc = IdLoc; + D.Type = IteratorType; + D.AssignLoc = AssignLoc; + D.ColonLoc = ColonLoc; + D.SecColonLoc = SecColonLoc; + D.Range.Begin = Begin.get(); + D.Range.End = End.get(); + D.Range.Step = Step.get(); + } + + // Parse ')'. + SourceLocation RLoc = Tok.getLocation(); + if (!T.consumeClose()) + RLoc = T.getCloseLocation(); + + return Actions.ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc, LLoc, RLoc, + Data); +} + /// Parses clauses with list. bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, @@ -3069,6 +3178,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, getOpenMPClauseName(Kind))) return true; + bool DependWithIterator = false; bool NeedRParenForLinear = false; BalancedDelimiterTracker LinearT(*this, tok::l_paren, tok::annot_pragma_openmp_end); @@ -3106,6 +3216,22 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { + if (getLangOpts().OpenMP >= 50) { + if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") { + // Handle optional dependence modifier. + // iterator(iterators-definition) + // where iterators-definition is iterator-specifier [, + // iterators-definition ] + // where iterator-specifier is [ iterator-type ] identifier = + // range-specification + DependWithIterator = true; + EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); + ExprResult IteratorRes = ParseOpenMPIteratorsExpr(); + Data.DepModOrTailExpr = IteratorRes.get(); + // Parse ',' + ExpectAndConsume(tok::comma); + } + } // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); Data.ExtraModifier = getOpenMPSimpleClauseType( @@ -3227,7 +3353,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /*DiscardedValue=*/false); if (Tail.isUsable()) { if (Tok.is(tok::colon)) { - Data.TailExpr = Tail.get(); + Data.DepModOrTailExpr = Tail.get(); Data.ColonLoc = ConsumeToken(); TPA.Commit(); } else { @@ -3253,6 +3379,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, 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))) { + ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope); ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); // Parse variable ExprResult VarExpr = @@ -3289,7 +3416,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, /*DiscardedValue*/ false); if (Tail.isUsable()) - Data.TailExpr = Tail.get(); + Data.DepModOrTailExpr = Tail.get(); else SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -3299,8 +3426,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.RLoc = Tok.getLocation(); if (!T.consumeClose()) Data.RLoc = T.getCloseLocation(); + // Exit from scope when the iterator is used in depend clause. + if (DependWithIterator) + ExitScope(); return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || - (MustHaveTail && !Data.TailExpr) || InvalidReductionId || + (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId || IsInvalidMapperModifier; } @@ -3372,7 +3502,7 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, return nullptr; OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); return Actions.ActOnOpenMPVarListClause( - Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, + Kind, Vars, Data.DepModOrTailExpr, Locs, Data.ColonLoc, Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, Data.IsMapTypeImplicit, Data.ExtraModifierLoc); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index fad2ae1cc066..0dc0c68205fb 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1300,6 +1300,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::BinaryOperatorClass: case Expr::DependentCoawaitExprClass: case Expr::CompoundAssignOperatorClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c0f8600aa0cc..8d0e97c85771 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4873,6 +4873,131 @@ ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, LParenLoc, RParenLoc, NewDims, Brackets); } +ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<OMPIteratorData> Data) { + SmallVector<OMPIteratorExpr::IteratorDefinition, 4> ID; + bool IsCorrect = true; + for (const OMPIteratorData &D : Data) { + TypeSourceInfo *TInfo = nullptr; + SourceLocation StartLoc; + QualType DeclTy; + if (!D.Type.getAsOpaquePtr()) { + // OpenMP 5.0, 2.1.6 Iterators + // In an iterator-specifier, if the iterator-type is not specified then + // the type of that iterator is of int type. + DeclTy = Context.IntTy; + StartLoc = D.DeclIdentLoc; + } else { + DeclTy = GetTypeFromParser(D.Type, &TInfo); + StartLoc = TInfo->getTypeLoc().getBeginLoc(); + } + + bool IsDeclTyDependent = DeclTy->isDependentType() || + DeclTy->containsUnexpandedParameterPack() || + DeclTy->isInstantiationDependentType(); + if (!IsDeclTyDependent) { + if (!DeclTy->isIntegralType(Context) && !DeclTy->isAnyPointerType()) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must be an integral or pointer type. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + if (DeclTy.isConstant(Context)) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must not be const qualified. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + } + + // Iterator declaration. + assert(D.DeclIdent && "Identifier expected."); + // Always try to create iterator declarator to avoid extra error messages + // about unknown declarations use. + auto *VD = VarDecl::Create(Context, CurContext, StartLoc, D.DeclIdentLoc, + D.DeclIdent, DeclTy, TInfo, SC_None); + VD->setImplicit(); + if (S) { + // Check for conflicting previous declaration. + DeclarationNameInfo NameInfo(VD->getDeclName(), D.DeclIdentLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); + Previous.suppressDiagnostics(); + LookupName(Previous, S); + + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + if (!Previous.empty()) { + NamedDecl *Old = Previous.getRepresentativeDecl(); + Diag(D.DeclIdentLoc, diag::err_redefinition) << VD->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } else { + PushOnScopeChains(VD, S); + } + } else { + CurContext->addDecl(VD); + } + Expr *Begin = D.Range.Begin; + if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) { + ExprResult BeginRes = + PerformImplicitConversion(Begin, DeclTy, AA_Converting); + Begin = BeginRes.get(); + } + Expr *End = D.Range.End; + if (!IsDeclTyDependent && End && !End->isTypeDependent()) { + ExprResult EndRes = PerformImplicitConversion(End, DeclTy, AA_Converting); + End = EndRes.get(); + } + Expr *Step = D.Range.Step; + if (!IsDeclTyDependent && Step && !Step->isTypeDependent()) { + if (!Step->getType()->isIntegralType(Context)) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_not_integral) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + llvm::APSInt Result; + bool IsConstant = Step->isIntegerConstantExpr(Result, Context); + // OpenMP 5.0, 2.1.6 Iterators, Restrictions + // If the step expression of a range-specification equals zero, the + // behavior is unspecified. + if (IsConstant && Result.isNullValue()) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + } + if (!Begin || !End || !IsCorrect) { + IsCorrect = false; + continue; + } + OMPIteratorExpr::IteratorDefinition &IDElem = ID.emplace_back(); + IDElem.IteratorDecl = VD; + IDElem.AssignmentLoc = D.AssignLoc; + IDElem.Range.Begin = Begin; + IDElem.Range.End = End; + IDElem.Range.Step = Step; + IDElem.ColonLoc = D.ColonLoc; + IDElem.SecondColonLoc = D.SecColonLoc; + } + if (!IsCorrect) { + // Invalidate all created iterator declarations if error is found. + for (const OMPIteratorExpr::IteratorDefinition &D : ID) { + if (Decl *ID = D.IteratorDecl) + ID->setInvalidDecl(); + } + return ExprError(); + } + return OMPIteratorExpr::Create(Context, Context.OMPIteratorTy, IteratorKwLoc, + LLoc, RLoc, ID); +} + ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -5634,6 +5759,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return true; } @@ -18513,6 +18639,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { case BuiltinType::OMPArrayShaping: return ExprError(Diag(E->getBeginLoc(), diag::err_omp_array_shaping_use)); + case BuiltinType::OMPIterator: + return ExprError(Diag(E->getBeginLoc(), diag::err_omp_iterator_use)); + // Everything else should be impossible. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 7d2ae172fe4d..df56c3be43fc 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -13053,7 +13053,7 @@ OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc, } OMPClause *Sema::ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, @@ -13103,13 +13103,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown && "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( - VarList, TailExpr, StartLoc, LParenLoc, + VarList, DepModOrTailExpr, StartLoc, LParenLoc, static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: - Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -13124,8 +13124,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast<OpenMPDependClauseKind>(ExtraModifier), ExtraModifierLoc, - ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && @@ -13150,8 +13150,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); break; case OMPC_allocate: - Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_nontemporal: Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -15642,7 +15642,7 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, } OMPClause * -Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, +Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -15664,12 +15664,26 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, Except.push_back(OMPC_DEPEND_sink); if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) Except.push_back(OMPC_DEPEND_depobj); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_depend, /*First=*/0, - /*Last=*/OMPC_DEPEND_unknown, Except) + << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, + Except) << getOpenMPClauseName(OMPC_depend); return nullptr; } + if (DepModifier && + (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { + Diag(DepModifier->getExprLoc(), + diag::err_omp_depend_sink_source_with_modifier); + return nullptr; + } + if (DepModifier && + !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) + Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); + SmallVector<Expr *, 8> Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); @@ -15878,8 +15892,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, - DepKind, DepLoc, ColonLoc, Vars, - TotalDepCount.getZExtValue()); + DepModifier, DepKind, DepLoc, ColonLoc, + Vars, TotalDepCount.getZExtValue()); if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) && DSAStack->isParentOrderedRegion()) DSAStack->addDoacrossDependClause(C, OpsOffs); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 82cfa246e3f7..de05d436d3b9 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1842,12 +1842,13 @@ class TreeTransform { /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide diff erent behavior. OMPClause * - RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, - StartLoc, LParenLoc, EndLoc); + RebuildOMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDependClause(DepModifier, DepKind, DepLoc, + ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); } /// Build a new OpenMP 'device' clause. @@ -2391,6 +2392,17 @@ class TreeTransform { BracketsRanges); } + /// Build a new iterator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide diff erent behavior. + ExprResult RebuildOMPIteratorExpr( + SourceLocation IteratorKwLoc, SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<Sema::OMPIteratorData> Data) { + return getSema().ActOnOMPIteratorExpr(/*Scope=*/nullptr, IteratorKwLoc, + LLoc, RLoc, Data); + } + /// Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -9291,6 +9303,13 @@ template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) { llvm::SmallVector<Expr *, 16> Vars; + Expr *DepModifier = C->getModifier(); + if (DepModifier) { + ExprResult DepModRes = getDerived().TransformExpr(DepModifier); + if (DepModRes.isInvalid()) + return nullptr; + DepModifier = DepModRes.get(); + } Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); @@ -9299,8 +9318,9 @@ TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) { Vars.push_back(EVar.get()); } return getDerived().RebuildOMPDependClause( - C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars, - C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + DepModifier, C->getDependencyKind(), C->getDependencyLoc(), + C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); } template <typename Derived> @@ -10054,6 +10074,65 @@ TreeTransform<Derived>::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) { E->getBracketsRanges()); } +template <typename Derived> +ExprResult +TreeTransform<Derived>::TransformOMPIteratorExpr(OMPIteratorExpr *E) { + unsigned NumIterators = E->numOfIterators(); + SmallVector<Sema::OMPIteratorData, 4> Data(NumIterators); + + bool ErrorFound = false; + bool NeedToRebuild = getDerived().AlwaysRebuild(); + for (unsigned I = 0; I < NumIterators; ++I) { + auto *D = cast<VarDecl>(E->getIteratorDecl(I)); + Data[I].DeclIdent = D->getIdentifier(); + Data[I].DeclIdentLoc = D->getLocation(); + if (D->getLocation() == D->getBeginLoc()) { + assert(SemaRef.Context.hasSameType(D->getType(), SemaRef.Context.IntTy) && + "Implicit type must be int."); + } else { + TypeSourceInfo *TSI = getDerived().TransformType(D->getTypeSourceInfo()); + QualType DeclTy = getDerived().TransformType(D->getType()); + Data[I].Type = SemaRef.CreateParsedType(DeclTy, TSI); + } + OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I); + ExprResult Begin = getDerived().TransformExpr(Range.Begin); + ExprResult End = getDerived().TransformExpr(Range.End); + ExprResult Step = getDerived().TransformExpr(Range.Step); + ErrorFound = ErrorFound || + !(!D->getTypeSourceInfo() || (Data[I].Type.getAsOpaquePtr() && + !Data[I].Type.get().isNull())) || + Begin.isInvalid() || End.isInvalid() || Step.isInvalid(); + if (ErrorFound) + continue; + Data[I].Range.Begin = Begin.get(); + Data[I].Range.End = End.get(); + Data[I].Range.Step = Step.get(); + Data[I].AssignLoc = E->getAssignLoc(I); + Data[I].ColonLoc = E->getColonLoc(I); + Data[I].SecColonLoc = E->getSecondColonLoc(I); + NeedToRebuild = + NeedToRebuild || + (D->getTypeSourceInfo() && Data[I].Type.get().getTypePtrOrNull() != + D->getType().getTypePtrOrNull()) || + Range.Begin != Data[I].Range.Begin || Range.End != Data[I].Range.End || + Range.Step != Data[I].Range.Step; + } + if (ErrorFound) + return ExprError(); + if (!NeedToRebuild) + return E; + + ExprResult Res = getDerived().RebuildOMPIteratorExpr( + E->getIteratorKwLoc(), E->getLParenLoc(), E->getRParenLoc(), Data); + if (!Res.isUsable()) + return Res; + auto *IE = cast<OMPIteratorExpr>(Res.get()); + for (unsigned I = 0; I < NumIterators; ++I) + getDerived().transformedLocalDecl(E->getIteratorDecl(I), + IE->getIteratorDecl(I)); + return Res; +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 158a12f0329d..566bda2d71f7 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -246,6 +246,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::OMPArrayShaping: ID = PREDEF_TYPE_OMP_ARRAY_SHAPING; break; + case BuiltinType::OMPIterator: + ID = PREDEF_TYPE_OMP_ITERATOR; + break; } return TypeIdx(ID); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 7437f649a090..d4764229abfc 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6960,6 +6960,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_OMP_ARRAY_SHAPING: T = Context.OMPArraySectionTy; break; + case PREDEF_TYPE_OMP_ITERATOR: + T = Context.OMPIteratorTy; + break; #define SVE_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ @@ -12307,6 +12310,7 @@ void OMPClauseReader::VisitOMPDepobjClause(OMPDepobjClause *C) { void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { C->setLParenLoc(Record.readSourceLocation()); + C->setModifier(Record.readSubExpr()); C->setDependencyKind( static_cast<OpenMPDependClauseKind>(Record.readInt())); C->setDependencyLoc(Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index bc8c231731e8..d5f2213aaabe 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -927,6 +927,24 @@ void ASTStmtReader::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { E->setRParenLoc(readSourceLocation()); } +void ASTStmtReader::VisitOMPIteratorExpr(OMPIteratorExpr *E) { + VisitExpr(E); + unsigned NumIterators = Record.readInt(); + E->setIteratorKwLoc(readSourceLocation()); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); + for (unsigned I = 0; I < NumIterators; ++I) { + E->setIteratorDeclaration(I, Record.readDeclRef()); + E->setAssignmentLoc(I, readSourceLocation()); + Expr *Begin = Record.readSubExpr(); + Expr *End = Record.readSubExpr(); + Expr *Step = Record.readSubExpr(); + SourceLocation ColonLoc = readSourceLocation(); + SourceLocation SecColonLoc = readSourceLocation(); + E->setIteratorRange(I, Begin, ColonLoc, End, SecColonLoc, Step); + } +} + void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); unsigned NumArgs = Record.readInt(); @@ -2887,6 +2905,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { Context, Record[ASTStmtReader::NumExprFields]); break; + case EXPR_OMP_ITERATOR: + S = OMPIteratorExpr::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_CALL: S = CallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f7c58ed11d9f..27f44a706f9f 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6379,6 +6379,7 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); Record.AddSourceLocation(C->getLParenLoc()); + Record.AddStmt(C->getModifier()); Record.push_back(C->getDependencyKind()); Record.AddSourceLocation(C->getDependencyLoc()); Record.AddSourceLocation(C->getColonLoc()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 840823298be7..5a56b265b781 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -787,6 +787,25 @@ void ASTStmtWriter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { Code = serialization::EXPR_OMP_ARRAY_SHAPING; } +void ASTStmtWriter::VisitOMPIteratorExpr(OMPIteratorExpr *E) { + VisitExpr(E); + Record.push_back(E->numOfIterators()); + Record.AddSourceLocation(E->getIteratorKwLoc()); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { + Record.AddDeclRef(E->getIteratorDecl(I)); + Record.AddSourceLocation(E->getAssignLoc(I)); + OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I); + Record.AddStmt(Range.Begin); + Record.AddStmt(Range.End); + Record.AddStmt(Range.Step); + Record.AddSourceLocation(E->getColonLoc(I)); + Record.AddSourceLocation(E->getSecondColonLoc(I)); + } + Code = serialization::EXPR_OMP_ITERATOR; +} + void ASTStmtWriter::VisitCallExpr(CallExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index d16410a19b97..1cf81b54e77d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -352,6 +352,7 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, case Stmt::ArraySubscriptExprClass: case Stmt::OMPArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: + case Stmt::OMPIteratorExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ParenExprClass: case Stmt::BreakStmtClass: diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4c0914628a0d..1f0d89d59120 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1414,6 +1414,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXNullPtrLiteralExprClass: case Stmt::OMPArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: + case Stmt::OMPIteratorExprClass: case Stmt::TypeTraitExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; diff --git a/clang/test/OpenMP/depobj_messages.cpp b/clang/test/OpenMP/depobj_messages.cpp index a33b16f985a0..1b20b1c525e7 100644 --- a/clang/test/OpenMP/depobj_messages.cpp +++ b/clang/test/OpenMP/depobj_messages.cpp @@ -142,7 +142,7 @@ label1 : { #pragma omp parallel depobj(argc) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} ; #pragma omp depobj(x) seq_cst // expected-error {{unexpected OpenMP clause 'seq_cst' in directive '#pragma omp depobj'}} -#pragma omp depobj(x) depend(source: x) // expected-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} +#pragma omp depobj(x) depend(source: x) // expected-error {{expected depend modifier(iterator) or 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} #pragma omp depobj(x) update // expected-error {{expected '(' after 'update'}} #pragma omp depobj(x) update( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'update'}} #pragma omp depobj(x) update(sink // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'update'}} diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp index 1da6c5045934..c465a1b1b07f 100644 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -26,7 +26,7 @@ struct S1 { template <typename T> class S7 : public T { protected: - T a, b; + T a, b, c[10], d[10]; S7() : a(0) {} public: @@ -34,7 +34,7 @@ class S7 : public T { omp_depend_t x; omp_event_handle_t evt; #pragma omp taskgroup allocate(b) task_reduction(+:b) -#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) detach(evt) +#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) detach(evt) depend(iterator(i=0:10:1, T *k = &a:&b), in: c[i], d[(int)(k-&a)]) for (int k = 0; k < a.a; ++k) ++this->a.a; } @@ -47,9 +47,9 @@ class S7 : public T { }; // CHECK: #pragma omp taskgroup allocate(this->b) task_reduction(+: this->b) -// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt){{$}} +// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10, T * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)]){{$}} // CHECK: #pragma omp task private(this->a) private(this->a) -// CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a) +// CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10, S1 * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)]) class S8 : public S7<S1> { S8() {} @@ -176,10 +176,10 @@ int main(int argc, char **argv) { // CHECK-NEXT: foo(); #pragma omp taskgroup task_reduction(min: arr1) #pragma omp parallel reduction(+:arr1) -#pragma omp task in_reduction(min: arr1) +#pragma omp task in_reduction(min: arr1) depend(iterator(i=0:argc, unsigned j=argc:0:a), out: argv[i][j]) // CHECK-NEXT: #pragma omp taskgroup task_reduction(min: arr1) // CHECK-NEXT: #pragma omp parallel reduction(+: arr1) - // CHECK-NEXT: #pragma omp task in_reduction(min: arr1) + // CHECK-NEXT: #pragma omp task in_reduction(min: arr1) depend(iterator(int i = 0:argc, unsigned int j = argc:0), out : argv[i][j]) foo(); // CHECK-NEXT: foo(); // CHECK-NEXT: #pragma omp task in_reduction(+: arr1) diff --git a/clang/test/OpenMP/task_depend_messages.cpp b/clang/test/OpenMP/task_depend_messages.cpp index f04c167cbdcc..bfb0e771b2ca 100644 --- a/clang/test/OpenMP/task_depend_messages.cpp +++ b/clang/test/OpenMP/task_depend_messages.cpp @@ -28,11 +28,11 @@ int main(int argc, char **argv, char *env[]) { #pragma omp task depend(in : arr[0]) #pragma omp task depend // expected-error {{expected '(' after 'depend'}} - #pragma omp task depend ( // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{missing ':' after dependency type - ignoring}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} - #pragma omp task depend () // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} - #pragma omp task depend (argc // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} - #pragma omp task depend (source : argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} - #pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend ( // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{missing ':' after dependency type - ignoring}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend () // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend (argc // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend (source : argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} #pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} #pragma omp task depend (out: ) // expected-error {{expected expression}} #pragma omp task depend (inout : foobool(argc)), depend (in, argc) // omp50-error {{expected addressable lvalue expression, array element, array section or array shaping expression}} omp45-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}} @@ -70,7 +70,19 @@ int main(int argc, char **argv, char *env[]) { #pragma omp task depend(in : ([a])a) // omp45-error {{expected body of lambda expression}} omp50-error {{expected expression with a pointer to a complete type as a base of an array shaping operation}} #pragma omp task depend(in : ([a])argc) // omp45-error {{expected body of lambda expression}} omp50-error {{expected expression with a pointer to a complete type as a base of an array shaping operation}} #pragma omp task depend(in : ([-1][0])argv) // omp45-error {{expected variable name or 'this' in lambda capture list}} omp45-error {{expected ')'}} omp45-note {{to match this '('}} omp50-error {{array shaping dimension is evaluated to a non-positive value -1}} omp50-error {{array shaping dimension is evaluated to a non-positive value 0}} + #pragma omp task depend(iterator // expected-error {{expected ')'}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-note {{to match this '('}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} omp50-error {{expected '(' after 'iterator'}} omp50-error {{expected ','}} + #pragma omp task depend(iterator():argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected ','}} omp50-error {{expected 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} + #pragma omp task depend(iterator(argc // expected-error {{expected ')'}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-note {{to match this '('}} omp50-error {{unknown type name 'argc'}} omp50-error {{expected ')'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} omp50-error {{expected ','}} omp50-note {{to match this '('}} + #pragma omp task depend(iterator(unsigned argc: // expected-error {{expected ')'}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-note {{to match this '('}} omp50-error {{expected '=' in iterator specifier}} omp50-error 2 {{expected expression}} omp50-error {{expected ',' or ')' after iterator specifier}} omp50-error {{expected ')'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} omp50-error {{expected ','}} omp50-note {{to match this '('}} + #pragma omp task depend(iterator(unsigned argc = // expected-error {{expected ')'}} omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-note {{to match this '('}} omp50-error 2 {{expected expression}} omp50-error {{expected ',' or ')' after iterator specifier}} omp50-error {{expected ')'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} omp50-error {{expected ','}} omp50-note {{to match this '('}} + #pragma omp task depend(iterator(vector argc = 0:2):argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{expected integral or pointer type as the iterator-type, not 'vector'}} omp50-error {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset' or 'depobj' in OpenMP clause 'depend'}} omp50-error {{expected ','}} + #pragma omp task depend(iterator(vector *argc = nullptr:nullptr+2:0), in:argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{invalid operands to binary expression ('nullptr_t' and 'int')}} omp50-error {{iterator step expression 0 evaluates to 0}} + #pragma omp task depend(iterator(vector *argc = 0:vector():argc), in:argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp50-error {{converting 'vector' to incompatible type 'vector *'}} foo(); +#pragma omp task depend(iterator(unsigned argc = 0:10), in : argc) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} + argc = 0; +#pragma omp task depend(iterator(i = 0:10, i = 0:10), in : argv[i]) // omp45-error {{expected 'in', 'out', 'inout' or 'mutexinoutset' in OpenMP clause 'depend'}} omp45-error {{use of undeclared identifier 'i'}} omp50-error {{redefinition of 'i'}} omp50-note {{previous definition is here}} + i = 0; // expected-error {{use of undeclared identifier 'i'}} return 0; } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index bb9fed165679..14814f89d97d 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5185,6 +5185,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OMPArraySectionExpr"); case CXCursor_OMPArrayShapingExpr: return cxstring::createRef("OMPArrayShapingExpr"); + case CXCursor_OMPIteratorExpr: + return cxstring::createRef("OMPIteratorExpr"); case CXCursor_BinaryOperator: return cxstring::createRef("BinaryOperator"); case CXCursor_CompoundAssignOperator: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 4f4e0c4ea1d5..3bcc7cc7af05 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -427,6 +427,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, K = CXCursor_OMPArrayShapingExpr; break; + case Stmt::OMPIteratorExprClass: + K = CXCursor_OMPIteratorExpr; + break; + case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits