Skip to content

Commit 91c68ec

Browse files
committed
Fix bad diagnostic when having a constexpr template function call in OmpSs-2 context
The old method to detect a return instr. inside task body does not work because Scope is used only in parsing, not in instantiation. To make it work properly we push a fake FunctionScopeInfo with a flag to detect we are in task body context. Also, since a lambda tries to propagate captures to outer ones we have to skip our fake FunctionScopeInfo. Closes llvm#96 llvm#97
1 parent 5442a60 commit 91c68ec

File tree

8 files changed

+186
-142
lines changed

8 files changed

+186
-142
lines changed

clang/include/clang/Sema/ScopeInfo.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,12 @@ class FunctionScopeInfo {
124124
/// True if current scope is for OpenMP declare reduction combiner.
125125
bool HasOMPDeclareReductionCombiner : 1;
126126

127-
/// True if current scope is for OmpSs declare reduction combiner.
127+
/// True if current scope is for OmpSs-2 declare reduction combiner.
128128
bool HasOSSDeclareReductionCombiner : 1;
129129

130+
/// True if current scope is for OmpSs-2 task/taskloop...
131+
bool HasOSSExecutableDirective : 1;
132+
130133
/// Whether there is a fallthrough statement in this function.
131134
bool HasFallthroughStmt : 1;
132135

@@ -371,6 +374,7 @@ class FunctionScopeInfo {
371374
HasBranchIntoScope(false), HasIndirectGoto(false),
372375
HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
373376
HasOSSDeclareReductionCombiner(false),
377+
HasOSSExecutableDirective(false),
374378
HasFallthroughStmt(false), HasPotentialAvailabilityViolations(false),
375379
ObjCShouldCallSuper(false), ObjCIsDesignatedInit(false),
376380
ObjCWarnForNoDesignatedInitChain(false), ObjCIsSecondaryInit(false),
@@ -422,6 +426,10 @@ class FunctionScopeInfo {
422426
HasOSSDeclareReductionCombiner = true;
423427
}
424428

429+
void setHasOSSExecutableDirective() {
430+
HasOSSExecutableDirective = true;
431+
}
432+
425433
void setHasFallthroughStmt() {
426434
HasFallthroughStmt = true;
427435
}

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10895,6 +10895,10 @@ class Sema final {
1089510895
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
1089610896

1089710897

10898+
// Used to push a fake FunctionScopeInfo
10899+
void ActOnOmpSsExecutableDirectiveStart();
10900+
// Used to pop the fake FunctionScopeInfo
10901+
void ActOnOmpSsExecutableDirectiveEnd();
1089810902
StmtResult ActOnOmpSsExecutableDirective(ArrayRef<OSSClause *> Clauses,
1089910903
OmpSsDirectiveKind Kind, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
1090010904

clang/lib/Parse/ParseOmpSs.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,9 @@ StmtResult Parser::ParseOmpSsDeclarativeOrExecutableDirective(
594594

595595
StmtResult AssociatedStmt;
596596
if (HasAssociatedStatement) {
597+
Actions.ActOnOmpSsExecutableDirectiveStart();
597598
AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement());
599+
Actions.ActOnOmpSsExecutableDirectiveEnd();
598600
}
599601

600602
Clauses = StackClauses.back();

clang/lib/Sema/ScopeInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void FunctionScopeInfo::Clear() {
2929
HasDroppedStmt = false;
3030
HasOMPDeclareReductionCombiner = false;
3131
HasOSSDeclareReductionCombiner = false;
32+
HasOSSExecutableDirective = false;
3233
HasFallthroughStmt = false;
3334
HasPotentialAvailabilityViolations = false;
3435
ObjCShouldCallSuper = false;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 139 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -17317,118 +17317,120 @@ bool Sema::tryCaptureVariable(
1731717317
}
1731817318

1731917319
FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex];
17320-
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
1732117320

17321+
if (!(getLangOpts().OmpSs && FSI->HasOSSExecutableDirective)) {
17322+
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
1732217323

17323-
// Check whether we've already captured it.
17324-
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
17325-
DeclRefType)) {
17326-
CSI->getCapture(Var).markUsed(BuildAndDiagnose);
17327-
break;
17328-
}
17329-
// If we are instantiating a generic lambda call operator body,
17330-
// we do not want to capture new variables. What was captured
17331-
// during either a lambdas transformation or initial parsing
17332-
// should be used.
17333-
if (isGenericLambdaCallOperatorSpecialization(DC)) {
17334-
if (BuildAndDiagnose) {
17335-
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
17336-
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
17337-
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
17338-
Diag(Var->getLocation(), diag::note_previous_decl)
17339-
<< Var->getDeclName();
17340-
Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
17341-
} else
17342-
diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
17324+
// Check whether we've already captured it.
17325+
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
17326+
DeclRefType)) {
17327+
CSI->getCapture(Var).markUsed(BuildAndDiagnose);
17328+
break;
17329+
}
17330+
// If we are instantiating a generic lambda call operator body,
17331+
// we do not want to capture new variables. What was captured
17332+
// during either a lambdas transformation or initial parsing
17333+
// should be used.
17334+
if (isGenericLambdaCallOperatorSpecialization(DC)) {
17335+
if (BuildAndDiagnose) {
17336+
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
17337+
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
17338+
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
17339+
Diag(Var->getLocation(), diag::note_previous_decl)
17340+
<< Var->getDeclName();
17341+
Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
17342+
} else
17343+
diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
17344+
}
17345+
return true;
17346+
}
17347+
17348+
// Try to capture variable-length arrays types.
17349+
if (Var->getType()->isVariablyModifiedType()) {
17350+
// We're going to walk down into the type and look for VLA
17351+
// expressions.
17352+
QualType QTy = Var->getType();
17353+
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
17354+
QTy = PVD->getOriginalType();
17355+
captureVariablyModifiedType(Context, QTy, CSI);
1734317356
}
17344-
return true;
17345-
}
1734617357

