Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -709,6 +709,8 @@ return QualType::isConstant(*this, Ctx); } + bool isWriteOnce(ASTContext &Ctx); + /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). bool isPODType(ASTContext &Context) const; Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1919,6 +1919,19 @@ } } +bool QualType::isWriteOnce(ASTContext &Context) { + + if (!Context.getLangOpts().CPlusPlus || + !isConstant(Context) || getTypePtr()->isReferenceType()) + return false; + + if (const CXXRecordDecl *Record + = Context.getBaseElementType(*this)->getAsCXXRecordDecl()) + return !Record->hasMutableFields(); + + return true; +} + bool QualType::isPODType(ASTContext &Context) const { // C++11 has a more relaxed definition of POD. if (Context.getLangOpts().CPlusPlus11) Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -949,7 +949,8 @@ // to this variable. Set it to zero to indicate that NRVO was not // applied. llvm::Value *Zero = Builder.getFalse(); - llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo"); + llvm::AllocaInst *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo"); + NRVOFlag->setWriteOnce(Ty.isWriteOnce(getContext())); EnsureInsertPoint(); Builder.CreateStore(Zero, NRVOFlag); @@ -964,6 +965,7 @@ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); Alloc->setName(D.getName()); + Alloc->setWriteOnce(Ty.isWriteOnce(getContext())); CharUnits allocaAlignment = alignment; if (isByRef) @@ -986,7 +988,8 @@ if (!DidCallStackSave) { // Save the stack. - llvm::Value *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack"); + llvm::AllocaInst *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack"); + Stack->setWriteOnce(Ty.isWriteOnce(getContext())); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave); llvm::Value *V = Builder.CreateCall(F); @@ -1009,6 +1012,7 @@ // Allocate memory for the array. llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla"); vla->setAlignment(alignment.getQuantity()); + vla->setWriteOnce(Ty.isWriteOnce(getContext())); DeclPtr = vla; } @@ -1678,6 +1682,7 @@ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), D.getName() + ".addr"); Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + Alloc->setWriteOnce(Ty.isWriteOnce(getContext())); LValue lv = MakeAddrLValue(Alloc, Ty, getContext().getDeclAlign(&D)); EmitStoreOfScalar(Arg, lv, /* isInitialization */ true); LocalAddr = Builder.CreateLoad(Alloc); @@ -1721,6 +1726,7 @@ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), D.getName() + ".addr"); Alloc->setAlignment(Align.getQuantity()); + Alloc->setWriteOnce(Ty.isWriteOnce(getContext())); DeclPtr = Alloc; DoStore = true; } Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1705,6 +1705,7 @@ /// will not be considered. The caller will need to verify that the object is /// not written to during its construction. bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) { + if (!Ty.isConstant(Context) && !Ty->isReferenceType()) return false; @@ -2077,6 +2078,9 @@ GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor && isTypeConstant(D->getType(), true)); + // Mark const variables 'writeonce', if global is not 'constant'. + GV->setWriteOnce(!GV->isConstant() && D->getType().isWriteOnce(Context)); + // If it is in a read-only section, mark it 'constant'. if (const SectionAttr *SA = D->getAttr()) { const ASTContext::SectionInfo &SI = Context.SectionInfos[SA->getName()];