https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/203252
>From b925b2c3fa0f15b20898bd6456329eddfdb027ea Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Wed, 20 May 2026 05:48:13 -0700 Subject: [PATCH 1/6] [OpenMP] Prevent parser infinite loop on unimplemented clauses --- clang/lib/Basic/OpenMPKinds.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 9 ++ clang/lib/Sema/SemaOpenMP.cpp | 4 + .../OpenMP/unimplemented_clause_messages.cpp | 93 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 clang/test/OpenMP/unimplemented_clause_messages.cpp diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 287eb217ba458..675d86349c933 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -965,6 +965,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_simd: case OMPD_single: case OMPD_target_data: + case OMPD_taskgraph: case OMPD_taskgroup: case OMPD_stripe: // These directives (when standalone) use OMPD_unknown as the region, diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 45a47ec797f01..ba3d3113700ff 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2388,6 +2388,8 @@ StmtResult Parser::ParseOpenMPExecutableDirective( ImplicitClauseAllowed = false; Actions.OpenMP().StartOpenMPClause(CKind); HasImplicitClause = false; + SourceLocation ClauseLoc = Tok.getLocation(); + OMPClause *Clause = ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); SeenClauses[unsigned(CKind)] = true; @@ -2398,6 +2400,13 @@ StmtResult Parser::ParseOpenMPExecutableDirective( if (Tok.is(tok::comma)) ConsumeToken(); Actions.OpenMP().EndOpenMPClause(); + + // If ParseOpenMPClause returned without consuming any tokens, skip + // to end to avoid an infinite loop. + if (Tok.getLocation() == ClauseLoc) { + skipUntilPragmaOpenMPEnd(DKind); + break; + } } // End location of the directive. EndLoc = Tok.getLocation(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d6f6bc919a31b..76b40a5039180 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -6778,6 +6778,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_begin_declare_variant: case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); + case OMPD_taskgraph: + Diag(StartLoc, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(OMPD_taskgraph); + return StmtError(); case OMPD_unknown: default: llvm_unreachable("Unknown OpenMP directive"); diff --git a/clang/test/OpenMP/unimplemented_clause_messages.cpp b/clang/test/OpenMP/unimplemented_clause_messages.cpp new file mode 100644 index 0000000000000..172203ea5d040 --- /dev/null +++ b/clang/test/OpenMP/unimplemented_clause_messages.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp -fopenmp-version=60 %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp -fopenmp-version=51 %s +// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp-simd -fopenmp-version=60 %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp-simd -fopenmp-version=51 %s + + +void test_induction_basic() { + int i; + // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+2{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp51-error@+1{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} +#pragma omp parallel for induction(i) + for (i = 0; i < 10; ++i) + ; +} + +void test_apply() { + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) apply(intratile: unroll) + for (int i = 0; i < 10; ++i) + ; +} + +void test_empty_apply() { + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) apply() + for (int i = 0; i < 10; ++i) + ; +} + +void test_nested_apply() +{ + // omp60-error@+5{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + //omp51-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+2{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) \ + apply(intratile: unroll partial(2) apply(reverse)) + for (int i = 0; i < 100; ++i) + ; +} + +void test_induction_with_following_clause() { + int i; + // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' are ignored}} +#pragma omp parallel for induction(i) num_threads(4) + for (i = 0; i < 10; ++i) + ; +} + +class Point { + float x, y, m; + char color; + +}; + +void processPointsInLine() { + float separation; + // omp60-error@+4{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp60-warning@+3{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' are ignored}} +#pragma omp parallel for induction(step(Separation)) + for (int i = 0; i < 10; ++i) { + ; + } +} + +// Make sure test doesn't crash. +void test_tasgraph() +{ + // omp60-error@+2{{unexpected OpenMP directive '#pragma omp taskgraph'}} + // omp51-error@+1{{unexpected OpenMP directive '#pragma omp taskgraph'}} +#pragma omp taskgraph + for (int i = 0; i < 10; ++i) + ; +} + +void test_implemented_clause() { +#pragma omp tile sizes(10) + for (int i = 0; i < 10; ++i) + ; +} >From c5a58c9381dedf5ea55ecf048394bc704797c127 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 11 Jun 2026 05:16:12 -0700 Subject: [PATCH 2/6] [OpenMP] Pointer dereference collapse loop --- clang/lib/Sema/SemaOpenMP.cpp | 2 +- clang/test/OpenMP/collapse_extern_ref_crash.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 clang/test/OpenMP/collapse_extern_ref_crash.cpp diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 113c8f3cb3016..79a0c396f787e 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -8044,7 +8044,7 @@ class ForSubExprChecker : public DynamicRecursiveASTVisitor { VarDecl *V = VD->getPotentiallyDecomposedVarDecl(); if (V->getType()->isReferenceType()) { VarDecl *VD = V->getDefinition(); - if (VD->hasInit()) { + if (VD && VD->hasInit()) { Expr *I = VD->getInit(); DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(I); if (!DRE) diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp b/clang/test/OpenMP/collapse_extern_ref_crash.cpp new file mode 100644 index 0000000000000..4cc1a56115c73 --- /dev/null +++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s + +// Verify no crash when collapsing a loop nest where the induction variable +// is an extern reference type. PR/issue: null dereference in getInitLCDecl +// when VarDecl::getDefinition() returns nullptr. + +extern int &dim; +auto test() { + // expected-error@+1 {{expected-error for malformed collapse}} +#pragma omp parallel for collapse(2) + for (int i = 0; i < dim; ++i) { + for (i = 0; i < 10; i++) { + int dummy; + } + } +} >From 2f48e43b7c6378862830683d1e662759e5eac1ac Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 11 Jun 2026 05:43:06 -0700 Subject: [PATCH 3/6] Fixed LIT test --- clang/test/OpenMP/collapse_extern_ref_crash.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp b/clang/test/OpenMP/collapse_extern_ref_crash.cpp index 4cc1a56115c73..432fd91ef5852 100644 --- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp +++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp @@ -1,13 +1,14 @@ // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s +// expected-no-diagnostics + // Verify no crash when collapsing a loop nest where the induction variable // is an extern reference type. PR/issue: null dereference in getInitLCDecl // when VarDecl::getDefinition() returns nullptr. extern int &dim; auto test() { - // expected-error@+1 {{expected-error for malformed collapse}} #pragma omp parallel for collapse(2) for (int i = 0; i < dim; ++i) { for (i = 0; i < 10; i++) { >From c74662a207430405550212076e96b7e34c1d52b9 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 11 Jun 2026 12:02:49 -0700 Subject: [PATCH 4/6] Added diag --- .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/lib/Sema/SemaOpenMP.cpp | 46 +++++++++++++++---- .../test/OpenMP/collapse_extern_ref_crash.cpp | 31 ++++++++++--- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a3b575b7ee63a..9abbcb7fd2c3d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12255,6 +12255,8 @@ def err_omp_loop_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP for loop">; def err_omp_loop_bad_collapse_var : Error< "cannot use variable %1 in collapsed imperfectly-nested loop %select{init|condition|increment}0 statement">; +def err_omp_loop_var_reused_in_collapsed_loop : Error< + "loop iteration variable %0 cannot be reused in a nested loop of a collapsed loop nest">; def err_omp_simd_region_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP simd region">; def warn_omp_loop_64_bit_var : Warning< diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 79a0c396f787e..f94f5657a3998 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -8082,6 +8082,8 @@ class OpenMPIterationSpaceChecker { SourceLocation ConditionLoc; /// The set of variables declared within the (to be collapsed) loop nest. const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls; + /// The set of induction variables from outer collapsed loops. + const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars; /// A source location for referring to loop init later. SourceRange InitSrcRange; /// A source location for referring to condition later. @@ -8128,10 +8130,12 @@ class OpenMPIterationSpaceChecker { OpenMPIterationSpaceChecker( Sema &SemaRef, bool SupportsNonRectangular, DSAStackTy &Stack, SourceLocation DefaultLoc, - const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopDecls) + const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopDecls, + const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars) : SemaRef(SemaRef), SupportsNonRectangular(SupportsNonRectangular), Stack(Stack), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), - CollapsedLoopVarDecls(CollapsedLoopDecls) {} + CollapsedLoopVarDecls(CollapsedLoopDecls), + CollapsedLoopInductionVars(CollapsedLoopInductionVars) {} /// Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool checkAndSetInit(Stmt *S, bool EmitDiags = true); @@ -8473,7 +8477,17 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), EmitDiags); - return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags); + // Check if this variable is already used as an induction variable + // in an outer collapsed loop. + ValueDecl *LoopVar = DRE->getDecl(); + if (!CollapsedLoopInductionVars.empty() && + CollapsedLoopInductionVars.count(LoopVar) && EmitDiags) { + SemaRef.Diag(DRE->getLocation(), + diag::err_omp_loop_var_reused_in_collapsed_loop) + << LoopVar; + return true; + } + return setLCDeclAndLB(LoopVar, DRE, BO->getRHS(), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && @@ -9435,7 +9449,8 @@ void SemaOpenMP::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, DSAStack->loopStart(); llvm::SmallPtrSet<const Decl *, 1> EmptyDeclSet; OpenMPIterationSpaceChecker ISC(SemaRef, /*SupportsNonRectangular=*/true, - *DSAStack, ForLoc, EmptyDeclSet); + *DSAStack, ForLoc, EmptyDeclSet, + EmptyDeclSet); if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); @@ -9535,7 +9550,8 @@ static bool checkOpenMPIterationSpace( SemaOpenMP::VarsWithInheritedDSAType &VarsWithImplicitDSA, llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, - const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls) { + const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls, + const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars) { bool SupportsNonRectangular = !isOpenMPLoopTransformationDirective(DKind); // OpenMP [2.9.1, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block @@ -9576,7 +9592,8 @@ static bool checkOpenMPIterationSpace( OpenMPIterationSpaceChecker ISC(SemaRef, SupportsNonRectangular, DSA, For ? For->getForLoc() : CXXFor->getForLoc(), - CollapsedLoopVarDecls); + CollapsedLoopVarDecls, + CollapsedLoopInductionVars); // Check init. Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt(); @@ -9999,6 +10016,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, bool SupportsNonPerfectlyNested = (SemaRef.LangOpts.OpenMP >= 50) && !isOpenMPLoopTransformationDirective(DKind); llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopVarDecls; + llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopInductionVars; if (CollapseLoopCountExpr) { // Found 'collapse' clause - calculate collapse number. @@ -10047,14 +10065,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SupportsNonPerfectlyNested, NumLoops, [DKind, &SemaRef, &DSA, NumLoops, NestedLoopCount, CollapseLoopCountExpr, OrderedLoopCountExpr, &VarsWithImplicitDSA, - &IterSpaces, &Captures, - &CollapsedLoopVarDecls](unsigned Cnt, Stmt *CurStmt) { + &IterSpaces, &Captures, &CollapsedLoopVarDecls, + &CollapsedLoopInductionVars](unsigned Cnt, Stmt *CurStmt) { if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, NumLoops, CollapseLoopCountExpr, OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures, - CollapsedLoopVarDecls)) + CollapsedLoopVarDecls, CollapsedLoopInductionVars)) return true; + // Add the current loop's induction variable to the set so nested + // loops can check against it. + if (Cnt < NestedLoopCount && IterSpaces[Cnt].CounterVar) { + if (auto *DRE = + dyn_cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar)) { + if (ValueDecl *VD = DRE->getDecl()) { + CollapsedLoopInductionVars.insert(VD->getCanonicalDecl()); + } + } + } if (Cnt > 0 && Cnt >= NestedLoopCount && IterSpaces[Cnt].CounterVar) { // Handle initialization of captured loop iterator variables. diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp b/clang/test/OpenMP/collapse_extern_ref_crash.cpp index 432fd91ef5852..a8ffcae2fe262 100644 --- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp +++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp @@ -1,18 +1,37 @@ // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s -// expected-no-diagnostics +// This test verify two behaviors: +// 1. No crash when the loop bound is an extern reference (fixed null pointer +// dereference). +// 2. Proper diagnostic when a nested loop reuses the outer loop's induction +// variable -// Verify no crash when collapsing a loop nest where the induction variable -// is an extern reference type. PR/issue: null dereference in getInitLCDecl -// when VarDecl::getDefinition() returns nullptr. extern int &dim; -auto test() { +auto test1() { #pragma omp parallel for collapse(2) for (int i = 0; i < dim; ++i) { + // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} for (i = 0; i < 10; i++) { - int dummy; + } + } +} + +auto test2() { +#pragma omp parallel for collapse(2) + for (int i = 0; i < dim; ++i) { + for (int i = 0; i < 10; i++) { + } + } +} + +int dim_storage = 10; +int &dim = dim_storage; +auto test3() { +#pragma omp parallel for collapse(2) + for (int i = 0; i < dim; ++i) { + for (int j = 0; j < 10; j++) { } } } >From facedb15772056a092b487da0ed5b53bcaf6aa54 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 11 Jun 2026 14:03:33 -0700 Subject: [PATCH 5/6] Addressed review comments --- clang/lib/Sema/SemaOpenMP.cpp | 3 ++- clang/test/OpenMP/collapse_extern_ref_crash.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index f94f5657a3998..918717b45b0d3 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -8481,7 +8481,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { // in an outer collapsed loop. ValueDecl *LoopVar = DRE->getDecl(); if (!CollapsedLoopInductionVars.empty() && - CollapsedLoopInductionVars.count(LoopVar) && EmitDiags) { + CollapsedLoopInductionVars.count(LoopVar->getCanonicalDecl()) && + EmitDiags) { SemaRef.Diag(DRE->getLocation(), diag::err_omp_loop_var_reused_in_collapsed_loop) << LoopVar; diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp b/clang/test/OpenMP/collapse_extern_ref_crash.cpp index a8ffcae2fe262..52192e648044d 100644 --- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp +++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp @@ -14,6 +14,7 @@ auto test1() { for (int i = 0; i < dim; ++i) { // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} for (i = 0; i < 10; i++) { + int dummy; } } } @@ -22,6 +23,7 @@ auto test2() { #pragma omp parallel for collapse(2) for (int i = 0; i < dim; ++i) { for (int i = 0; i < 10; i++) { + int dummy; } } } @@ -32,6 +34,7 @@ auto test3() { #pragma omp parallel for collapse(2) for (int i = 0; i < dim; ++i) { for (int j = 0; j < 10; j++) { + int dummy; } } } >From e673f026fcba9afeadab5b7dacf65731c1ab3700 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Fri, 12 Jun 2026 08:22:11 -0700 Subject: [PATCH 6/6] Added CXXOperatorCallExpr/OO_Equal test --- clang/lib/Sema/SemaOpenMP.cpp | 13 +++++++- .../test/OpenMP/collapse_extern_ref_crash.cpp | 28 ++++++++++++++++ clang/test/OpenMP/t1.cpp | 32 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 clang/test/OpenMP/t1.cpp diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 918717b45b0d3..d3c66072239fa 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -8523,7 +8523,18 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), EmitDiags); - return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags); + // Check if this variable is already used as an induction variable + // in an outer collapsed loop. + ValueDecl *LoopVar = DRE->getDecl(); + if (!CollapsedLoopInductionVars.empty() && + CollapsedLoopInductionVars.count(LoopVar->getCanonicalDecl()) && + EmitDiags) { + SemaRef.Diag(DRE->getLocation(), + diag::err_omp_loop_var_reused_in_collapsed_loop) + << LoopVar; + return true; + } + return setLCDeclAndLB(LoopVar, DRE, CE->getArg(1), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp b/clang/test/OpenMP/collapse_extern_ref_crash.cpp index 52192e648044d..8995efc43e59f 100644 --- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp +++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp @@ -38,3 +38,31 @@ auto test3() { } } } + +struct Iterator { + int value; + Iterator& operator=(int v) { value = v; return *this; } + bool operator<(int n) const { return value < n; } + Iterator& operator++() { ++value; return *this; } +}; + +Iterator i; +auto test4() { +#pragma omp parallel for collapse(2) + for (i = 0; i < dim; ++i) { + // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} + for (i = 0; i < 10; ++i) { + int dummy; + } + } +} + +auto test5() { +#pragma omp parallel for collapse(2) + for (i = 0; i < dim; ++i) { + // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} + for (i = 0; i < 10; ++i) { + int dummy; + } + } +} diff --git a/clang/test/OpenMP/t1.cpp b/clang/test/OpenMP/t1.cpp new file mode 100644 index 0000000000000..c50f878d52e7a --- /dev/null +++ b/clang/test/OpenMP/t1.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s + +// Test 4: Reuse with overloaded operator= (should error) +struct Iterator { + int value; + Iterator& operator=(int v) { value = v; return *this; } + bool operator<(int n) const { return value < n; } + Iterator& operator++() { ++value; return *this; } +}; + +Iterator i; +extern int &dim; +auto test4() { + #pragma omp parallel for collapse(2) + for (i = 0; i < dim; ++i) { + // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} + for (i = 0; i < 10; ++i) { + int dummy; + } + } + } + +auto test5() { +#pragma omp parallel for collapse(2) + for (i = 0; i < dim; ++i) { + // expected-error@+1{{loop iteration variable 'i' cannot be reused in a nested loop of a collapsed loop nest}} + for (i = 0; i < 10; ++i) { + int dummy; + } + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