17347-
// Try to capture variable-length arrays types.
17348-
if (Var->getType()->isVariablyModifiedType()) {
17349-
// We're going to walk down into the type and look for VLA
17350-
// expressions.
17351-
QualType QTy = Var->getType();
17352-
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
17353-
QTy = PVD->getOriginalType();
17354-
captureVariablyModifiedType(Context, QTy, CSI);
17355-
}
17356-
17357-
if (getLangOpts().OpenMP) {
17358-
if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
17359-
// OpenMP private variables should not be captured in outer scope, so
17360-
// just break here. Similarly, global variables that are captured in a
17361-
// target region should not be captured outside the scope of the region.
17362-
if (RSI->CapRegionKind == CR_OpenMP) {
17363-
OpenMPClauseKind IsOpenMPPrivateDecl = isOpenMPPrivateDecl(
17364-
Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
17365-
// If the variable is private (i.e. not captured) and has variably
17366-
// modified type, we still need to capture the type for correct
17367-
// codegen in all regions, associated with the construct. Currently,
17368-
// it is captured in the innermost captured region only.
17369-
if (IsOpenMPPrivateDecl != OMPC_unknown &&
17370-
Var->getType()->isVariablyModifiedType()) {
17371-
QualType QTy = Var->getType();
17372-
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
17373-
QTy = PVD->getOriginalType();
17374-
for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel);
17375-
I < E; ++I) {
17376-
auto *OuterRSI = cast<CapturedRegionScopeInfo>(
17377-
FunctionScopes[FunctionScopesIndex - I]);
17378-
assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
17379-
"Wrong number of captured regions associated with the "
17380-
"OpenMP construct.");
17381-
captureVariablyModifiedType(Context, QTy, OuterRSI);
17358+
if (getLangOpts().OpenMP) {
17359+
if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
17360+
// OpenMP private variables should not be captured in outer scope, so
17361+
// just break here. Similarly, global variables that are captured in a
17362+
// target region should not be captured outside the scope of the region.
17363+
if (RSI->CapRegionKind == CR_OpenMP) {
17364+
OpenMPClauseKind IsOpenMPPrivateDecl = isOpenMPPrivateDecl(
17365+
Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
17366+
// If the variable is private (i.e. not captured) and has variably
17367+
// modified type, we still need to capture the type for correct
17368+
// codegen in all regions, associated with the construct. Currently,
17369+
// it is captured in the innermost captured region only.
17370+
if (IsOpenMPPrivateDecl != OMPC_unknown &&
17371+
Var->getType()->isVariablyModifiedType()) {
17372+
QualType QTy = Var->getType();
17373+
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
17374+
QTy = PVD->getOriginalType();
17375+
for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel);
17376+
I < E; ++I) {
17377+
auto *OuterRSI = cast<CapturedRegionScopeInfo>(
17378+
FunctionScopes[FunctionScopesIndex - I]);
17379+
assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
17380+
"Wrong number of captured regions associated with the "
17381+
"OpenMP construct.");
17382+
captureVariablyModifiedType(Context, QTy, OuterRSI);
17383+
}
17384+
}
17385+
bool IsTargetCap =
17386+
IsOpenMPPrivateDecl != OMPC_private &&
17387+
isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel,
17388+
RSI->OpenMPCaptureLevel);
17389+
// Do not capture global if it is not privatized in outer regions.
17390+
bool IsGlobalCap =
17391+
IsGlobal && isOpenMPGlobalCapturedDecl(Var, RSI->OpenMPLevel,
17392+
RSI->OpenMPCaptureLevel);
17393+
17394+
// When we detect target captures we are looking from inside the
17395+
// target region, therefore we need to propagate the capture from the
17396+
// enclosing region. Therefore, the capture is not initially nested.
17397+
if (IsTargetCap)
17398+
adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel);
17399+
17400+
if (IsTargetCap || IsOpenMPPrivateDecl == OMPC_private ||
17401+
(IsGlobal && !IsGlobalCap)) {
17402+
Nested = !IsTargetCap;
17403+
DeclRefType = DeclRefType.getUnqualifiedType();
17404+
CaptureType = Context.getLValueReferenceType(DeclRefType);
17405+
break;
1738217406
}
17383-
}
17384-
bool IsTargetCap =
17385-
IsOpenMPPrivateDecl != OMPC_private &&
17386-
isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel,
17387-
RSI->OpenMPCaptureLevel);
17388-
// Do not capture global if it is not privatized in outer regions.
17389-
bool IsGlobalCap =
17390-
IsGlobal && isOpenMPGlobalCapturedDecl(Var, RSI->OpenMPLevel,
17391-
RSI->OpenMPCaptureLevel);
17392-
17393-
// When we detect target captures we are looking from inside the
17394-
// target region, therefore we need to propagate the capture from the
17395-
// enclosing region. Therefore, the capture is not initially nested.
17396-
if (IsTargetCap)
17397-
adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel);
17398-
17399-
if (IsTargetCap || IsOpenMPPrivateDecl == OMPC_private ||
17400-
(IsGlobal && !IsGlobalCap)) {
17401-
Nested = !IsTargetCap;
17402-
DeclRefType = DeclRefType.getUnqualifiedType();
17403-
CaptureType = Context.getLValueReferenceType(DeclRefType);
17404-
break;
1740517407
}
1740617408
}
1740717409
}
17408-
}
17409-
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
17410-
// No capture-default, and this is not an explicit capture
17411-
// so cannot capture this variable.
17412-
if (BuildAndDiagnose) {
17413-
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
17414-
Diag(Var->getLocation(), diag::note_previous_decl)
17415-
<< Var->getDeclName();
17416-
if (cast<LambdaScopeInfo>(CSI)->Lambda)
17417-
Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getBeginLoc(),
17418-
diag::note_lambda_decl);
17419-
// FIXME: If we error out because an outer lambda can not implicitly
17420-
// capture a variable that an inner lambda explicitly captures, we
17421-
// should have the inner lambda do the explicit capture - because
17422-
// it makes for cleaner diagnostics later. This would purely be done
17423-
// so that the diagnostic does not misleadingly claim that a variable
17424-
// can not be captured by a lambda implicitly even though it is captured
17425-
// explicitly. Suggestion:
17426-
// - create const bool VariableCaptureWasInitiallyExplicit = Explicit
17427-
// at the function head
17428-
// - cache the StartingDeclContext - this must be a lambda
17429-
// - captureInLambda in the innermost lambda the variable.
17410+
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
17411+
// No capture-default, and this is not an explicit capture
17412+
// so cannot capture this variable.
17413+
if (BuildAndDiagnose) {
17414+
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
17415+
Diag(Var->getLocation(), diag::note_previous_decl)
17416+
<< Var->getDeclName();
17417+
if (cast<LambdaScopeInfo>(CSI)->Lambda)
17418+
Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getBeginLoc(),
17419+
diag::note_lambda_decl);
17420+
// FIXME: If we error out because an outer lambda can not implicitly
17421+
// capture a variable that an inner lambda explicitly captures, we
17422+
// should have the inner lambda do the explicit capture - because
17423+
// it makes for cleaner diagnostics later. This would purely be done
17424+
// so that the diagnostic does not misleadingly claim that a variable
17425+
// can not be captured by a lambda implicitly even though it is captured
17426+
// explicitly. Suggestion:
17427+
// - create const bool VariableCaptureWasInitiallyExplicit = Explicit
17428+
// at the function head
17429+
// - cache the StartingDeclContext - this must be a lambda
17430+
// - captureInLambda in the innermost lambda the variable.
17431+
}
17432+
return true;
1743017433
}
17431-
return true;
1743217434
}
1743317435

