Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2457,6 +2457,9 @@ template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: include/clang/AST/OpenMPClause.h =================================================================== --- include/clang/AST/OpenMPClause.h +++ include/clang/AST/OpenMPClause.h @@ -138,7 +138,7 @@ return ArrayRef( reinterpret_cast( reinterpret_cast(this) + - llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf())), + llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf())), NumVars); } }; @@ -926,6 +926,7 @@ /// with the variables 'a' and 'b'. /// class OMPPrivateClause : public OMPVarListClause { + friend class OMPClauseReader; /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. @@ -947,6 +948,20 @@ SourceLocation(), SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param InitVL List of references. + void setPrivateCopies(ArrayRef VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef getPrivateCopies() { + return MutableArrayRef(varlist_end(), varlist_size()); + } + ArrayRef getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + public: /// \brief Creates clause with a list of variables \a VL. /// @@ -955,10 +970,12 @@ /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param VL List of references to the variables. + /// \param PrivateVL List of references to private copies with initializers. /// static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef VL); + SourceLocation EndLoc, ArrayRef VL, + ArrayRef PrivateVL); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -966,6 +983,21 @@ /// static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + typedef MutableArrayRef::iterator private_copies_iterator; + typedef ArrayRef::iterator private_copies_const_iterator; + typedef llvm::iterator_range private_copies_range; + typedef llvm::iterator_range + private_copies_const_range; + + private_copies_range private_copies() { + return private_copies_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + private_copies_const_range private_copies() const { + return private_copies_const_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + StmtRange children() { return StmtRange(reinterpret_cast(varlist_begin()), reinterpret_cast(varlist_end())); Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2479,6 +2479,9 @@ template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: lib/AST/Stmt.cpp =================================================================== --- lib/AST/Stmt.cpp +++ lib/AST/Stmt.cpp @@ -1122,17 +1122,24 @@ llvm_unreachable("unknown OMPClause"); } -OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { +void OMPPrivateClause::setPrivateCopies(ArrayRef VL) { + assert(VL.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), varlist_end()); +} + +OMPPrivateClause * +OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PrivateVL) { + // Allocate space for private variables and initializer expressions. void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf()) + - sizeof(Expr *) * VL.size()); - OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, - EndLoc, VL.size()); + 2 * sizeof(Expr *) * VL.size()); + OMPPrivateClause *Clause = + new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setPrivateCopies(PrivateVL); return Clause; } @@ -1140,7 +1147,7 @@ unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf()) + - sizeof(Expr *) * N); + 2 * sizeof(Expr *) * N); return new (Mem) OMPPrivateClause(N); } Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -322,12 +322,16 @@ template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { - for (auto *I : Node->varlists()) - Profiler->VisitStmt(I); + for (auto *E : Node->varlists()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->private_copies()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPFirstprivateClause( const OMPFirstprivateClause *C) { Index: lib/CodeGen/CGOpenMPRuntime.h =================================================================== --- lib/CodeGen/CGOpenMPRuntime.h +++ lib/CodeGen/CGOpenMPRuntime.h @@ -68,7 +68,9 @@ // microtask, ...); OMPRTL__kmpc_fork_call, // Call to kmp_int32 kmpc_global_thread_num(ident_t *loc); - OMPRTL__kmpc_global_thread_num + OMPRTL__kmpc_global_thread_num, + // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); + OMPRTL__kmpc_barrier }; private: Index: lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntime.cpp +++ lib/CodeGen/CGOpenMPRuntime.cpp @@ -50,11 +50,10 @@ DefaultOpenMPPSource = llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy); } - llvm::GlobalVariable *DefaultOpenMPLocation = cast( - CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr")); + auto DefaultOpenMPLocation = new llvm::GlobalVariable( + CGM.getModule(), IdentTy, /*isConstant*/ true, + llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr); DefaultOpenMPLocation->setUnnamedAddr(true); - DefaultOpenMPLocation->setConstant(true); - DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage); llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true); llvm::Constant *Values[] = {Zero, @@ -62,6 +61,7 @@ Zero, Zero, DefaultOpenMPPSource}; llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values); DefaultOpenMPLocation->setInitializer(Init); + OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation; return DefaultOpenMPLocation; } return Entry; @@ -196,6 +196,14 @@ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num"); break; } + case OMPRTL__kmpc_barrier: { + // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier"); + break; + } } return RTLFn; } Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -23,6 +23,57 @@ // OpenMP Directive Emission //===----------------------------------------------------------------------===// +void CodeGenFunction::EmitOMPPrivateClause( + const OMPExecutableDirective &D, + CodeGenFunction::OuterDeclMapTy &OuterDeclMap) { + auto PrivateFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_private; + }; + for (OMPExecutableDirective::filtered_clause_iterator + I(D.clauses(), PrivateFilter); I; ++I) { + auto *C = cast(*I); + auto IRef = C->varlist_begin(); + for (auto IInit : C->private_copies()) { + auto VD = cast(cast(IInit)->getDecl()); + EmitDecl(*VD); + OuterDeclMap[cast(*IRef)->getDecl()] = GetAddrOfLocalVar(VD); + ++IRef; + } + } +} + +CodeGenFunction::CGOpenMPRegionInfo::~CGOpenMPRegionInfo() {} + +void CodeGenFunction::CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, + Stmt *S) { + OuterDeclMapTy OuterDeclMap; + CGF.EmitOMPPrivateClause(Directive, OuterDeclMap); + if (!OuterDeclMap.empty()) { + // Emit implicit barrier to synchronize threads and avoid data races. + // Build call __kmpc_barrier(loc, gtid) + auto Flags = static_cast( + CGOpenMPRuntime::OMP_IDENT_KMPC | + CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL); + llvm::Value *Args[] = {CGF.CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation( + CGF, Directive.getLocStart(), Flags), + CGF.CGM.getOpenMPRuntime().GetOpenMPGlobalThreadNum( + CGF, Directive.getLocStart())}; + auto RTLFn = CGF.CGM.getOpenMPRuntime().CreateRuntimeFunction( + CGOpenMPRuntime::OMPRTL__kmpc_barrier); + CGF.EmitRuntimeCall(RTLFn, Args); + // Remap captured variables to use their private copies in the outlined + // function. + for (auto I : OuterDeclMap) { + CGF.LocalDeclMap[I.first] = I.second; + } + } + CGCapturedStmtInfo::EmitBody(CGF, S); + // Clear mappings of captured private variables. + for (auto I : OuterDeclMap) { + CGF.LocalDeclMap.erase(I.first); + } +} + void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { const CapturedStmt *CS = cast(S.getAssociatedStmt()); llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS); @@ -30,7 +81,7 @@ llvm::Value *OutlinedFn; { CodeGenFunction CGF(CGM, true); - CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind()); + CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin()); CGF.CapturedStmtInfo = &CGInfo; OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -238,6 +238,40 @@ /// \brief Captured 'this' type. FieldDecl *CXXThisFieldDecl; }; + + /// \brief API for captured statement code generation in OpenMP constructs. + class CGOpenMPRegionInfo : public CGCapturedStmtInfo { + public: + CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S, + const VarDecl *GTidVar) + : CGCapturedStmtInfo(S, CR_OpenMP), GTidVar(GTidVar), Directive(D) {} + + virtual ~CGOpenMPRegionInfo() override; + + /// \brief Gets a variable or parameter for storing global thread id + /// inside OpenMP construct. + const VarDecl *getGTidVariable() const { return GTidVar; } + + static bool classof(const CGCapturedStmtInfo *Info) { + return Info->getKind() == CR_OpenMP; + } + + /// \brief Emit the captured statement body. + virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override; + + /// \brief Get the name of the capture helper. + virtual StringRef getHelperName() const override { + return ".omp_outlined."; + } + + private: + /// \brief A variable or parameter storing global thread id for OpenMP + /// constructs. + const VarDecl *GTidVar; + /// \brief OpenMP executable directive associated with the region. + const OMPExecutableDirective &Directive; + }; + CGCapturedStmtInfo *CapturedStmtInfo; /// BoundsChecking - Emit run-time bounds checks. Higher values mean @@ -1925,8 +1959,13 @@ const ArrayRef &Attrs = None); llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K); + void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S); + llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S); llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S); llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S); + typedef llvm::DenseMap OuterDeclMapTy; + void EmitOMPPrivateClause(const OMPExecutableDirective &D, + OuterDeclMapTy &OuterDeclMap); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -3059,11 +3059,13 @@ SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; + SmallVector PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + PrivateCopies.push_back(nullptr); continue; } @@ -3085,6 +3087,7 @@ if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + PrivateCopies.push_back(nullptr); continue; } @@ -3110,54 +3113,8 @@ // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the // class type. - while (Type.getNonReferenceType()->isArrayType()) { - Type = cast(Type.getNonReferenceType().getTypePtr()) - ->getElementType(); - } - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the private variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); - } + while (Type->isArrayType()) { + Type = cast(Type.getTypePtr())->getElementType(); } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -3175,14 +3132,30 @@ continue; } + auto VDPrivate = + VarDecl::Create(Context, CurContext, DE->getLocStart(), + DE->getExprLoc(), VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false); + if (VDPrivate->isInvalidDecl()) + continue; + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = DeclRefExpr::Create( + Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDPrivate, + /*isEnclosingLocal*/ false, /*NameLoc*/ SourceLocation(), VD->getType(), + /*VK*/ VK_LValue); + DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); + PrivateCopies.push_back(VDPrivateRefExpr); } if (Vars.empty()) return nullptr; - return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + PrivateCopies); } OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1842,6 +1842,10 @@ for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Reader->Reader.ReadSubExpr()); C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setPrivateCopies(Vars); } void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1752,8 +1752,12 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlists()) { + Writer->Writer.AddStmt(VE); + } + for (auto *VE : C->private_copies()) { Writer->Writer.AddStmt(VE); + } } void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { Index: test/OpenMP/for_private_messages.cpp =================================================================== --- test/OpenMP/for_private_messages.cpp +++ test/OpenMP/for_private_messages.cpp @@ -24,16 +24,16 @@ S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp for private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ #pragma omp for private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}} Index: test/OpenMP/parallel_codegen.cpp =================================================================== --- test/OpenMP/parallel_codegen.cpp +++ test/OpenMP/parallel_codegen.cpp @@ -39,7 +39,7 @@ // CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0 // CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]] // CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8* -// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]]) +// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]]) // CHECK-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}} // CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]]) // CHECK-NEXT: ret i32 [[RET]] @@ -55,13 +55,13 @@ // CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4 // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]] // CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8* -// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]]) +// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]]) // CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}} // CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]]) // CHECK-DEBUG-NEXT: ret i32 [[RET]] // CHECK-DEBUG-NEXT: } -// CHECK-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context) +// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context) // CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon* // CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]] // CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]] @@ -73,7 +73,7 @@ // CHECK: call void @{{.+terminate.*}}( // CHECK-NEXT: unreachable // CHECK-NEXT: } -// CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context) +// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context) // CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon* // CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]] // CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]] @@ -96,7 +96,7 @@ // CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0 // CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]] // CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8* -// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]]) +// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]]) // CHECK-NEXT: ret i32 0 // CHECK-NEXT: } // CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc) @@ -110,11 +110,11 @@ // CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4 // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]] // CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8* -// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]]) +// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]]) // CHECK-DEBUG-NEXT: ret i32 0 // CHECK-DEBUG-NEXT: } -// CHECK-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context) +// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context) // CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0* // CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]] // CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]] @@ -126,7 +126,7 @@ // CHECK: call void @{{.+terminate.*}}( // CHECK-NEXT: unreachable // CHECK-NEXT: } -// CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context) +// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context) // CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0* // CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]] // CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]] Index: test/OpenMP/parallel_for_private_messages.cpp =================================================================== --- test/OpenMP/parallel_for_private_messages.cpp +++ test/OpenMP/parallel_for_private_messages.cpp @@ -24,16 +24,16 @@ S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel for private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ #pragma omp parallel for private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp parallel for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel for private(h) // expected-error {{threadprivate or thread local variable cannot be private}} Index: test/OpenMP/parallel_private_codegen.cpp =================================================================== --- test/OpenMP/parallel_private_codegen.cpp +++ test/OpenMP/parallel_private_codegen.cpp @@ -0,0 +1,105 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -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 +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +template +struct S { + T f; + S(T a) : f(a) {} + S() : f() {} + operator T() { return T(); } + ~S() {} +}; + +// 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]+}} } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8* +template +T tmain() { + S test; + T t_var; + T vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel private(t_var, vec, s_arr, var) + { + vec[0] = t_var; + s_arr[0] = var; + } + return T(); +} + +int main() { + S test; + int t_var; + int vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel private(t_var, vec, s_arr, var) + { + vec[0] = t_var; + s_arr[0] = var; + } + return tmain(); +} + +// CHECK: define i{{[0-9]+}} @main() +// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) +// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]* +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], +// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]] +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: {{.+}}: +// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]* +// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]]) +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) +// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) +// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) +// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* +// CHECK: ret void + +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], +// CHECK: call void [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void +// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], +// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]], +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]], +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]] +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: {{.+}}: +// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]* +// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]]) +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]]) +// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) +// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]]) +// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* +// CHECK: ret void +#endif + Index: test/OpenMP/parallel_private_messages.cpp =================================================================== --- test/OpenMP/parallel_private_messages.cpp +++ test/OpenMP/parallel_private_messages.cpp @@ -25,15 +25,15 @@ const S3 c; // expected-note {{global variable is predetermined as shared}} const S3 ca[5]; // expected-note {{global variable is predetermined as shared}} extern const int f; // expected-note {{global variable is predetermined as shared}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v):a(v) { } }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5():a(0) {} + S5():a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -44,8 +44,8 @@ int main(int argc, char **argv) { const int d = 5; // expected-note {{constant variable is predetermined as shared}} const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}} - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g[] = {5, 6}; int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel private // expected-error {{expected '(' after 'private'}} @@ -62,7 +62,7 @@ #pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}} #pragma omp parallel private(da) // expected-error {{shared variable cannot be private}} #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}} - #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} #pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} foo(); Index: test/OpenMP/parallel_sections_private_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_private_messages.cpp +++ test/OpenMP/parallel_sections_private_messages.cpp @@ -24,16 +24,16 @@ S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -124,8 +124,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel sections private // expected-error {{expected '(' after 'private'}} @@ -168,7 +168,7 @@ { foo(); } -#pragma omp parallel sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp parallel sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } Index: test/OpenMP/sections_private_messages.cpp =================================================================== --- test/OpenMP/sections_private_messages.cpp +++ test/OpenMP/sections_private_messages.cpp @@ -24,16 +24,16 @@ S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -124,8 +124,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp sections private // expected-error {{expected '(' after 'private'}} @@ -168,7 +168,7 @@ { foo(); } -#pragma omp sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } Index: test/OpenMP/simd_private_messages.cpp =================================================================== --- test/OpenMP/simd_private_messages.cpp +++ test/OpenMP/simd_private_messages.cpp @@ -22,15 +22,15 @@ S3():a(0) { } }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v):a(v) { } }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5():a(0) {} + S5():a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -86,8 +86,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp simd private // expected-error {{expected '(' after 'private'}} @@ -110,7 +110,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp simd private (argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; - #pragma omp simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}} for (int k = 0; k < argc; ++k) ++k; Index: test/OpenMP/single_private_messages.cpp =================================================================== --- test/OpenMP/single_private_messages.cpp +++ test/OpenMP/single_private_messages.cpp @@ -24,16 +24,16 @@ S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -92,8 +92,8 @@ } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp single private // expected-error {{expected '(' after 'private'}} @@ -116,7 +116,7 @@ foo(); #pragma omp single private(argv[1]) // expected-error {{expected variable name}} foo(); -#pragma omp single private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp single private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}} foo(); Index: test/OpenMP/task_private_messages.cpp =================================================================== --- test/OpenMP/task_private_messages.cpp +++ test/OpenMP/task_private_messages.cpp @@ -27,16 +27,16 @@ const S3 c; // expected-note {{global variable is predetermined as shared}} const S3 ca[5]; // expected-note {{global variable is predetermined as shared}} extern const int f; // expected-note {{global variable is predetermined as shared}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -48,8 +48,8 @@ int main(int argc, char **argv) { const int d = 5; // expected-note {{constant variable is predetermined as shared}} const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}} - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp task private // expected-error {{expected '(' after 'private'}} @@ -66,7 +66,7 @@ #pragma omp task private(ca) // expected-error {{shared variable cannot be private}} #pragma omp task private(da) // expected-error {{shared variable cannot be private}} #pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}} -#pragma omp task private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} #pragma omp task private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} #pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} foo(); Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -1993,12 +1993,16 @@ template void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { - for (const auto *I : Node->varlists()) + for (const auto *I : Node->varlists()) { Visitor->AddStmt(I); + } } void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); + for (const auto *E : C->private_copies()) { + Visitor->AddStmt(E); + } } void OMPClauseEnqueue::VisitOMPFirstprivateClause( const OMPFirstprivateClause *C) {