Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -886,9 +886,9 @@ /// DeclRefExprBits.HasTemplateKWAndArgsInfo: /// Specifies when this declaration reference expression has an explicit /// C++ template keyword and/or template argument list. -/// DeclRefExprBits.RefersToEnclosingLocal +/// DeclRefExprBits.RefersToCapturedVariable /// Specifies when this declaration reference expression (validly) -/// refers to a local variable from a different function. +/// refers to a captured variable. class DeclRefExpr : public Expr { /// \brief The declaration that we are referencing. ValueDecl *D; @@ -933,7 +933,7 @@ DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - ValueDecl *D, bool refersToEnclosingLocal, + ValueDecl *D, bool RefersToCapturedVariable, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, @@ -948,7 +948,7 @@ void computeDependence(const ASTContext &C); public: - DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T, + DeclRefExpr(ValueDecl *D, bool RefersToCapturedVariable, QualType T, ExprValueKind VK, SourceLocation L, const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), @@ -957,22 +957,22 @@ DeclRefExprBits.HasTemplateKWAndArgsInfo = 0; DeclRefExprBits.HasFoundDecl = 0; DeclRefExprBits.HadMultipleCandidates = 0; - DeclRefExprBits.RefersToEnclosingLocal = refersToEnclosingLocal; + DeclRefExprBits.RefersToCapturedVariable = RefersToCapturedVariable; computeDependence(D->getASTContext()); } static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal, - SourceLocation NameLoc, QualType T, ExprValueKind VK, - NamedDecl *FoundD = nullptr, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToCapturedVariable, SourceLocation NameLoc, QualType T, + ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal, - const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, - NamedDecl *FoundD = nullptr, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToCapturedVariable, const DeclarationNameInfo &NameInfo, + QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); /// \brief Construct an empty declaration reference expression. @@ -1144,10 +1144,9 @@ DeclRefExprBits.HadMultipleCandidates = V; } - /// Does this DeclRefExpr refer to a local declaration from an - /// enclosing function scope? - bool refersToEnclosingLocal() const { - return DeclRefExprBits.RefersToEnclosingLocal; + /// Does this DeclRefExpr refer to a captured variable? + bool refersToCapturedVariable() const { + return DeclRefExprBits.RefersToCapturedVariable; } static bool classof(const Stmt *T) { Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -212,7 +212,7 @@ unsigned HasTemplateKWAndArgsInfo : 1; unsigned HasFoundDecl : 1; unsigned HadMultipleCandidates : 1; - unsigned RefersToEnclosingLocal : 1; + unsigned RefersToCapturedVariable : 1; }; class CastExprBitfields { Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3427,6 +3427,9 @@ TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); + /// \brief Checks if the variable must be captured. + bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); + /// \brief Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); @@ -7453,6 +7456,10 @@ void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind); + /// \brief Checks if the specified variable is used in one of the private + /// clauses in OpenMP constructs. + bool IsOpenMPCapturedVar(VarDecl *VD); + public: ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -4375,7 +4375,7 @@ Importer.Import(E->getQualifierLoc()), Importer.Import(E->getTemplateKeywordLoc()), ToD, - E->refersToEnclosingLocal(), + E->refersToCapturedVariable(), Importer.Import(E->getLocation()), T, E->getValueKind(), FoundD, Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -322,7 +322,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - ValueDecl *D, bool RefersToEnclosingLocal, + ValueDecl *D, bool RefersToCapturedVariable, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, @@ -343,7 +343,7 @@ getInternalFoundDecl() = FoundD; DeclRefExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0; - DeclRefExprBits.RefersToEnclosingLocal = RefersToEnclosingLocal; + DeclRefExprBits.RefersToCapturedVariable = RefersToCapturedVariable; if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; @@ -367,14 +367,14 @@ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, - bool RefersToEnclosingLocal, + bool RefersToCapturedVariable, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { return Create(Context, QualifierLoc, TemplateKWLoc, D, - RefersToEnclosingLocal, + RefersToCapturedVariable, DeclarationNameInfo(D->getDeclName(), NameLoc), T, VK, FoundD, TemplateArgs); } @@ -383,7 +383,7 @@ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, - bool RefersToEnclosingLocal, + bool RefersToCapturedVariable, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, @@ -405,7 +405,7 @@ void *Mem = Context.Allocate(Size, llvm::alignOf()); return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D, - RefersToEnclosingLocal, + RefersToCapturedVariable, NameInfo, FoundD, TemplateArgs, T, VK); } Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -115,7 +115,7 @@ /* QualifierLoc = */ NestedNameSpecifierLoc(), /* TemplateKWLoc = */ SourceLocation(), /* D = */ const_cast(D), - /* isEnclosingLocal = */ false, + /* RefersToCapturedVariable = */ false, /* NameLoc = */ SourceLocation(), /* T = */ D->getType(), /* VK = */ VK_LValue); Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -1897,6 +1897,23 @@ QualType T = E->getType(); if (const auto *VD = dyn_cast(ND)) { + // Check for captured variables. + if (E->refersToCapturedVariable()) { + if (auto *FD = LambdaCaptureFields.lookup(VD)) + return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); + else if (CapturedStmtInfo) { + if (auto *FD = CapturedStmtInfo->lookup(VD)) { + if (auto *V = LocalDeclMap.lookup(VD)) + return MakeAddrLValue(V, T, Alignment); + else + return EmitCapturedFieldLValue(*this, FD, + CapturedStmtInfo->getContextValue()); + } + } else if (auto BD = dyn_cast_or_null(CurCodeDecl)) + if (BD->capturesVariable(VD)) + return MakeAddrLValue( + GetAddrOfBlockDecl(VD, VD->hasAttr()), T, Alignment); + } // Global Named registers access via intrinsics only if (VD->getStorageClass() == SC_Register && VD->hasAttr() && !VD->isLocalVarDecl()) @@ -1947,21 +1964,6 @@ *this, VD, T, V, getTypes().ConvertTypeForMem(VD->getType()), Alignment, E->getExprLoc()); - // Use special handling for lambdas. - if (!V) { - if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) { - return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); - } else if (CapturedStmtInfo) { - if (const FieldDecl *FD = CapturedStmtInfo->lookup(VD)) - return EmitCapturedFieldLValue(*this, FD, - CapturedStmtInfo->getContextValue()); - } - - assert(isa(CurCodeDecl) && E->refersToEnclosingLocal()); - return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable), - T, Alignment); - } - assert(V && "DeclRefExpr not entered in LocalDeclMap?"); if (isBlockVariable) Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -614,7 +614,6 @@ addPrivate(const VarDecl *LocalVD, const std::function &PrivateGen) { assert(PerformCleanup && "adding private to dead scope"); - assert(LocalVD->isLocalVarDecl() && "privatizing non-local variable"); if (SavedLocals.count(LocalVD) > 0) return false; SavedLocals[LocalVD] = CGF.LocalDeclMap.lookup(LocalVD); CGF.LocalDeclMap.erase(LocalVD); Index: lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -4564,7 +4564,7 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DRE->refersToCapturedVariable()) { // FIXME: Handle enums. if (!isa(DRE->getDecl())) BlockDeclRefs.push_back(DRE); @@ -4595,7 +4595,7 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DRE->refersToCapturedVariable()) { if (!isa(DRE->getDecl()) && !InnerContexts.count(DRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(DRE); @@ -4776,7 +4776,7 @@ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR // for each DeclRefExp where BYREFVAR is name of the variable. ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); + bool isArrow = DeclRefExp->refersToCapturedVariable(); FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), Index: lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteObjC.cpp +++ lib/Frontend/Rewrite/RewriteObjC.cpp @@ -3672,7 +3672,7 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DRE->refersToCapturedVariable()) { // FIXME: Handle enums. if (!isa(DRE->getDecl())) BlockDeclRefs.push_back(DRE); @@ -3703,7 +3703,7 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DRE->refersToCapturedVariable()) { if (!isa(DRE->getDecl()) && !InnerContexts.count(DRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(DRE); @@ -3865,7 +3865,7 @@ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR // for each DeclRefExp where BYREFVAR is name of the variable. ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); + bool isArrow = DeclRefExp->refersToCapturedVariable(); FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -4858,7 +4858,7 @@ DeclRefExpr *DR = cast(E); // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingLocal()) + if (DR->refersToCapturedVariable()) return nullptr; if (VarDecl *V = dyn_cast(DR->getDecl())) @@ -5025,7 +5025,7 @@ DeclRefExpr *DR = cast(E); // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingLocal()) + if (DR->refersToCapturedVariable()) return nullptr; if (VarDecl *V = dyn_cast(DR->getDecl())) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10159,7 +10159,7 @@ QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, - /*RefersToEnclosingLocal*/true, C.getLocation(), + /*RefersToCapturedVariable*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), CaptureType, /*Expr*/ nullptr); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1601,29 +1601,29 @@ } } - bool refersToEnclosingScope = - (CurContext != D->getDeclContext() && - D->getDeclContext()->isFunctionOrMethod()) || - (isa(D) && - cast(D)->isInitCapture()); + bool RefersToCapturedVariable = + (CurContext != D->getDeclContext() && + D->getDeclContext()->isFunctionOrMethod()) || + (isa(D) && + !NeedToCaptureVariable(cast(D), NameInfo.getLoc())); DeclRefExpr *E; if (isa(D)) { VarTemplateSpecializationDecl *VarSpec = cast(D); - E = DeclRefExpr::Create( - Context, - SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), - VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope, - NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs); + E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context) + : NestedNameSpecifierLoc(), + VarSpec->getTemplateKeywordLoc(), D, + RefersToCapturedVariable, NameInfo.getLoc(), Ty, VK, + FoundD, TemplateArgs); } else { assert(!TemplateArgs && "No template arguments for non-variable" " template specialization references"); - E = DeclRefExpr::Create( - Context, - SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), - SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD); + E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context) + : NestedNameSpecifierLoc(), + SourceLocation(), D, RefersToCapturedVariable, + NameInfo, Ty, VK, FoundD); } MarkDeclRefReferenced(E); @@ -8462,7 +8462,7 @@ // Must be a reference to a declaration from an enclosing scope. DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return NCCK_None; - if (!DRE->refersToEnclosingLocal()) return NCCK_None; + if (!DRE->refersToCapturedVariable()) return NCCK_None; // The declaration must be a variable which is not declared 'const'. VarDecl *var = dyn_cast(DRE->getDecl()); @@ -11654,7 +11654,7 @@ const bool Diagnose, Sema &S) { if (isa(DC) || isa(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - else { + else if (Var->hasLocalStorage()) { if (Diagnose) diagnoseUncapturableValueReference(S, Loc, Var, DC); } @@ -11782,10 +11782,10 @@ // According to the blocks spec, the capture of a variable from // the stack requires a const copy constructor. This is not true // of the copy/move done to move a __block variable to the heap. - Expr *DeclRef = new (S.Context) DeclRefExpr(Var, Nested, - DeclRefType.withConst(), - VK_LValue, Loc); - + Expr *DeclRef = new (S.Context) + DeclRefExpr(Var, /*RefersToCapturedVariable=*/true, + DeclRefType.withConst(), VK_LValue, Loc); + ExprResult Result = S.PerformCopyInitialization( InitializedEntity::InitializeBlock(Var->getLocation(), @@ -11822,7 +11822,7 @@ const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, - const bool RefersToEnclosingLocal, + const bool RefersToCapturedVariable, Sema &S) { // By default, capture variables by reference. @@ -11843,16 +11843,16 @@ Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); - - CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, - DeclRefType, VK_LValue, Loc); + + CopyExpr = new (S.Context) DeclRefExpr( + Var, /*RefersToCapturedVariable=*/true, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); Var->markUsed(S.Context); } // Actually capture the variable. if (BuildAndDiagnose) - RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToEnclosingLocal, Loc, + RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc, SourceLocation(), CaptureType, CopyExpr); @@ -11865,8 +11865,7 @@ LambdaScopeInfo *LSI, VarDecl *Var, QualType FieldType, QualType DeclRefType, - SourceLocation Loc, - bool RefersToEnclosingLocal) { + SourceLocation Loc) { CXXRecordDecl *Lambda = LSI->Lambda; // Build the non-static data member. @@ -11895,8 +11894,8 @@ // C++ [expr.prim.labda]p12: // An entity captured by a lambda-expression is odr-used (3.2) in // the scope containing the lambda-expression. - Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, - DeclRefType, VK_LValue, Loc); + Expr *Ref = new (S.Context) DeclRefExpr( + Var, /*RefersToCapturedVariable=*/true, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); Var->markUsed(S.Context); @@ -11989,7 +11988,7 @@ const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, - const bool RefersToEnclosingLocal, + const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, SourceLocation EllipsisLoc, const bool IsTopScope, @@ -12061,9 +12060,8 @@ // Capture this variable in the lambda. Expr *CopyExpr = nullptr; if (BuildAndDiagnose) { - ExprResult Result = addAsFieldToClosureType(S, LSI, Var, - CaptureType, DeclRefType, Loc, - RefersToEnclosingLocal); + ExprResult Result = + addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc); if (!Result.isInvalid()) CopyExpr = Result.get(); } @@ -12084,7 +12082,7 @@ // Add the capture. if (BuildAndDiagnose) - LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToEnclosingLocal, + LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable, Loc, EllipsisLoc, CaptureType, CopyExpr); return true; @@ -12115,7 +12113,10 @@ // If the variable is declared in the current context (and is not an // init-capture), there is no need to capture it. if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true; - if (!Var->hasLocalStorage()) return true; + // Capture global variables if it is required to use private copy of this + // variable. + if (!Var->hasLocalStorage() && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var))) + return true; // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -12136,8 +12137,14 @@ ExprLoc, BuildAndDiagnose, *this); - if (!ParentDC) return true; - + if (!ParentDC) { + if (!Var->hasLocalStorage()) { + FunctionScopesIndex = MaxFunctionScopesIndex - 1; + break; + } + return true; + } + FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast(FSI); @@ -12363,6 +12370,14 @@ DeclRefType, nullptr); } +bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { + QualType CaptureType; + QualType DeclRefType; + return tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), + /*BuildAndDiagnose=*/false, CaptureType, + DeclRefType, nullptr); +} + QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -551,6 +551,18 @@ #define DSAStack static_cast(VarDataSharingAttributesStack) +bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { + if (LangOpts.OpenMP && DSAStack->getCurrentDirective() != OMPD_unknown) { + auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) + return true; + DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), + /*FromParent=*/false); + return DVarPrivate.CKind != OMPC_unknown; + } + return false; +} + void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -4016,7 +4028,7 @@ auto VDPrivateRefExpr = DeclRefExpr::Create( Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), /*TemplateKWLoc*/ SourceLocation(), VDPrivate, - /*isEnclosingLocal*/ false, /*NameLoc*/ SourceLocation(), DE->getType(), + /*RefersToCapturedVariable*/ false, /*NameLoc*/ SourceLocation(), DE->getType(), /*VK*/ VK_LValue); DSAStack->addDSA(VD, DE, OMPC_private); @@ -4236,10 +4248,9 @@ VD->getTypeSourceInfo(), /*S*/ SC_Auto); CurContext->addHiddenDecl(VDInit); VDInitRefExpr = DeclRefExpr::Create( - Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), - /*TemplateKWLoc*/ SourceLocation(), VDInit, - /*isEnclosingLocal*/ false, ELoc, Type, - /*VK*/ VK_LValue); + Context, NestedNameSpecifierLoc(), SourceLocation(), VDInit, + /*RefersToCapturedVariable=*/true, ELoc, Type, + /*VK=*/VK_LValue); VDInit->setIsUsed(); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit); @@ -4252,8 +4263,14 @@ else VDPrivate->setInit(Result.getAs()); } else { - AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(), - /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + AddInitializerToDecl( + VDPrivate, DefaultLvalueConversion( + DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), DE->getDecl(), + /*RefersToCapturedVariable=*/true, + DE->getExprLoc(), DE->getType(), + /*VK=*/VK_LValue)).get(), + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { @@ -4264,10 +4281,9 @@ } CurContext->addDecl(VDPrivate); auto VDPrivateRefExpr = DeclRefExpr::Create( - Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), - /*TemplateKWLoc*/ SourceLocation(), VDPrivate, - /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(), - /*VK*/ VK_LValue); + Context, NestedNameSpecifierLoc(), SourceLocation(), VDPrivate, + /*RefersToCapturedVariable=*/false, DE->getLocStart(), DE->getType(), + /*VK=*/VK_LValue); DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); PrivateCopies.push_back(VDPrivateRefExpr); Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -2447,7 +2447,7 @@ // - in a return statement in a function [where] ... // ... the expression is the name of a non-volatile automatic object ... DeclRefExpr *DR = dyn_cast(E->IgnoreParens()); - if (!DR || DR->refersToEnclosingLocal()) + if (!DR || DR->refersToCapturedVariable()) return nullptr; VarDecl *VD = dyn_cast(DR->getDecl()); if (!VD) Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -433,7 +433,7 @@ E->DeclRefExprBits.HasFoundDecl = Record[Idx++]; E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record[Idx++]; E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++]; - E->DeclRefExprBits.RefersToEnclosingLocal = Record[Idx++]; + E->DeclRefExprBits.RefersToCapturedVariable = Record[Idx++]; unsigned NumTemplateArgs = 0; if (E->hasTemplateKWAndArgsInfo()) NumTemplateArgs = Record[Idx++]; Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -1842,7 +1842,8 @@ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //RefersToEnclosingLocal + Abv->Add( + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // RefersToCapturedVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location DeclRefExprAbbrev = Stream.EmitAbbrev(Abv); Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -344,7 +344,7 @@ Record.push_back(E->getDecl() != E->getFoundDecl()); Record.push_back(E->hasTemplateKWAndArgsInfo()); Record.push_back(E->hadMultipleCandidates()); - Record.push_back(E->refersToEnclosingLocal()); + Record.push_back(E->refersToCapturedVariable()); if (E->hasTemplateKWAndArgsInfo()) { unsigned NumTemplateArgs = E->getNumTemplateArgs(); Index: test/OpenMP/parallel_firstprivate_codegen.cpp =================================================================== --- test/OpenMP/parallel_firstprivate_codegen.cpp +++ test/OpenMP/parallel_firstprivate_codegen.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -12,7 +14,7 @@ ~St() {} }; -volatile int g; +volatile int g = 1212; template struct S { @@ -47,6 +49,83 @@ } int main() { +#ifdef LAMBDA + // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, + // LAMBDA-LABEL: @main + // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + [&]() { + // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( + // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel firstprivate(g) + { + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // LAMBDA: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]] + // LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]] + // LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // LAMBDA: call void @__kmpc_barrier( + g = 1; + // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] + // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) + [&]() { + // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]]) + // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]], + g = 2; + // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]] + // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]] + // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + }(); + } + }(); + return 0; +#elif defined(BLOCKS) + // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, + // BLOCKS-LABEL: @main + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* + // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel firstprivate(g) + { + // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // BLOCKS: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]] + // BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]] + // BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]] + // BLOCKS: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS: call void @__kmpc_barrier( + g = 1; + // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define {{.+}} void {{@.+}}(i8* + g = 2; + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: ret + }(); + } + }(); + return 0; +#else S test; int t_var = 0; int vec[] = {1, 2}; @@ -58,6 +137,7 @@ s_arr[0] = var; } return tmain(); +#endif } // CHECK: define {{.*}}i{{[0-9]+}} @main() Index: test/OpenMP/parallel_private_codegen.cpp =================================================================== --- test/OpenMP/parallel_private_codegen.cpp +++ test/OpenMP/parallel_private_codegen.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -14,6 +16,8 @@ ~S() {} }; +volatile int g = 1212; + // CHECK: [[S_FLOAT_TY:%.+]] = type { float } // CHECK: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } @@ -22,7 +26,7 @@ template T tmain() { S test; - T t_var; + T t_var = T(); T vec[] = {1, 2}; S s_arr[] = {1, 2}; S var(3); @@ -35,8 +39,75 @@ } int main() { +#ifdef LAMBDA + // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, + // LAMBDA-LABEL: @main + // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + [&]() { + // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( + // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel private(g) + { + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // LAMBDA: call void @__kmpc_barrier( + g = 1; + // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] + // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) + [&]() { + // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]]) + // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]], + g = 2; + // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]] + // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]] + // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + }(); + } + }(); + return 0; +#elif defined(BLOCKS) + // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, + // BLOCKS-LABEL: @main + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* + // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel private(g) + { + // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // BLOCKS: call void @__kmpc_barrier( + g = 1; + // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define {{.+}} void {{@.+}}(i8* + g = 2; + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: ret + }(); + } + }(); + return 0; +#else S test; - int t_var; + int t_var = 0; int vec[] = {1, 2}; S s_arr[] = {1, 2}; S var(3); @@ -46,6 +117,7 @@ s_arr[0] = var; } return tmain(); +#endif } // CHECK: define i{{[0-9]+}} @main()