1743417436
FunctionScopesIndex--;
@@ -17444,40 +17446,42 @@ bool Sema::tryCaptureVariable(
1744417446
bool Invalid = false;
1744517447
for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
1744617448
++I) {
17447-
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
17448-
17449-
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
17450-
// certain types of variables (unnamed, variably modified types etc.)
17451-
// so check for eligibility.
17452-
if (!Invalid)
17453-
Invalid =
17454-
!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this);
17455-
17456-
// After encountering an error, if we're actually supposed to capture, keep
17457-
// capturing in nested contexts to suppress any follow-on diagnostics.
17458-
if (Invalid && !BuildAndDiagnose)
17459-
return true;
17449+
if (!(getLangOpts().OmpSs && FunctionScopes[I]->HasOSSExecutableDirective)) {
17450+
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
17451+
17452+
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
17453+
// certain types of variables (unnamed, variably modified types etc.)
17454+
// so check for eligibility.
17455+
if (!Invalid)
17456+
Invalid =
17457+
!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this);
17458+
17459+
// After encountering an error, if we're actually supposed to capture, keep
17460+
// capturing in nested contexts to suppress any follow-on diagnostics.
17461+
if (Invalid && !BuildAndDiagnose)
17462+
return true;
1746017463

17461-
if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
17462-
Invalid = !captureInBlock(BSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
17463-
DeclRefType, Nested, *this, Invalid);
17464-
Nested = true;
17465-
} else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
17466-
Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose,
17467-
CaptureType, DeclRefType, Nested,
17468-
*this, Invalid);
17469-
Nested = true;
17470-
} else {
17471-
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
17472-
Invalid =
17473-
!captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
17474-
DeclRefType, Nested, Kind, EllipsisLoc,
17475-
/*IsTopScope*/ I == N - 1, *this, Invalid);
17476-
Nested = true;
17477-
}
17464+
if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
17465+
Invalid = !captureInBlock(BSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
17466+
DeclRefType, Nested, *this, Invalid);
17467+
Nested = true;
17468+
} else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
17469+
Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose,
17470+
CaptureType, DeclRefType, Nested,
17471+
*this, Invalid);
17472+
Nested = true;
17473+
} else {
17474+
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
17475+
Invalid =
17476+
!captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
17477+
DeclRefType, Nested, Kind, EllipsisLoc,
17478+
/*IsTopScope*/ I == N - 1, *this, Invalid);
17479+
Nested = true;
17480+
}
1747817481

