Index: clang/include/clang/AST/OpenMPClause.h =================================================================== --- clang/include/clang/AST/OpenMPClause.h +++ clang/include/clang/AST/OpenMPClause.h @@ -322,6 +322,81 @@ } }; +/// This represents the 'align' clause in the '#pragma omp allocate' +/// directive. +/// +/// \code +/// #pragma omp allocate(a) allocator(omp_default_mem_alloc) align(8) +/// \endcode +/// In this example directive '#pragma omp allocate' has simple 'allocator' +/// clause with the allocator 'omp_default_mem_alloc' and align clause with +/// value of 8. +class OMPAlignClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Alignment specified with align clause. + Stmt *Alignment = nullptr; + + /// Set alignment value. + void setAlignment(Expr *A) { Alignment = A; } + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + /// Build 'align' clause with the given alignment + /// + /// \param A Alignment value. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPAlignClause(Expr *A, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_align, StartLoc, EndLoc), + LParenLoc(LParenLoc), Alignment(A) {} + + /// Build an empty clause. + OMPAlignClause() + : OMPClause(llvm::omp::OMPC_align, SourceLocation(), SourceLocation()) {} + +public: + /// Build 'align' clause with the given alignment + /// + /// \param A Alignment value. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + static OMPAlignClause *Create(const ASTContext &C, Expr *A, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns alignment + Expr *getAlignment() const { return cast_or_null(Alignment); } + + child_range children() { return child_range(&Alignment, &Alignment + 1); } + + const_child_range children() const { + return const_child_range(&Alignment, &Alignment + 1); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_align; + } +}; + /// This represents clause 'allocate' in the '#pragma omp ...' directives. /// /// \code Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -3093,6 +3093,12 @@ return true; } +template +bool RecursiveASTVisitor::VisitOMPAlignClause(OMPAlignClause *C) { + TRY_TO(TraverseStmt(C->getAlignment())); + return true; +} + template bool RecursiveASTVisitor::VisitOMPSafelenClause(OMPSafelenClause *C) { TRY_TO(TraverseStmt(C->getSafelen())); Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3683,7 +3683,8 @@ "OMPCGroupMemAlloc", "OMPPTeamMemAlloc", "OMPThreadMemAlloc", "OMPUserDefinedMemAlloc" ]>, - ExprArgument<"Allocator"> + ExprArgument<"Allocator">, + ExprArgument<"Alignment"> ]; let Documentation = [Undocumented]; } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11034,6 +11034,10 @@ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'align' clause. + OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, Index: clang/lib/AST/DeclPrinter.cpp =================================================================== --- clang/lib/AST/DeclPrinter.cpp +++ clang/lib/AST/DeclPrinter.cpp @@ -1662,10 +1662,11 @@ Out << ")"; } if (!D->clauselist_empty()) { - Out << " "; OMPClausePrinter Printer(Out, Policy); - for (OMPClause *C : D->clauselists()) + for (OMPClause *C : D->clauselists()) { + Out << " "; Printer.Visit(C); + } } } Index: clang/lib/AST/OpenMPClause.cpp =================================================================== --- clang/lib/AST/OpenMPClause.cpp +++ clang/lib/AST/OpenMPClause.cpp @@ -629,6 +629,13 @@ return new (Mem) OMPAlignedClause(NumVars); } +OMPAlignClause *OMPAlignClause::Create(const ASTContext &C, Expr *A, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return new (C) OMPAlignClause(A, StartLoc, LParenLoc, EndLoc); +} + void OMPCopyinClause::setSourceExprs(ArrayRef SrcExprs) { assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " "not the same as the " @@ -1622,6 +1629,12 @@ OS << ")"; } +void OMPClausePrinter::VisitOMPAlignClause(OMPAlignClause *Node) { + OS << "align("; + Node->getAlignment()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) { OS << "safelen("; Node->getSafelen()->printPretty(OS, nullptr, Policy, 0); Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ clang/lib/AST/StmtProfile.cpp @@ -452,6 +452,11 @@ Profiler->VisitStmt(C->getNumThreads()); } +void OMPClauseProfiler::VisitOMPAlignClause(const OMPAlignClause *C) { + if (C->getAlignment()) + Profiler->VisitStmt(C->getAlignment()); +} + void OMPClauseProfiler::VisitOMPSafelenClause(const OMPSafelenClause *C) { if (C->getSafelen()) Profiler->VisitStmt(C->getSafelen()); Index: clang/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- clang/lib/CodeGen/CGStmtOpenMP.cpp +++ clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -5993,6 +5993,7 @@ case OMPC_append_args: case OMPC_memory_order: case OMPC_bind: + case OMPC_align: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -3105,6 +3105,7 @@ case OMPC_nocontext: case OMPC_filter: case OMPC_partial: + case OMPC_align: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3362,6 +3363,9 @@ /// detach-clause: /// 'detach' '(' event-handler-expression ')' /// +/// align-clause +/// 'align' '(' positive-integer-constant ')' +/// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, bool ParseOnly) { SourceLocation Loc = ConsumeToken(); Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -3130,16 +3130,22 @@ static void applyOMPAllocateAttribute(Sema &S, VarDecl *VD, OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, - Expr *Allocator, SourceRange SR) { + Expr *Allocator, Expr *Alignment, SourceRange SR) { if (VD->hasAttr()) return; + if (Alignment && + (Alignment->isTypeDependent() || Alignment->isValueDependent() || + Alignment->isInstantiationDependent() || + Alignment->containsUnexpandedParameterPack())) + // Apply later when we have a usable value. + return; if (Allocator && (Allocator->isTypeDependent() || Allocator->isValueDependent() || Allocator->isInstantiationDependent() || Allocator->containsUnexpandedParameterPack())) return; auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind, - Allocator, SR); + Allocator, Alignment, SR); VD->addAttr(A); if (ASTMutationListener *ML = S.Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPAllocate(VD, A); @@ -3148,7 +3154,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( SourceLocation Loc, ArrayRef VarList, ArrayRef Clauses, DeclContext *Owner) { - assert(Clauses.size() <= 1 && "Expected at most one clause."); + assert(Clauses.size() <= 2 && "Expected at most two clauses."); + Expr *Alignment = nullptr; Expr *Allocator = nullptr; if (Clauses.empty()) { // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions. @@ -3159,7 +3166,13 @@ !DSAStack->hasRequiresDeclWithClause()) targetDiag(Loc, diag::err_expected_allocator_clause); } else { - Allocator = cast(Clauses.back())->getAllocator(); + for (const OMPClause *C : Clauses) + if (const auto *AC = dyn_cast(C)) + Allocator = AC->getAllocator(); + else if (const auto *AC = dyn_cast(C)) + Alignment = AC->getAlignment(); + else + llvm_unreachable("Unexpected clause on allocate directive"); } OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = getAllocatorKind(*this, DSAStack, Allocator); @@ -3200,7 +3213,7 @@ } Vars.push_back(RefExpr); - applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, + applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, Alignment, DE->getSourceRange()); } if (Vars.empty()) @@ -5228,8 +5241,10 @@ if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD, AllocatorKind, AC->getAllocator())) continue; + // Placeholder until allocate clause supports align modifier. + Expr *Alignment = nullptr; applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(), - E->getSourceRange()); + Alignment, E->getSourceRange()); } } } @@ -13415,6 +13430,9 @@ case OMPC_partial: Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_align: + Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_device: case OMPC_if: case OMPC_default: @@ -14528,7 +14546,7 @@ << E->getSourceRange(); return ExprError(); } - if (CKind == OMPC_aligned && !Result.isPowerOf2()) { + if ((CKind == OMPC_aligned || CKind == OMPC_align) && !Result.isPowerOf2()) { Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two) << E->getSourceRange(); return ExprError(); @@ -14953,6 +14971,17 @@ FactorExpr); } +OMPClause *Sema::ActOnOpenMPAlignClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + ExprResult AlignVal; + AlignVal = VerifyPositiveIntegerConstantInClause(A, OMPC_align); + if (AlignVal.isInvalid()) + return nullptr; + return OMPAlignClause::Create(Context, AlignVal.get(), StartLoc, LParenLoc, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3371,12 +3371,23 @@ SmallVector Clauses; // Copy map clauses from the original mapper. for (OMPClause *C : D->clauselists()) { - auto *AC = cast(C); - ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); - if (!NewE.isUsable()) - continue; - OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause( - NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + OMPClause *IC = nullptr; + if (auto *AC = dyn_cast(C)) { + ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); + if (!NewE.isUsable()) + continue; + IC = SemaRef.ActOnOpenMPAllocatorClause( + NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + } else if (auto *AC = dyn_cast(C)) { + ExprResult NewE = SemaRef.SubstExpr(AC->getAlignment(), TemplateArgs); + if (!NewE.isUsable()) + continue; + IC = SemaRef.ActOnOpenMPAlignClause(NewE.get(), AC->getBeginLoc(), + AC->getLParenLoc(), AC->getEndLoc()); + // If align clause value ends up being invalid, this can end up null. + if (!IC) + continue; + } Clauses.push_back(IC); } Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -2269,6 +2269,16 @@ EndLoc); } + /// Build a new OpenMP 'align' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAlignClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -9547,6 +9557,15 @@ C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause *TreeTransform::TransformOMPAlignClause(OMPAlignClause *C) { + ExprResult E = getDerived().TransformExpr(C->getAlignment()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPAlignClause(E.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause *TreeTransform::TransformOMPUnifiedAddressClause( OMPUnifiedAddressClause *C) { Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -11974,6 +11974,9 @@ case llvm::omp::OMPC_bind: C = OMPBindClause::CreateEmpty(Context); break; + case llvm::omp::OMPC_align: + C = new (Context) OMPAlignClause(); + break; #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; @@ -12964,6 +12967,11 @@ C->setBindKindLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPAlignClause(OMPAlignClause *C) { + C->setAlignment(Record.readExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -4757,9 +4757,10 @@ auto AllocatorKind = static_cast(Record.readInt()); Expr *Allocator = Record.readExpr(); + Expr *Alignment = Record.readExpr(); SourceRange SR = readSourceRange(); D->addAttr(OMPAllocateDeclAttr::CreateImplicit( - Reader.getContext(), AllocatorKind, Allocator, SR, + Reader.getContext(), AllocatorKind, Allocator, Alignment, SR, AttributeCommonInfo::AS_Pragma)); break; } Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -5026,6 +5026,7 @@ auto *A = D->getAttr(); Record.push_back(A->getAllocatorType()); Record.AddStmt(A->getAllocator()); + Record.AddStmt(A->getAlignment()); Record.AddSourceRange(A->getRange()); break; } @@ -6230,6 +6231,11 @@ Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPAlignClause(OMPAlignClause *C) { + Record.AddStmt(C->getAlignment()); + Record.AddSourceLocation(C->getLParenLoc()); +} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); Index: clang/test/OpenMP/align_clause_ast_print.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/align_clause_ast_print.cpp @@ -0,0 +1,134 @@ +// expected-no-diagnostics + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -ast-print %s | FileCheck %s --check-prefix=PRINT + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -ast-dump %s | FileCheck %s --check-prefix=DUMP + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -emit-pch -o %t %s + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP + +#ifndef HEADER +#define HEADER + +typedef enum omp_allocator_handle_t { + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +int foo1() { + char a; +#pragma omp allocate(a) align(4) allocator(omp_pteam_mem_alloc) + return a; +} +// DUMP: FunctionDecl {{.*}} +// DUMP: DeclStmt {{.*}} +// DUMP: VarDecl {{.*}}a 'char' +// DUMP: OMPAllocateDeclAttr {{.*}}OMPPTeamMemAlloc +// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_pteam_mem_alloc' 'omp_allocator_handle_t' +// DUMP: ConstantExpr {{.*}}'int' +// DUMP: value: Int 4 +// DUMP: IntegerLiteral {{.*}}'int' 4 +// DUMP: DeclStmt {{.*}} +// DUMP: OMPAllocateDecl {{.*}} +// DUMP: DeclRefExpr {{.*}}'char' lvalue Var {{.*}} 'a' 'char' +// DUMP: OMPAlignClause {{.*}} +// DUMP: ConstantExpr {{.*}}'int' +// DUMP: value: Int 4 +// DUMP: IntegerLiteral {{.*}}'int' 4 +// DUMP: OMPAllocatorClause {{.*}} +// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}}'omp_pteam_mem_alloc' 'omp_allocator_handle_t' +// PRINT: #pragma omp allocate(a) align(4) allocator(omp_pteam_mem_alloc) + +int foo2() { + char b; +#pragma omp allocate(b) allocator(omp_low_lat_mem_alloc) align(2) + return b; +} +// DUMP: FunctionDecl {{.*}} +// DUMP: DeclStmt {{.*}} +// DUMP: VarDecl {{.*}}b 'char' +// DUMP: OMPAllocateDeclAttr {{.*}}Implicit OMPLowLatMemAlloc +// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_low_lat_mem_alloc' 'omp_allocator_handle_t' +// DUMP: ConstantExpr {{.*}}'int' +// DUMP: value: Int 2 +// DUMP: IntegerLiteral {{.*}}'int' 2 +// DUMP: DeclStmt {{.*}} +// DUMP: OMPAllocateDecl {{.*}} +// DUMP: DeclRefExpr {{.*}}'char' lvalue Var {{.*}} 'b' 'char' +// DUMP: OMPAllocatorClause {{.*}} +// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_low_lat_mem_alloc' 'omp_allocator_handle_t' +// DUMP: OMPAlignClause {{.*}} +// DUMP: ConstantExpr {{.*}}'int' +// DUMP: value: Int 2 +// DUMP: IntegerLiteral {{.*}}'int' 2 +// PRINT: #pragma omp allocate(b) allocator(omp_low_lat_mem_alloc) align(2) + +template +T run() { + T foo; +#pragma omp allocate(foo) align(size) + return size; +} + +int template_test() { + double d; + d = run(); + return 0; +} + +// DUMP: FunctionTemplateDecl {{.*}} +// DUMP: TemplateTypeParmDecl {{.*}} +// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size +// DUMP: FunctionDecl {{.*}}'T ()' +// DUMP: DeclStmt {{.*}} +// DUMP: OMPAllocateDecl {{.*}} +// DUMP: DeclRefExpr {{.*}}'T' lvalue Var {{.*}} 'foo' 'T' +// DUMP: OMPAlignClause {{.*}} +// DUMP: DeclRefExpr {{.*}}'unsigned int' NonTypeTemplateParm {{.*}} 'size' 'unsigned int' +// DUMP: FunctionDecl {{.*}}run 'double ()' +// DUMP: TemplateArgument type 'double' +// DUMP: BuiltinType {{.*}}'double' +// DUMP: TemplateArgument integral 1 +// DUMP: OMPAllocateDeclAttr {{.*}}Implicit OMPNullMemAlloc +// DUMP: ConstantExpr {{.*}}'unsigned int' +// DUMP: value: Int 1 +// DUMP: SubstNonTypeTemplateParmExpr {{.*}}'unsigned int' +// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size +// DUMP: IntegerLiteral {{.*}}'unsigned int' 1 +// DUMP: OMPAllocateDecl {{.*}} +// DUMP: DeclRefExpr {{.*}}'double':'double' lvalue Var {{.*}} 'foo' 'double':'double' +// DUMP: OMPAlignClause {{.*}} +// DUMP: ConstantExpr {{.*}}'unsigned int' +// DUMP: value: Int 1 +// DUMP: SubstNonTypeTemplateParmExpr {{.*}}'unsigned int' +// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size +// DUMP: IntegerLiteral {{.*}}'unsigned int' 1 +// PRINT: #pragma omp allocate(foo) align(size) +// PRINT: #pragma omp allocate(foo) align(1U) +#endif // HEADER Index: clang/test/OpenMP/align_clause_messages.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/align_clause_messages.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 %s -verify + +int foobar() { + return 1; +} + +int main(int argc, char *argv[]) { + // expected-note@+1 {{declared here}} + int a; + // expected-note@+1 {{declared here}} + int b; + // expected-note@+1 {{declared here}} + int c; + double f; + int foo2[10]; + +// expected-error@+1 {{expected '(' after 'align'}} +#pragma omp allocate(a) align +// expected-error@+3 {{expected expression}} +// expected-error@+2 {{expected ')'}} +// expected-note@+1 {{to match this '('}} +#pragma omp allocate(a) align( +// expected-error@+1 {{expected expression}} +#pragma omp allocate(a) align() +// expected-error@+4 {{expected ')'}} +// expected-note@+3 {{to match this '('}} +// expected-error@+2 {{expression is not an integral constant expression}} +// expected-note@+1 {{read of non-const variable 'a' is not allowed in a constant expression}} +#pragma omp allocate(a) align(a +// expected-error@+2 {{expression is not an integral constant expression}} +// expected-note@+1 {{read of non-const variable 'b' is not allowed in a constant expression}} +#pragma omp allocate(a) align(b) +// expected-error@+2 {{expression is not an integral constant expression}} +// expected-note@+1 {{read of non-const variable 'c' is not allowed in a constant expression}} +#pragma omp allocate(a) align(c + 1) +// expected-error@+1 {{expected an OpenMP directive}} +#pragma omp align(2) allocate(a) +// expected-error@+1 {{directive '#pragma omp allocate' cannot contain more than one 'align' clause}} +#pragma omp allocate(a) align(2) align(4) +// expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}} +#pragma omp allocate(a) align(9) +// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}} +#pragma omp allocate(a) align(f) +} + +// Verify appropriate errors when using templates. +template +T run() { + T foo[size]; +// expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}} +#pragma omp allocate(foo) align(align) + return foo[0]; +} + +int template_test() { + double d; + // expected-note@+1 {{in instantiation of function template specialization 'run' requested here}} + d = run(); + return 0; +} Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -2315,6 +2315,10 @@ Visitor->AddStmt(C->getThreadID()); } +void OMPClauseEnqueue::VisitOMPAlignClause(const OMPAlignClause *C) { + Visitor->AddStmt(C->getAlignment()); +} + void OMPClauseEnqueue::VisitOMPUnifiedAddressClause( const OMPUnifiedAddressClause *) {} Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -1481,6 +1481,7 @@ CHECK_SIMPLE_CLAUSE(AppendArgs, OMPC_append_args) CHECK_SIMPLE_CLAUSE(MemoryOrder, OMPC_memory_order) CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind) +CHECK_SIMPLE_CLAUSE(Align, OMPC_align) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -363,6 +363,9 @@ let clangClass = "OMPFilterClause"; let flangClass = "ScalarIntExpr"; } +def OMPC_Align : Clause<"align"> { + let clangClass = "OMPAlignClause"; +} def OMPC_When: Clause<"when"> {} def OMPC_Bind : Clause<"bind"> { @@ -1539,7 +1542,8 @@ } def OMP_Allocate : Directive<"allocate"> { let allowedOnceClauses = [ - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_DeclareVariant : Directive<"declare variant"> {