Index: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h +++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h @@ -2482,6 +2482,12 @@ bool RecursiveASTVisitor::VisitOMPFirstprivateClause( OMPFirstprivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: cfe/trunk/include/clang/AST/OpenMPClause.h =================================================================== --- cfe/trunk/include/clang/AST/OpenMPClause.h +++ cfe/trunk/include/clang/AST/OpenMPClause.h @@ -986,6 +986,8 @@ /// with the variables 'a' and 'b'. /// class OMPFirstprivateClause : public OMPVarListClause { + friend class OMPClauseReader; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. @@ -1006,6 +1008,33 @@ : OMPVarListClause( OMPC_firstprivate, SourceLocation(), SourceLocation(), SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param VL 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()); + } + + /// \brief Sets the list of references to initializer variables for new + /// private variables. + /// \param VL List of references. + void setInits(ArrayRef VL); + + /// \brief Gets the list of references to initializer variables for new + /// private variables. + MutableArrayRef getInits() { + return MutableArrayRef(getPrivateCopies().end(), varlist_size()); + } + ArrayRef getInits() const { + return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size()); + } public: /// \brief Creates clause with a list of variables \a VL. @@ -1014,11 +1043,16 @@ /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// \param VL List of references to the variables. + /// \param VL List of references to the original variables. + /// \param PrivateVL List of references to private copies with initializers. + /// \param InitVL List of references to auto generated variables used for + /// initialization of a single array element. Used if firstprivate variable is + /// of array type. /// static OMPFirstprivateClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef VL); + SourceLocation EndLoc, ArrayRef VL, ArrayRef PrivateVL, + ArrayRef InitVL); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -1026,6 +1060,33 @@ /// static OMPFirstprivateClause *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()); + } + + typedef MutableArrayRef::iterator inits_iterator; + typedef ArrayRef::iterator inits_const_iterator; + typedef llvm::iterator_range inits_range; + typedef llvm::iterator_range inits_const_range; + + inits_range inits() { + return inits_range(getInits().begin(), getInits().end()); + } + inits_const_range inits() const { + return inits_const_range(getInits().begin(), getInits().end()); + } + StmtRange children() { return StmtRange(reinterpret_cast(varlist_begin()), reinterpret_cast(varlist_end())); Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h @@ -2504,6 +2504,12 @@ bool RecursiveASTVisitor::VisitOMPFirstprivateClause( OMPFirstprivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -7141,8 +7141,8 @@ "expected variable name">; def err_omp_required_method : Error< "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">; -def err_omp_task_predetermined_firstprivate_required_method : Error< - "predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous %select{copy constructor|destructor}0">; +def note_omp_task_predetermined_firstprivate_here : Note< + "predetermined as a firstprivate in a task construct here">; def err_omp_clause_ref_type_arg : Error< "arguments of OpenMP clause '%0' cannot be of reference type %1">; def err_omp_task_predetermined_firstprivate_ref_type_arg : Error< Index: cfe/trunk/lib/AST/Stmt.cpp =================================================================== --- cfe/trunk/lib/AST/Stmt.cpp +++ cfe/trunk/lib/AST/Stmt.cpp @@ -1198,19 +1198,31 @@ return new (Mem) OMPPrivateClause(N); } -OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { +void OMPFirstprivateClause::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()); +} + +void OMPFirstprivateClause::setInits(ArrayRef VL) { + assert(VL.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), getPrivateCopies().end()); +} + +OMPFirstprivateClause * +OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PrivateVL, + ArrayRef InitVL) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause), llvm::alignOf()) + - sizeof(Expr *) * VL.size()); - OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc, - LParenLoc, - EndLoc, - VL.size()); + 3 * sizeof(Expr *) * VL.size()); + OMPFirstprivateClause *Clause = + new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setPrivateCopies(PrivateVL); + Clause->setInits(InitVL); return Clause; } @@ -1218,7 +1230,7 @@ unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause), llvm::alignOf()) + - sizeof(Expr *) * N); + 3 * sizeof(Expr *) * N); return new (Mem) OMPFirstprivateClause(N); } Index: cfe/trunk/lib/AST/StmtProfile.cpp =================================================================== --- cfe/trunk/lib/AST/StmtProfile.cpp +++ cfe/trunk/lib/AST/StmtProfile.cpp @@ -329,9 +329,15 @@ void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); } -void OMPClauseProfiler::VisitOMPFirstprivateClause( - const OMPFirstprivateClause *C) { +void +OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->private_copies()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->inits()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) { Index: cfe/trunk/lib/CodeGen/CGDecl.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp +++ cfe/trunk/lib/CodeGen/CGDecl.cpp @@ -1073,7 +1073,7 @@ /// \brief Determine whether the given initializer is trivial in the sense /// that it requires no code to be generated. -static bool isTrivialInitializer(const Expr *Init) { +bool CodeGenFunction::isTrivialInitializer(const Expr *Init) { if (!Init) return true; Index: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h =================================================================== --- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h +++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h @@ -14,33 +14,49 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H #define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H +#include "CodeGenFunction.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" -namespace llvm { -class AllocaInst; -class CallInst; -class GlobalVariable; -class Constant; -class Function; -class Module; -class StructLayout; -class ArrayType; -class FunctionType; -class StructType; -class Type; -class Value; -} // namespace llvm - namespace clang { namespace CodeGen { -class CodeGenFunction; -class CodeGenModule; +/// \brief API for captured statement code generation in OpenMP constructs. +class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo { +public: + CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S, + const VarDecl *ThreadIDVar) + : CGCapturedStmtInfo(S, CR_OpenMP), ThreadIDVar(ThreadIDVar), + Directive(D) {} + + virtual ~CGOpenMPRegionInfo() override{}; + + /// \brief Gets a variable or parameter for storing global thread id + /// inside OpenMP construct. + const VarDecl *getThreadIDVariable() const { return ThreadIDVar; } + + 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 *ThreadIDVar; + /// \brief OpenMP executable directive associated with the region. + const OMPExecutableDirective &Directive; +}; class CGOpenMPRuntime { public: @@ -76,7 +92,9 @@ OMPRTL__kmpc_critical, // Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, // kmp_critical_name *crit); - OMPRTL__kmpc_end_critical + OMPRTL__kmpc_end_critical, + // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); + OMPRTL__kmpc_barrier }; private: @@ -139,24 +157,15 @@ /// \brief Map of local debug location and functions. typedef llvm::DenseMap OpenMPLocMapTy; OpenMPLocMapTy OpenMPLocMap; - /// \brief Map of local gtid and functions. - typedef llvm::DenseMap OpenMPGtidMapTy; - OpenMPGtidMapTy OpenMPGtidMap; + /// \brief Map of local ThreadID and functions. + typedef llvm::DenseMap OpenMPThreadIDMapTy; + OpenMPThreadIDMapTy OpenMPThreadIDMap; /// \brief Type kmp_critical_name, originally defined as typedef kmp_int32 /// kmp_critical_name[8]; llvm::ArrayType *KmpCriticalNameTy; /// \brief Map of critical regions names and the corresponding lock objects. llvm::StringMap CriticalRegionVarNames; -public: - explicit CGOpenMPRuntime(CodeGenModule &CGM); - virtual ~CGOpenMPRuntime() {} - - /// \brief Cleans up references to the objects in finished function. - /// \param CGF Reference to finished CodeGenFunction. - /// - void FunctionFinished(CodeGenFunction &CGF); - /// \brief Emits object of ident_t type with info for source location. /// \param CGF Reference to current CodeGenFunction. /// \param Loc Clang source location. @@ -166,13 +175,6 @@ EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags = OMP_IDENT_KMPC); - /// \brief Generates global thread number value. - /// \param CGF Reference to current CodeGenFunction. - /// \param Loc Clang source location. - /// - llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF, - SourceLocation Loc); - /// \brief Returns pointer to ident_t type; llvm::Type *getIdentTyPointerTy(); @@ -184,6 +186,33 @@ /// \return Specified function. llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function); + /// \brief Gets thread id value for the current thread. + /// \param CGF Reference to current CodeGenFunction. + /// \param Loc Clang source location. + /// + llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc); + +public: + explicit CGOpenMPRuntime(CodeGenModule &CGM); + virtual ~CGOpenMPRuntime() {} + + /// \brief Cleans up references to the objects in finished function. + /// \param CGF Reference to finished CodeGenFunction. + /// + void FunctionFinished(CodeGenFunction &CGF); + + /// \brief Emits code for parallel call of the \a OutlinedFn with variables + /// captured in a record which address is stored in \a CapturedStruct. + /// \param CGF Reference to current CodeGenFunction. + /// \param Loc Clang source location. + /// \param OutlinedFn Outlined function to be run in parallel threads. + /// \param CapturedStruct A pointer to the record with the references to + /// variables used in \a OutlinedFn function. + /// + virtual void EmitOMPParallelCall(CodeGenFunction &CGF, SourceLocation Loc, + llvm::Value *OutlinedFn, + llvm::Value *CapturedStruct); + /// \brief Returns corresponding lock object for the specified critical region /// name. If the lock object does not exist it is created, otherwise the /// reference to the existing copy is returned. @@ -208,6 +237,14 @@ virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF, llvm::Value *RegionLock, SourceLocation Loc); + + /// \brief Emits a barrier for OpenMP threads. + /// \param CGF Reference to current CodeGenFunction. + /// \param Loc Clang source location. + /// \param Flags Flags for the barrier. + /// + virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPLocationFlags Flags); }; } // namespace CodeGen } // namespace clang Index: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp +++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp @@ -24,6 +24,29 @@ using namespace clang; using namespace CodeGen; +void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) { + CodeGenFunction::OuterDeclMapTy OuterDeclMap; + CGF.EmitOMPFirstprivateClause(Directive, OuterDeclMap); + if (!OuterDeclMap.empty()) { + // Emit implicit barrier to synchronize threads and avoid data races. + auto Flags = static_cast( + CGOpenMPRuntime::OMP_IDENT_KMPC | + CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL); + CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(), + Flags); + // 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); + } +} + CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) : CGM(CGM), DefaultOpenMPPSource(nullptr) { IdentTy = llvm::StructType::create( @@ -51,11 +74,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, @@ -63,6 +85,7 @@ Zero, Zero, DefaultOpenMPPSource}; llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values); DefaultOpenMPLocation->setInitializer(Init); + OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation; return DefaultOpenMPLocation; } return Entry; @@ -120,14 +143,14 @@ return LocValue; } -llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF, - SourceLocation Loc) { +llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF, + SourceLocation Loc) { assert(CGF.CurFn && "No function in current CodeGenFunction."); - llvm::Value *GTid = nullptr; - OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn); - if (I != OpenMPGtidMap.end()) { - GTid = I->second; + llvm::Value *ThreadID = nullptr; + OpenMPThreadIDMapTy::iterator I = OpenMPThreadIDMap.find(CGF.CurFn); + if (I != OpenMPThreadIDMap.end()) { + ThreadID = I->second; } else { // Check if current function is a function which has first parameter // with type int32 and name ".global_tid.". @@ -145,24 +168,24 @@ CGF.CurFn->arg_begin()->getName() == ".global_tid.") { CGBuilderTy::InsertPointGuard IPG(CGF.Builder); CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); - GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin()); + ThreadID = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin()); } else { // Generate "int32 .kmpc_global_thread_num.addr;" CGBuilderTy::InsertPointGuard IPG(CGF.Builder); CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)}; - GTid = CGF.EmitRuntimeCall( + ThreadID = CGF.EmitRuntimeCall( CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args); } - OpenMPGtidMap[CGF.CurFn] = GTid; + OpenMPThreadIDMap[CGF.CurFn] = ThreadID; } - return GTid; + return ThreadID; } void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) { assert(CGF.CurFn && "No function in current CodeGenFunction."); - if (OpenMPGtidMap.count(CGF.CurFn)) - OpenMPGtidMap.erase(CGF.CurFn); + if (OpenMPThreadIDMap.count(CGF.CurFn)) + OpenMPThreadIDMap.erase(CGF.CurFn); if (OpenMPLocMap.count(CGF.CurFn)) OpenMPLocMap.erase(CGF.CurFn); } @@ -219,10 +242,33 @@ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical"); 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; } +void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF, + SourceLocation Loc, + llvm::Value *OutlinedFn, + llvm::Value *CapturedStruct) { + // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/) + llvm::Value *Args[] = { + EmitOpenMPUpdateLocation(CGF, Loc), + CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument + // (there is only one additional argument - 'context') + CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()), + CGF.EmitCastToVoidPtr(CapturedStruct)}; + auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call); + CGF.EmitRuntimeCall(RTLFn, Args); +} + llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); @@ -245,7 +291,7 @@ SourceLocation Loc) { // Prepare other arguments and build a call to __kmpc_critical llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), - GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock}; + GetOpenMPThreadID(CGF, Loc), RegionLock}; auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical); CGF.EmitRuntimeCall(RTLFn, Args); } @@ -255,8 +301,19 @@ SourceLocation Loc) { // Prepare other arguments and build a call to __kmpc_end_critical llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), - GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock}; + GetOpenMPThreadID(CGF, Loc), RegionLock}; auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical); CGF.EmitRuntimeCall(RTLFn, Args); } + +void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF, + SourceLocation Loc, + OpenMPLocationFlags Flags) { + // Build call __kmpc_barrier(loc, thread_id) + llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags), + GetOpenMPThreadID(CGF, Loc)}; + auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier); + CGF.EmitRuntimeCall(RTLFn, Args); +} + Index: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp +++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp @@ -24,6 +24,110 @@ // OpenMP Directive Emission //===----------------------------------------------------------------------===// +void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr, + llvm::Value *PrivateAddr, + const Expr *AssignExpr, + QualType OriginalType, + const VarDecl *VDInit) { + EmitBlock(createBasicBlock(".omp.assign.begin.")); + if (!isa(AssignExpr) || isTrivialInitializer(AssignExpr)) { + // Perform simple memcpy. + EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(), + AssignExpr->getType()); + } else { + // Perform element-by-element initialization. + QualType ElementTy; + auto SrcBegin = OriginalAddr.getAddress(); + auto DestBegin = PrivateAddr; + auto ArrayTy = OriginalType->getAsArrayTypeUnsafe(); + auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin); + auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin); + auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements); + auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + auto BodyBB = createBasicBlock("omp.arraycpy.body"); + auto DoneBB = createBasicBlock("omp.arraycpy.done"); + auto IsEmpty = + Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + auto EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2, + "omp.arraycpy.srcElementPast"); + SrcElementPast->addIncoming(SrcEnd, EntryBB); + auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2, + "omp.arraycpy.destElementPast"); + DestElementPast->addIncoming(DestEnd, EntryBB); + + // Shift the address back by one element. + auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne, + "omp.arraycpy.dest.element"); + auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne, + "omp.arraycpy.src.element"); + { + // Create RunCleanScope to cleanup possible temps. + CodeGenFunction::RunCleanupsScope Init(*this); + // Emit initialization for single element. + LocalDeclMap[VDInit] = SrcElement; + EmitAnyExprToMem(AssignExpr, DestElement, + AssignExpr->getType().getQualifiers(), + /*IsInitializer*/ false); + LocalDeclMap.erase(VDInit); + } + + // Check whether we've reached the end. + auto Done = + Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock()); + SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } + EmitBlock(createBasicBlock(".omp.assign.end.")); +} + +void CodeGenFunction::EmitOMPFirstprivateClause( + const OMPExecutableDirective &D, + CodeGenFunction::OuterDeclMapTy &OuterDeclMap) { + auto PrivateFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_firstprivate; + }; + for (OMPExecutableDirective::filtered_clause_iterator + I(D.clauses(), PrivateFilter); I; ++I) { + auto *C = cast(*I); + auto IRef = C->varlist_begin(); + auto InitsRef = C->inits().begin(); + for (auto IInit : C->private_copies()) { + auto VD = cast(cast(IInit)->getDecl()); + if (*InitsRef != nullptr) { + // Emit VarDecl with copy init for arrays. + auto *FD = CapturedStmtInfo->lookup( + cast(cast(*IRef)->getDecl())); + LValue Base = MakeNaturalAlignAddrLValue( + CapturedStmtInfo->getContextValue(), + getContext().getTagDeclType(FD->getParent())); + auto OriginalAddr = EmitLValueForField(Base, FD); + auto VDInit = cast(cast(*InitsRef)->getDecl()); + auto Emission = EmitAutoVarAlloca(*VD); + // Emit initialization of aggregate firstprivate vars. + EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(), + VD->getInit(), (*IRef)->getType(), VDInit); + EmitAutoVarCleanups(Emission); + } else + // Emit VarDecl with copy init. + EmitDecl(*VD); + OuterDeclMap[cast(*IRef)->getDecl()] = GetAddrOfLocalVar(VD); + ++IRef, ++InitsRef; + } + } +} + void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { const CapturedStmt *CS = cast(S.getAssociatedStmt()); llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS); @@ -31,22 +135,13 @@ 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); } - // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/) - llvm::Value *Args[] = { - CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()), - Builder.getInt32(1), // Number of arguments after 'microtask' argument - // (there is only one additional argument - 'context') - Builder.CreateBitCast(OutlinedFn, - CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()), - EmitCastToVoidPtr(CapturedStruct)}; - llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction( - CGOpenMPRuntime::OMPRTL__kmpc_fork_call); - EmitRuntimeCall(RTLFn, Args); + CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn, + CapturedStruct); } void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S, Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -113,6 +113,7 @@ void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION; friend class CGCXXABI; + friend class CGOpenMPRegionInfo; public: /// A jump destination is an abstract label, branching to which may /// require a jump out through normal cleanups. @@ -1826,6 +1827,10 @@ typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D, llvm::Value *Address); + /// \brief Determine whether the given initializer is trivial in the sense + /// that it requires no code to be generated. + bool isTrivialInitializer(const Expr *Init); + /// EmitAutoVarDecl - Emit an auto variable declaration. /// /// This function can be called with a null (unreachable) insert point. @@ -1991,8 +1996,16 @@ 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 EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr, + const Expr *AssignExpr, QualType Type, + const VarDecl *VDInit); + void EmitOMPFirstprivateClause(const OMPExecutableDirective &D, + OuterDeclMapTy &OuterDeclMap); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); Index: cfe/trunk/lib/Sema/SemaOpenMP.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOpenMP.cpp +++ cfe/trunk/lib/Sema/SemaOpenMP.cpp @@ -3902,11 +3902,36 @@ return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } +namespace { +class DiagsUninitializedSeveretyRAII { +private: + DiagnosticsEngine &Diags; + SourceLocation SavedLoc; + bool IsIgnored; + +public: + DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc, + bool IsIgnored) + : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) { + if (!IsIgnored) { + Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init, + /*Map*/ diag::Severity::Ignored, Loc); + } + } + ~DiagsUninitializedSeveretyRAII() { + if (!IsIgnored) + Diags.popMappings(SavedLoc); + } +}; +} + OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; + SmallVector PrivateCopies; + SmallVector Inits; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); auto ImplicitClauseLoc = DSAStack->getConstructLoc(); @@ -3916,11 +3941,13 @@ if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + PrivateCopies.push_back(nullptr); + Inits.push_back(nullptr); continue; } - SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc - : RefExpr->getExprLoc(); + SourceLocation ELoc = + IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] @@ -3938,6 +3965,8 @@ if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + PrivateCopies.push_back(nullptr); + Inits.push_back(nullptr); continue; } @@ -3971,65 +4000,6 @@ // clause requires an accessible, unambiguous copy constructor for the // class type. Type = Context.getBaseElementType(Type); - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the firstprivate variable. - if (RD) { - CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - if (IsImplicitClause) { - Diag(ImplicitClauseLoc, - diag::err_omp_task_predetermined_firstprivate_required_method) - << 0; - Diag(RefExpr->getExprLoc(), diag::note_used_here); - } else { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_firstprivate) << 1; - } - 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()) { - if (IsImplicitClause) { - Diag(ImplicitClauseLoc, - diag::err_omp_task_predetermined_firstprivate_required_method) - << 1; - Diag(RefExpr->getExprLoc(), diag::note_used_here); - } else { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_firstprivate) << 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); - } - } // If an implicit firstprivate variable found it was checked already. if (!IsImplicitClause) { @@ -4119,15 +4089,67 @@ } } + Type = Type.getUnqualifiedType(); + auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(), + ELoc, VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + // Generate helper private variable and initialize it with the value of the + // original variable. The address of the original variable is replaced by + // the address of the new private variable in the CodeGen. This new variable + // is not added to IdResolver, so the code in the OpenMP region uses + // original variable for proper diagnostics and variable capturing. + Expr *VDInitRefExpr = nullptr; + // For arrays generate initializer for single element and replace it by the + // original array element in CodeGen. + if (DE->getType()->isArrayType()) { + auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(), + ELoc, VD->getIdentifier(), Type, + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + CurContext->addHiddenDecl(VDInit); + VDInitRefExpr = DeclRefExpr::Create( + Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDInit, + /*isEnclosingLocal*/ false, ELoc, Type, + /*VK*/ VK_LValue); + VDInit->setIsUsed(); + auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); + InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit); + InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc); + + InitializationSequence InitSeq(*this, Entity, Kind, Init); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init); + if (Result.isInvalid()) + VDPrivate->setInvalidDecl(); + else + VDPrivate->setInit(Result.getAs()); + } else { + AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(), + /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + } + if (VDPrivate->isInvalidDecl()) { + if (IsImplicitClause) { + Diag(DE->getExprLoc(), + diag::note_omp_task_predetermined_firstprivate_here); + } + continue; + } + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = DeclRefExpr::Create( + Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDPrivate, + /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(), + /*VK*/ VK_LValue); DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); + PrivateCopies.push_back(VDPrivateRefExpr); + Inits.push_back(VDInitRefExpr); } if (Vars.empty()) return nullptr; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); + Vars, PrivateCopies, Inits); } OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, Index: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp @@ -1854,6 +1854,14 @@ 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); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setInits(Vars); } void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) { Index: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp @@ -1761,8 +1761,15 @@ void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *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); + } + for (auto *VE : C->inits()) { + Writer->Writer.AddStmt(VE); + } } void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { Index: cfe/trunk/test/OpenMP/for_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/for_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/for_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -26,23 +26,23 @@ S3 &operator=(const S3 &s3); public: - S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}} + S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel @@ -107,7 +107,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel -#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for firstprivate(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 @@ -138,7 +138,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel -#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) // expected-note {{defined as private}} @@ -155,8 +155,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -194,7 +194,7 @@ for (i = 0; i < argc; ++i) foo(); #pragma omp parallel -#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} +#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'const S3'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel @@ -235,7 +235,7 @@ for (i = 0; i < argc; ++i) foo(); #pragma omp parallel -#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel @@ -263,7 +263,7 @@ for (i = 0; i < argc; ++i) foo(); #pragma omp parallel -#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel @@ -291,3 +291,4 @@ return foomain(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain' requested here}} } + Index: cfe/trunk/test/OpenMP/for_simd_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/for_simd_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/for_simd_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel @@ -99,7 +99,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel -#pragma omp for simd firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}} +#pragma omp for simd firstprivate(a, b) // expected-error {{a firstprivate variable with incomplete type 'S1'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel @@ -107,7 +107,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel -#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for simd firstprivate(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 @@ -138,7 +138,7 @@ for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel -#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) // expected-note {{defined as private}} @@ -155,8 +155,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -235,7 +235,7 @@ for (i = 0; i < argc; ++i) foo(); #pragma omp parallel -#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel @@ -263,7 +263,7 @@ for (i = 0; i < argc; ++i) foo(); #pragma omp parallel -#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel Index: cfe/trunk/test/OpenMP/parallel_codegen.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_codegen.cpp +++ cfe/trunk/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: cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp +++ cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp @@ -0,0 +1,169 @@ +// 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 + +struct St { + int a, b; + St() : a(0), b(0) {} + St(const St &st) : a(st.a + st.b), b(0) {} + ~St() {} +}; + +template +struct S { + T f; + S(T a) : f(a) {} + S() : f() {} + S(const S &s, St t = St()) : f(s.f + t.a) {} + operator T() { return T(); } + ~S() {} +}; + +// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float } +// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } +// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, i{{[0-9]+}} } +// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } +// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK-DAG: [[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(); + T vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel firstprivate(t_var, vec, s_arr, var) + { + vec[0] = t_var; + s_arr[0] = var; + } + return T(); +} + +int main() { + S test; + int t_var = 0; + int vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel firstprivate(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: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 +// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]], +// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]], +// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]], +// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]], +// CHECK: br label %[[VEC_PRIV_INIT:.+]] +// CHECK: [[VEC_PRIV_INIT]]: +// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8* +// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8* +// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]], +// CHECK: br label %[[VEC_PRIV_INIT_END:.+]] +// CHECK: [[VEC_PRIV_INIT_END]]: +// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2 +// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]], +// CHECK: br label %[[S_ARR_PRIV_INIT:.+]] +// CHECK: [[S_ARR_PRIV_INIT:.+]]: +// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2 +// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2 +// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]] +// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]] +// CHECK: [[S_ARR_BODY]]: +// CHECK: call void [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) +// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: call void [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]] +// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]] +// CHECK: [[S_ARR_PRIV_INIT_END]]: +// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3 +// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]** [[VAR_REF_PTR]], +// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) +// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]]) +// 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: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 +// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]], +// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]], +// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]], +// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]], +// CHECK: br label %[[VEC_PRIV_INIT:.+]] +// CHECK: [[VEC_PRIV_INIT]]: +// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8* +// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8* +// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]], +// CHECK: br label %[[VEC_PRIV_INIT_END:.+]] +// CHECK: [[VEC_PRIV_INIT_END]]: +// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2 +// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]], +// CHECK: br label %[[S_ARR_PRIV_INIT:.+]] +// CHECK: [[S_ARR_PRIV_INIT:.+]]: +// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 +// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2 +// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2 +// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]] +// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]] +// CHECK: [[S_ARR_BODY]]: +// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) +// CHECK: call void [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]] +// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]] +// CHECK: [[S_ARR_PRIV_INIT_END]]: +// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3 +// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]** [[VAR_REF_PTR]], +// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) +// CHECK: call void [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]]) +// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]]) +// 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: cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp @@ -13,7 +13,7 @@ mutable int a; public: S2():a(0) { } - S2(S2 &s2):a(s2.a) { } + S2(const S2 &s2):a(s2.a) { } static float S2s; static const float S2sc; }; @@ -24,22 +24,22 @@ int a; public: S3():a(0) { } - S3(S3 &s3):a(s3.a) { } + S3(const S3 &s3):a(s3.a) { } }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const 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(const S5 &s5):a(s5.a) { } + S5(const S5 &s5):a(s5.a) { } // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -50,8 +50,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = { 0 }; - 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 firstprivate // expected-error {{expected '(' after 'firstprivate'}} @@ -69,7 +69,7 @@ #pragma omp parallel firstprivate(da) #pragma omp parallel firstprivate(S2::S2s) #pragma omp parallel firstprivate(S2::S2sc) - #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + #pragma omp parallel firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} #pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} foo(); Index: cfe/trunk/test/OpenMP/parallel_for_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_for_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/parallel_for_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel for firstprivate // expected-error {{expected '(' after 'firstprivate'}} @@ -96,7 +96,7 @@ #pragma omp parallel for firstprivate(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for firstprivate(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 firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} @@ -123,7 +123,7 @@ #pragma omp parallel for firstprivate(i) for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) @@ -140,8 +140,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -201,7 +201,7 @@ #pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel for firstprivate(m) // OK @@ -223,7 +223,7 @@ #pragma omp parallel for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} for (i = 0; i < argc; ++i) foo(); -#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel for lastprivate(n) firstprivate(n) // OK Index: cfe/trunk/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}} @@ -96,7 +96,7 @@ #pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for simd firstprivate(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 simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} @@ -122,7 +122,7 @@ #pragma omp parallel for simd firstprivate(i) for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) @@ -139,8 +139,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -200,7 +200,7 @@ #pragma omp parallel for simd safelen(5) for (i = 0; i < argc; ++i) foo(); -#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel for simd firstprivate(m) // OK @@ -221,7 +221,7 @@ #pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} for (i = 0; i < argc; ++i) foo(); -#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} for (i = 0; i < argc; ++i) foo(); #pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK Index: cfe/trunk/test/OpenMP/parallel_sections_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_sections_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/parallel_sections_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel sections firstprivate // expected-error {{expected '(' after 'firstprivate'}} @@ -106,7 +106,7 @@ { foo(); } -#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -138,7 +138,7 @@ { foo(); } -#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -158,8 +158,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -237,7 +237,7 @@ { foo(); } -#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -262,7 +262,7 @@ { foo(); } -#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} { foo(); } Index: cfe/trunk/test/OpenMP/sections_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/sections_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/sections_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel @@ -117,7 +117,7 @@ foo(); } #pragma omp parallel -#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -153,7 +153,7 @@ foo(); } #pragma omp parallel -#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -173,8 +173,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -271,7 +271,7 @@ foo(); } #pragma omp parallel -#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } @@ -301,7 +301,7 @@ foo(); } #pragma omp parallel -#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} { foo(); } Index: cfe/trunk/test/OpenMP/single_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/single_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/single_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -27,22 +27,22 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note 2 {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note 4 {{'S5' declared here}} +class S5 { int a; - S5(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}} public: S5() : a(0) {} @@ -62,8 +62,8 @@ template int foomain(int argc, char **argv) { - I e(4); // expected-note {{'e' defined here}} - C g(5); // expected-note 2 {{'g' defined here}} + I e(4); + C g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel @@ -97,7 +97,7 @@ #pragma omp single firstprivate(argv[1]) // expected-error {{expected variable name}} foo(); #pragma omp parallel -#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp parallel #pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} @@ -121,7 +121,7 @@ #pragma omp single firstprivate(i) foo(); #pragma omp parallel -#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp parallel private(i) // expected-note {{defined as private}} #pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}} @@ -135,8 +135,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note 2 {{'g' defined here}} + S4 e(4); + S5 g(5); S3 m; S6 n(2); int i; @@ -197,7 +197,7 @@ #pragma omp single safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp single'}} foo(); #pragma omp parallel -#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp parallel #pragma omp single firstprivate(m) // OK @@ -215,7 +215,7 @@ #pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} foo(); #pragma omp parallel -#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp parallel #pragma omp single firstprivate(n) // OK Index: cfe/trunk/test/OpenMP/task_firstprivate_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/task_firstprivate_messages.cpp +++ cfe/trunk/test/OpenMP/task_firstprivate_messages.cpp @@ -14,7 +14,7 @@ public: S2() : a(0) {} - S2(S2 &s2) : a(s2.a) {} + S2(const S2 &s2) : a(s2.a) {} static float S2s; static const float S2sc; }; @@ -26,23 +26,23 @@ public: S3() : a(0) {} - S3(S3 &s3) : a(s3.a) {} + S3(const S3 &s3) : a(s3.a) {} }; const S3 c; const S3 ca[5]; extern const int f; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; S4(); - S4(const S4 &s4); + S4(const S4 &s4); // expected-note 2 {{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(const S5 &s5) : a(s5.a) {} + S5(const S5 &s5) : a(s5.a) {} // expected-note 2 {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -54,8 +54,8 @@ int main(int argc, char **argv) { const int d = 5; const int da[5] = {0}; - 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 firstprivate // expected-error {{expected '(' after 'firstprivate'}} @@ -73,7 +73,7 @@ #pragma omp task firstprivate(da) #pragma omp task firstprivate(S2::S2s) #pragma omp task firstprivate(S2::S2sc) -#pragma omp task firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} +#pragma omp task firstprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}} expected-error 2 {{calling a private constructor of class 'S5'}} #pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} #pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} foo(); Index: cfe/trunk/test/OpenMP/task_messages.cpp =================================================================== --- cfe/trunk/test/OpenMP/task_messages.cpp +++ cfe/trunk/test/OpenMP/task_messages.cpp @@ -5,8 +5,8 @@ #pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}} -class S { // expected-note 6 {{'S' declared here}} - S(const S &s) { a = s.a + 12; } +class S { + S(const S &s) { a = s.a + 12; } // expected-note 6 {{implicitly declared private here}} int a; public: @@ -17,23 +17,35 @@ S operator+(const S &) { return *this; } }; +class S1 { + int a; + +public: + S1() : a(0) {} + S1 &operator++() { return *this; } + S1(const S1 &) = delete; // expected-note 2 {{'S1' has been explicitly marked deleted here}} +}; + template int foo() { - T a; // expected-note 3 {{'a' defined here}} + T a; T &b = a; // expected-note 4 {{'b' defined here}} int r; + S1 s1; +// expected-error@+1 2 {{call to deleted constructor of 'S1'}} +#pragma omp task +// expected-note@+1 2 {{predetermined as a firstprivate in a task construct here}} + ++s1; #pragma omp task default(none) #pragma omp task default(shared) ++a; -// expected-error@+2 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} #pragma omp task default(none) #pragma omp task -// expected-note@+1 {{used here}} + // expected-error@+1 {{calling a private constructor of class 'S'}} ++a; #pragma omp task -// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} #pragma omp task - // expected-note@+1 {{used here}} + // expected-error@+1 {{calling a private constructor of class 'S'}} ++a; #pragma omp task default(shared) #pragma omp task @@ -46,11 +58,11 @@ #pragma omp task // expected-note@+1 2 {{used here}} ++b; -// expected-error@+3 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}} -// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}} -// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} +// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}} +// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}} #pragma omp task -// expected-note@+1 3 {{used here}} +// expected-error@+2 {{calling a private constructor of class 'S'}} +// expected-note@+1 2 {{used here}} #pragma omp parallel shared(a, b) ++a, ++b; // expected-note@+1 3 {{defined as reduction}} @@ -109,7 +121,7 @@ int main(int argc, char **argv) { int a; int &b = a; // expected-note 2 {{'b' defined here}} - S sa; // expected-note 3 {{'sa' defined here}} + S sa; S &sb = sa; // expected-note 2 {{'sb' defined here}} int r; #pragma omp task { // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} @@ -193,14 +205,12 @@ #pragma omp task default(shared) ++sa; #pragma omp task default(none) -// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} #pragma omp task -// expected-note@+1 {{used here}} + // expected-error@+1 {{calling a private constructor of class 'S'}} ++sa; #pragma omp task -// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} #pragma omp task -// expected-note@+1 {{used here}} + // expected-error@+1 {{calling a private constructor of class 'S'}} ++sa; #pragma omp task default(shared) #pragma omp task @@ -212,10 +222,10 @@ #pragma omp task // expected-note@+1 {{used here}} ++sb; -// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}} -// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}} +// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}} #pragma omp task -// expected-note@+1 2 {{used here}} +// expected-error@+2 {{calling a private constructor of class 'S'}} +// expected-note@+1 {{used here}} #pragma omp parallel shared(sa, sb) ++sa, ++sb; // expected-note@+1 2 {{defined as reduction}}