17479-
if (Invalid && !BuildAndDiagnose)
17480-
return true;
17482+
if (Invalid && !BuildAndDiagnose)
17483+
return true;
17484+
}
1748117485
}
1748217486
return Invalid;
1748317487
}

clang/lib/Sema/SemaOmpSs.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,21 @@ Sema::DeclGroupPtrTy Sema::ActOnOmpSsDeclareReductionDirectiveEnd(
12811281
return DeclReductions;
12821282
}
12831283

1284+
void Sema::ActOnOmpSsExecutableDirectiveStart() {
1285+
// Enter new function scope.
1286+
PushFunctionScope();
1287+
setFunctionHasBranchProtectedScope();
1288+
getCurFunction()->setHasOSSExecutableDirective();
1289+
PushExpressionEvaluationContext(
1290+
ExpressionEvaluationContext::PotentiallyEvaluated);
1291+
}
1292+
1293+
void Sema::ActOnOmpSsExecutableDirectiveEnd() {
1294+
DiscardCleanupsInEvaluationContext();
1295+
PopExpressionEvaluationContext();
1296+
1297+
PopFunctionScopeInfo();
1298+
}
12841299

12851300
StmtResult Sema::ActOnOmpSsExecutableDirective(ArrayRef<OSSClause *> Clauses,
12861301
OmpSsDirectiveKind Kind, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {

0 commit comments

Comments
 (0)