From 2d6a5670465cb3f1d811695a9f23e372508240d2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 14 Jan 2012 04:30:29 +0000 Subject: [PATCH] constexpr irgen: Add irgen support for APValue::Struct, APValue::Union, APValue::Array and APValue::MemberPointer. All APValue values can now be emitted as constants. Add new CGCXXABI entry point for emitting an APValue MemberPointer. The other entrypoints dealing with constant member pointers are no longer necessary and will be removed in a later change. Switch codegen from using EvaluateAsRValue/EvaluateAsLValue to VarDecl::evaluateValue. This performs caching and deals with the nasty cases in C++11 where a non-const object's initializer can refer indirectly to previously-initialized fields within the same object. Building the intermediate APValue object incurs a measurable performance hit on pathological testcases with huge initializer lists, so we continue to build IR directly from the Expr nodes for array and record types outside of C++11. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148178 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 3 + include/clang/AST/Decl.h | 8 +- lib/AST/Decl.cpp | 15 +- lib/AST/ExprConstant.cpp | 13 +- lib/AST/RecordLayoutBuilder.cpp | 22 + lib/CodeGen/CGBlocks.cpp | 14 +- lib/CodeGen/CGCXXABI.cpp | 4 + lib/CodeGen/CGCXXABI.h | 3 + lib/CodeGen/CGDebugInfo.cpp | 5 +- lib/CodeGen/CGDecl.cpp | 4 +- lib/CodeGen/CGExprConstant.cpp | 527 ++++++++++++-------- lib/CodeGen/CodeGenModule.cpp | 7 +- lib/CodeGen/CodeGenModule.h | 10 + lib/CodeGen/ItaniumCXXABI.cpp | 49 +- test/CodeGen/2007-09-28-PackedUnionMember.c | 2 +- test/CodeGenCXX/blocks.cpp | 8 + test/CodeGenCXX/const-init-cxx11.cpp | 188 +++++++ test/CodeGenCXX/pr9965.cpp | 1 + 18 files changed, 646 insertions(+), 237 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c272580650..226613641b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1309,6 +1309,9 @@ public: /// of class definition. const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD); + /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits. + uint64_t getFieldOffset(const ValueDecl *FD) const; + bool isNearlyEmpty(const CXXRecordDecl *RD) const; MangleContext *createMangleContext(); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 4221239ec8..a5e5fcd39b 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1024,9 +1024,11 @@ public: /// \brief Attempt to evaluate the value of the initializer attached to this /// declaration, and produce notes explaining why it cannot be evaluated or is - /// not a constant expression. Returns true if evaluation succeeded. - /// The value can be obtained by calling getEvaluatedValue. - bool evaluateValue(llvm::SmallVectorImpl &Notes) const; + /// not a constant expression. Returns a pointer to the value if evaluation + /// succeeded, 0 otherwise. + APValue *evaluateValue() const; + APValue *evaluateValue( + llvm::SmallVectorImpl &Notes) const; /// \brief Return the already-evaluated value of this variable's /// initializer, or NULL if the value is not yet known. Returns pointer diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9132b0a190..3caca9d7e6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1379,15 +1379,20 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const { return Eval; } -bool VarDecl::evaluateValue( - llvm::SmallVectorImpl &Notes) const { +APValue *VarDecl::evaluateValue() const { + llvm::SmallVector Notes; + return evaluateValue(Notes); +} + +APValue *VarDecl::evaluateValue( + llvm::SmallVectorImpl &Notes) const { EvaluatedStmt *Eval = ensureEvaluatedStmt(); // We only produce notes indicating why an initializer is non-constant the // first time it is evaluated. FIXME: The notes won't always be emitted the // first time we try evaluation, so might not be produced at all. if (Eval->WasEvaluated) - return !Eval->Evaluated.isUninit(); + return Eval->Evaluated.isUninit() ? 0 : &Eval->Evaluated; const Expr *Init = cast(Eval->Value); assert(!Init->isValueDependent()); @@ -1396,7 +1401,7 @@ bool VarDecl::evaluateValue( // FIXME: Produce a diagnostic for self-initialization. Eval->CheckedICE = true; Eval->IsICE = false; - return false; + return 0; } Eval->IsEvaluating = true; @@ -1418,7 +1423,7 @@ bool VarDecl::evaluateValue( Eval->IsICE = Notes.empty(); } - return Result; + return Result ? &Eval->Evaluated : 0; } bool VarDecl::checkInitIsICE() const { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 912b111d61..ec5111579a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -5413,15 +5413,12 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { return true; } - // FIXME: Evaluating initializers for large arrays can cause performance - // problems, and we don't use such values yet. Once we have a more efficient - // array representation, this should be reinstated, and used by CodeGen. - // The same problem affects large records. + // FIXME: Evaluating values of large array and record types can cause + // performance problems. Only do so in C++11 for now. if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) && !Ctx.getLangOptions().CPlusPlus0x) return false; - // FIXME: If this is the initializer for an lvalue, pass that in. EvalInfo Info(Ctx, Result); return ::EvaluateAsRValue(Info, this, Result.Val); } @@ -5461,6 +5458,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, const VarDecl *VD, llvm::SmallVectorImpl &Notes) const { + // FIXME: Evaluating initializers for large array and record types can cause + // performance problems. Only do so in C++11 for now. + if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) && + !Ctx.getLangOptions().CPlusPlus0x) + return false; + Expr::EvalStatus EStatus; EStatus.Diag = &Notes; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 5223219a30..d094461dc3 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -2153,6 +2153,28 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { return Entry; } +static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) { + const ASTRecordLayout &Layout = C.getASTRecordLayout(FD->getParent()); + return Layout.getFieldOffset(FD->getFieldIndex()); +} + +uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const { + uint64_t OffsetInBits; + if (const FieldDecl *FD = dyn_cast(VD)) { + OffsetInBits = ::getFieldOffset(*this, FD); + } else { + const IndirectFieldDecl *IFD = cast(VD); + + OffsetInBits = 0; + for (IndirectFieldDecl::chain_iterator CI = IFD->chain_begin(), + CE = IFD->chain_end(); + CI != CE; ++CI) + OffsetInBits += ::getFieldOffset(*this, cast(*CI)); + } + + return OffsetInBits; +} + /// getObjCLayout - Get or compute information about the layout of the /// given interface. /// diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 8fc4344201..e6ecb6a88b 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -215,6 +215,7 @@ static bool isSafeForCXXConstantCapture(QualType type) { /// acceptable because we make no promises about address stability of /// captured variables. static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM, + CodeGenFunction *CGF, const VarDecl *var) { QualType type = var->getType(); @@ -235,7 +236,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM, const Expr *init = var->getInit(); if (!init) return 0; - return CGM.EmitConstantExpr(init, var->getType()); + return CGM.EmitConstantInit(*var, CGF); } /// Get the low bit of a nonzero character count. This is the @@ -278,7 +279,8 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, /// Compute the layout of the given block. Attempts to lay the block /// out with minimal space requirements. -static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { +static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, + CGBlockInfo &info) { ASTContext &C = CGM.getContext(); const BlockDecl *block = info.getBlockDecl(); @@ -342,7 +344,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { // Otherwise, build a layout chunk with the size and alignment of // the declaration. - if (llvm::Constant *constant = tryCaptureAsConstant(CGM, variable)) { + if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) { info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant); continue; } @@ -497,7 +499,7 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { // Compute information about the layout, etc., of this block, // pushing cleanups as necessary. - computeBlockInfo(CGF.CGM, blockInfo); + computeBlockInfo(CGF.CGM, &CGF, blockInfo); // Nothing else to do if it can be global. if (blockInfo.CanBeGlobal) return; @@ -604,7 +606,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { // layout for it. if (!blockExpr->getBlockDecl()->hasCaptures()) { CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName()); - computeBlockInfo(CGM, blockInfo); + computeBlockInfo(CGM, this, blockInfo); blockInfo.BlockExpression = blockExpr; return EmitBlockLiteral(blockInfo); } @@ -911,7 +913,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr, blockInfo.BlockExpression = blockExpr; // Compute information about the layout, etc., of this block. - computeBlockInfo(*this, blockInfo); + computeBlockInfo(*this, 0, blockInfo); // Using that metadata, generate the actual block function. llvm::Constant *blockFn; diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 248448ccdc..702029dd34 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -110,6 +110,10 @@ llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, return GetBogusMemberPointer(CGM, QualType(MPT, 0)); } +llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { + return GetBogusMemberPointer(CGM, MPT); +} + bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { // Fake answer. return true; diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index c2abf35832..e86e639627 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -125,6 +125,9 @@ public: virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); + /// Create a member pointer for the given member pointer constant. + virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT); + /// Emit a comparison between two member pointers. Returns an i1. virtual llvm::Value * EmitMemberPointerComparison(CodeGenFunction &CGF, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 31e4bcf5f8..ba89d3756e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1112,9 +1112,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); I != E; ++I) if (const VarDecl *V = dyn_cast(*I)) { - llvm::SmallVector Notes; - if (V->getInit() && V->evaluateValue(Notes)) { - APValue *Value = V->getEvaluatedValue(); + if (V->getInit()) { + const APValue *Value = V->evaluateValue(); if (Value && Value->isInt()) { llvm::ConstantInt *CI = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 05087f0e95..dd7cdb69a8 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -203,7 +203,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); + llvm::Constant *Init = CGM.EmitConstantInit(D, this); // If constant emission failed, then this should be a C++ static // initializer. @@ -972,7 +972,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::Constant *constant = 0; if (emission.IsConstantAggregate) { assert(!capturedByInit && "constant init contains a capturing block?"); - constant = CGM.EmitConstantExpr(D.getInit(), type, this); + constant = CGM.EmitConstantInit(D, this); } if (!constant) { diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index a8399d719f..f27586da04 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -44,14 +44,16 @@ class ConstStructBuilder { public: static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE); - -private: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + const APValue &Value, QualType ValTy); + +private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInChars(CharUnits::Zero()), LLVMStructAlignment(CharUnits::One()) { } - bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, + void AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitExpr); void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, @@ -62,8 +64,10 @@ private: void AppendTailPadding(CharUnits RecordSize); void ConvertStructToPacked(); - + bool Build(InitListExpr *ILE); + void Build(const APValue &Val, QualType ValTy); + llvm::Constant *Finalize(QualType Ty); CharUnits getAlignment(const llvm::Constant *C) const { if (Packed) return CharUnits::One(); @@ -77,7 +81,7 @@ private: } }; -bool ConstStructBuilder:: +void ConstStructBuilder:: AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitCst) { @@ -99,14 +103,13 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, // Convert the struct to a packed struct. ConvertStructToPacked(); - + AlignedNextFieldOffsetInChars = NextFieldOffsetInChars; } if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) { // We need to append padding. - AppendPadding( - FieldOffsetInChars - NextFieldOffsetInChars); + AppendPadding(FieldOffsetInChars - NextFieldOffsetInChars); assert(NextFieldOffsetInChars == FieldOffsetInChars && "Did not add enough padding!"); @@ -118,14 +121,12 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, Elements.push_back(InitCst); NextFieldOffsetInChars = AlignedNextFieldOffsetInChars + getSizeInChars(InitCst); - + if (Packed) - assert(LLVMStructAlignment == CharUnits::One() && + assert(LLVMStructAlignment == CharUnits::One() && "Packed struct not byte-aligned!"); else LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); - - return true; } void ConstStructBuilder::AppendBitField(const FieldDecl *Field, @@ -382,8 +383,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { if (!Field->isBitField()) { // Handle non-bitfield members. - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) - return false; + AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit); } else { // Otherwise we have a bitfield. AppendBitField(*Field, Layout.getFieldOffset(FieldNo), @@ -391,6 +391,77 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { } } + return true; +} + +void ConstStructBuilder::Build(const APValue &Val, QualType ValTy) { + RecordDecl *RD = ValTy->getAs()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + if (CXXRecordDecl *CD = dyn_cast(RD)) { + unsigned BaseNo = 0; + for (CXXRecordDecl::base_class_iterator Base = CD->bases_begin(), + BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) { + // Build the base class subobject at the appropriately-offset location + // within this object. + const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl(); + CharUnits BaseOffset = Layout.getBaseClassOffset(BD); + NextFieldOffsetInChars -= BaseOffset; + + Build(Val.getStructBase(BaseNo), Base->getType()); + + NextFieldOffsetInChars += BaseOffset; + } + } + + unsigned FieldNo = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->hasAttr(); + + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are + // ignored: + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD)) { + --FieldNo; + continue; + } + LastFD = (*Field); + } + + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && Val.getUnionField() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isUnnamedBitfield()) { + LastFD = (*Field); + continue; + } + + // Emit the value of the initializer. + const APValue &FieldValue = + RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo); + llvm::Constant *EltInit = + CGM.EmitConstantValue(FieldValue, Field->getType(), CGF); + assert(EltInit && "EmitConstantValue can't fail"); + + if (!Field->isBitField()) { + // Handle non-bitfield members. + AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit); + } else { + // Otherwise we have a bitfield. + AppendBitField(*Field, Layout.getFieldOffset(FieldNo), + cast(EltInit)); + } + } +} + +llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) { + RecordDecl *RD = Ty->getAs()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + CharUnits LayoutSizeInChars = Layout.getSize(); if (NextFieldOffsetInChars > LayoutSizeInChars) { @@ -398,62 +469,69 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { // we must have a flexible array member at the end. assert(RD->hasFlexibleArrayMember() && "Must have flexible array member if struct is bigger than type!"); - + // No tail padding is necessary. - return true; - } + } else { + // Append tail padding if necessary. + AppendTailPadding(LayoutSizeInChars); - CharUnits LLVMSizeInChars = - NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment); + CharUnits LLVMSizeInChars = + NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment); - // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInChars <= LayoutSizeInChars && - LLVMSizeInChars > LayoutSizeInChars) { - assert(!Packed && "Size mismatch!"); - - ConvertStructToPacked(); - assert(NextFieldOffsetInChars <= LayoutSizeInChars && - "Converting to packed did not help!"); - } + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInChars <= LayoutSizeInChars && + LLVMSizeInChars > LayoutSizeInChars) { + assert(!Packed && "Size mismatch!"); - // Append tail padding if necessary. - AppendTailPadding(LayoutSizeInChars); + ConvertStructToPacked(); + assert(NextFieldOffsetInChars <= LayoutSizeInChars && + "Converting to packed did not help!"); + } - assert(LayoutSizeInChars == NextFieldOffsetInChars && - "Tail padding mismatch!"); + assert(LayoutSizeInChars == NextFieldOffsetInChars && + "Tail padding mismatch!"); + } - return true; -} - -llvm::Constant *ConstStructBuilder:: - BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); - - if (!Builder.Build(ILE)) - return 0; - // Pick the type to use. If the type is layout identical to the ConvertType // type then use it, otherwise use whatever the builder produced for us. llvm::StructType *STy = llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(), - Builder.Elements,Builder.Packed); - llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType()); - if (llvm::StructType *ILESTy = dyn_cast(ILETy)) { - if (ILESTy->isLayoutIdentical(STy)) - STy = ILESTy; + Elements, Packed); + llvm::Type *ValTy = CGM.getTypes().ConvertType(Ty); + if (llvm::StructType *ValSTy = dyn_cast(ValTy)) { + if (ValSTy->isLayoutIdentical(STy)) + STy = ValSTy; } - - llvm::Constant *Result = - llvm::ConstantStruct::get(STy, Builder.Elements); - - assert(Builder.NextFieldOffsetInChars.RoundUpToAlignment( - Builder.getAlignment(Result)) == - Builder.getSizeInChars(Result) && "Size mismatch!"); - + + llvm::Constant *Result = llvm::ConstantStruct::get(STy, Elements); + + assert(NextFieldOffsetInChars.RoundUpToAlignment(getAlignment(Result)) == + getSizeInChars(Result) && "Size mismatch!"); + return Result; } - +llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, + CodeGenFunction *CGF, + InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + return Builder.Finalize(ILE->getType()); +} + +llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, + CodeGenFunction *CGF, + const APValue &Val, + QualType ValTy) { + ConstStructBuilder Builder(CGM, CGF); + Builder.Build(Val, ValTy); + return Builder.Finalize(ValTy); +} + + //===----------------------------------------------------------------------===// // ConstExprEmitter //===----------------------------------------------------------------------===// @@ -863,6 +941,22 @@ public: } // end anonymous namespace. +llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, + CodeGenFunction *CGF) { + if (const APValue *Value = D.evaluateValue()) + return EmitConstantValue(*Value, D.getType(), CGF); + + const Expr *E = D.getInit(); + assert(E && "No initializer to emit"); + + llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast(E)); + if (C && C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); + C = llvm::ConstantExpr::getZExt(C, BoolTy); + } + return C; +} + llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF) { @@ -875,155 +969,192 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, else Success = E->EvaluateAsRValue(Result, Context); - if (Success && !Result.HasSideEffects) { - switch (Result.Val.getKind()) { - case APValue::Uninitialized: - llvm_unreachable("Constant expressions should be initialized."); - case APValue::LValue: { - llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); - llvm::Constant *Offset = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - Result.Val.getLValueOffset().getQuantity()); - - llvm::Constant *C; - if (APValue::LValueBase LVBase = Result.Val.getLValueBase()) { - C = ConstExprEmitter(*this, CGF).EmitLValue(LVBase); - - // Apply offset if necessary. - if (!Offset->isNullValue()) { - llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); - llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type); - Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset); - C = llvm::ConstantExpr::getBitCast(Casted, C->getType()); - } - - // Convert to the appropriate type; this could be an lvalue for - // an integer. - if (isa(DestTy)) - return llvm::ConstantExpr::getBitCast(C, DestTy); + if (Success && !Result.HasSideEffects) + return EmitConstantValue(Result.Val, DestType, CGF); - return llvm::ConstantExpr::getPtrToInt(C, DestTy); - } else { - C = Offset; + llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast(E)); + if (C && C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); + C = llvm::ConstantExpr::getZExt(C, BoolTy); + } + return C; +} - // Convert to the appropriate type; this could be an lvalue for - // an integer. - if (isa(DestTy)) - return llvm::ConstantExpr::getIntToPtr(C, DestTy); +llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF) { + switch (Value.getKind()) { + case APValue::Uninitialized: + llvm_unreachable("Constant expressions should be initialized."); + case APValue::LValue: { + llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); + llvm::Constant *Offset = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + Value.getLValueOffset().getQuantity()); + + llvm::Constant *C; + if (APValue::LValueBase LVBase = Value.getLValueBase()) { + // An array can be represented as an lvalue referring to the base. + if (isa(DestTy)) { + assert(Offset->isNullValue() && "offset on array initializer"); + return ConstExprEmitter(*this, CGF).Visit( + const_cast(LVBase.get())); + } - // If the types don't match this should only be a truncate. - if (C->getType() != DestTy) - return llvm::ConstantExpr::getTrunc(C, DestTy); + C = ConstExprEmitter(*this, CGF).EmitLValue(LVBase); - return C; + // Apply offset if necessary. + if (!Offset->isNullValue()) { + llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); + llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type); + Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset); + C = llvm::ConstantExpr::getBitCast(Casted, C->getType()); } - } - case APValue::Int: { - llvm::Constant *C = llvm::ConstantInt::get(VMContext, - Result.Val.getInt()); - if (C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); - C = llvm::ConstantExpr::getZExt(C, BoolTy); - } - return C; - } - case APValue::ComplexInt: { - llvm::Constant *Complex[2]; - - Complex[0] = llvm::ConstantInt::get(VMContext, - Result.Val.getComplexIntReal()); - Complex[1] = llvm::ConstantInt::get(VMContext, - Result.Val.getComplexIntImag()); - - // FIXME: the target may want to specify that this is packed. - llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(), - Complex[1]->getType(), - NULL); - return llvm::ConstantStruct::get(STy, Complex); - } - case APValue::Float: { - const llvm::APFloat &Init = Result.Val.getFloat(); - if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf) - return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); - else - return llvm::ConstantFP::get(VMContext, Init); - } - case APValue::ComplexFloat: { - llvm::Constant *Complex[2]; - - Complex[0] = llvm::ConstantFP::get(VMContext, - Result.Val.getComplexFloatReal()); - Complex[1] = llvm::ConstantFP::get(VMContext, - Result.Val.getComplexFloatImag()); - - // FIXME: the target may want to specify that this is packed. - llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(), - Complex[1]->getType(), - NULL); - return llvm::ConstantStruct::get(STy, Complex); - } - case APValue::Vector: { - SmallVector Inits; - unsigned NumElts = Result.Val.getVectorLength(); + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (isa(DestTy)) + return llvm::ConstantExpr::getBitCast(C, DestTy); - if (Context.getLangOptions().AltiVec && - isa(E) && - cast(E)->getCastKind() == CK_VectorSplat) { - // AltiVec vector initialization with a single literal - APValue &Elt = Result.Val.getVectorElt(0); + return llvm::ConstantExpr::getPtrToInt(C, DestTy); + } else { + C = Offset; - llvm::Constant* InitValue = Elt.isInt() - ? cast - (llvm::ConstantInt::get(VMContext, Elt.getInt())) - : cast - (llvm::ConstantFP::get(VMContext, Elt.getFloat())); + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (isa(DestTy)) + return llvm::ConstantExpr::getIntToPtr(C, DestTy); - for (unsigned i = 0; i != NumElts; ++i) - Inits.push_back(InitValue); + // If the types don't match this should only be a truncate. + if (C->getType() != DestTy) + return llvm::ConstantExpr::getTrunc(C, DestTy); - } else { - for (unsigned i = 0; i != NumElts; ++i) { - APValue &Elt = Result.Val.getVectorElt(i); - if (Elt.isInt()) - Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); - else - Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); - } - } - return llvm::ConstantVector::get(Inits); + return C; } - case APValue::AddrLabelDiff: { - const AddrLabelExpr *LHSExpr = Result.Val.getAddrLabelDiffLHS(); - const AddrLabelExpr *RHSExpr = Result.Val.getAddrLabelDiffRHS(); - llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF); - llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF); - - // Compute difference - llvm::Type *ResultType = getTypes().ConvertType(E->getType()); - LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy); - RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy); - llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS); - - // LLVM is a bit sensitive about the exact format of the - // address-of-label difference; make sure to truncate after - // the subtraction. - return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType); + } + case APValue::Int: { + llvm::Constant *C = llvm::ConstantInt::get(VMContext, + Value.getInt()); + + if (C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType); + C = llvm::ConstantExpr::getZExt(C, BoolTy); } - case APValue::Array: - case APValue::Struct: - case APValue::Union: - case APValue::MemberPointer: - break; + return C; + } + case APValue::ComplexInt: { + llvm::Constant *Complex[2]; + + Complex[0] = llvm::ConstantInt::get(VMContext, + Value.getComplexIntReal()); + Complex[1] = llvm::ConstantInt::get(VMContext, + Value.getComplexIntImag()); + + // FIXME: the target may want to specify that this is packed. + llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(), + Complex[1]->getType(), + NULL); + return llvm::ConstantStruct::get(STy, Complex); + } + case APValue::Float: { + const llvm::APFloat &Init = Value.getFloat(); + if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf) + return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); + else + return llvm::ConstantFP::get(VMContext, Init); + } + case APValue::ComplexFloat: { + llvm::Constant *Complex[2]; + + Complex[0] = llvm::ConstantFP::get(VMContext, + Value.getComplexFloatReal()); + Complex[1] = llvm::ConstantFP::get(VMContext, + Value.getComplexFloatImag()); + + // FIXME: the target may want to specify that this is packed. + llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(), + Complex[1]->getType(), + NULL); + return llvm::ConstantStruct::get(STy, Complex); + } + case APValue::Vector: { + SmallVector Inits; + unsigned NumElts = Value.getVectorLength(); + + for (unsigned i = 0; i != NumElts; ++i) { + const APValue &Elt = Value.getVectorElt(i); + if (Elt.isInt()) + Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); + else + Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); } + return llvm::ConstantVector::get(Inits); + } + case APValue::AddrLabelDiff: { + const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS(); + const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS(); + llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF); + llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF); + + // Compute difference + llvm::Type *ResultType = getTypes().ConvertType(DestType); + LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy); + RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy); + llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS); + + // LLVM is a bit sensitive about the exact format of the + // address-of-label difference; make sure to truncate after + // the subtraction. + return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType); } + case APValue::Struct: + case APValue::Union: + return ConstStructBuilder::BuildStruct(*this, CGF, Value, DestType); + case APValue::Array: { + const ArrayType *CAT = Context.getAsArrayType(DestType); + unsigned NumElements = Value.getArraySize(); + unsigned NumInitElts = Value.getArrayInitializedElts(); - llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast(E)); - if (C && C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); - C = llvm::ConstantExpr::getZExt(C, BoolTy); + std::vector Elts; + Elts.reserve(NumElements); + + // Emit array filler, if there is one. + llvm::Constant *Filler = 0; + if (Value.hasArrayFiller()) + Filler = EmitConstantValue(Value.getArrayFiller(), + CAT->getElementType(), CGF); + + // Emit initializer elements. + llvm::Type *CommonElementType = 0; + for (unsigned I = 0; I < NumElements; ++I) { + llvm::Constant *C = Filler; + if (I < NumInitElts) + C = EmitConstantValue(Value.getArrayInitializedElt(I), + CAT->getElementType(), CGF); + if (I == 0) + CommonElementType = C->getType(); + else if (C->getType() != CommonElementType) + CommonElementType = 0; + Elts.push_back(C); + } + + if (!CommonElementType) { + // FIXME: Try to avoid packing the array + std::vector Types; + for (unsigned i = 0; i < Elts.size(); ++i) + Types.push_back(Elts[i]->getType()); + llvm::StructType *SType = llvm::StructType::get(VMContext, Types, true); + return llvm::ConstantStruct::get(SType, Elts); + } + + llvm::ArrayType *AType = + llvm::ArrayType::get(CommonElementType, NumElements); + return llvm::ConstantArray::get(AType, Elts); } - return C; + case APValue::MemberPointer: + return getCXXABI().EmitMemberPointer(Value, DestType); + } + llvm_unreachable("Unknown APValue kind"); } llvm::Constant * @@ -1032,11 +1163,6 @@ CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) { return ConstExprEmitter(*this, 0).EmitLValue(E); } -static uint64_t getFieldOffset(ASTContext &C, const FieldDecl *field) { - const ASTRecordLayout &layout = C.getASTRecordLayout(field->getParent()); - return layout.getFieldOffset(field->getFieldIndex()); -} - llvm::Constant * CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) { // Member pointer constants always have a very particular form. @@ -1048,18 +1174,7 @@ CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) { return getCXXABI().EmitMemberPointer(method); // Otherwise, a member data pointer. - uint64_t fieldOffset; - if (const FieldDecl *field = dyn_cast(decl)) - fieldOffset = getFieldOffset(getContext(), field); - else { - const IndirectFieldDecl *ifield = cast(decl); - - fieldOffset = 0; - for (IndirectFieldDecl::chain_iterator ci = ifield->chain_begin(), - ce = ifield->chain_end(); ci != ce; ++ci) - fieldOffset += getFieldOffset(getContext(), cast(*ci)); - } - + uint64_t fieldOffset = getContext().getFieldOffset(decl); CharUnits chars = getContext().toCharUnitsFromBits((int64_t) fieldOffset); return getCXXABI().EmitMemberDataPointer(type, chars); } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 76918dd448..c993abc2ac 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1354,7 +1354,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { QualType ASTTy = D->getType(); bool NonConstInit = false; - const Expr *InitExpr = D->getAnyInitializer(); + const VarDecl *InitDecl; + const Expr *InitExpr = D->getAnyInitializer(InitDecl); if (!InitExpr) { // This is a tentative definition; tentative definitions are @@ -1369,12 +1370,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); Init = EmitNullConstant(D->getType()); } else { - Init = EmitConstantExpr(InitExpr, D->getType()); + Init = EmitConstantInit(*InitDecl); if (!Init) { QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) T = D->getType(); - + if (getLangOptions().CPlusPlus) { Init = EmitNullConstant(T); NonConstInit = true; diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 4c839d1353..d94d10afc1 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -687,12 +687,22 @@ public: llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); + /// EmitConstantInit - Try to emit the initializer for the given declaration + /// as a constant; returns 0 if the expression cannot be emitted as a + /// constant. + llvm::Constant *EmitConstantInit(const VarDecl &D, CodeGenFunction *CGF = 0); + /// EmitConstantExpr - Try to emit the given expression as a /// constant; returns 0 if the expression cannot be emitted as a /// constant. llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF = 0); + /// EmitConstantValue - Try to emit the given constant value as a + /// constant; returns 0 if the value cannot be emitted as a constant. + llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, + CodeGenFunction *CGF = 0); + /// EmitNullConstant - Return the result of value-initializing the given /// type, i.e. a null expression of the given type. This is usually, /// but not always, an LLVM null constant. diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index c3f635aed6..969f03a8b0 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -82,6 +82,9 @@ public: llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); + llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT); + llvm::Constant *BuildMemberPointer(const CXXMethodDecl *MD, + CharUnits ThisAdjustment); llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, @@ -500,6 +503,11 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, } llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + return BuildMemberPointer(MD, CharUnits::Zero()); +} + +llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, + CharUnits ThisAdjustment) { assert(MD->isInstance() && "Member function must not be static!"); MD = MD->getCanonicalDecl(); @@ -524,14 +532,16 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { // discrimination as the least significant bit of ptr does for // Itanium. MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, + 2 * ThisAdjustment.getQuantity() + 1); } else { // Itanium C++ ABI 2.3: // For a virtual function, [the pointer field] is 1 plus the // virtual table offset (in bytes) of the function, // represented as a ptrdiff_t. MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, + ThisAdjustment.getQuantity()); } } else { const FunctionProtoType *FPT = MD->getType()->castAs(); @@ -549,12 +559,45 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty); MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, (IsARM ? 2 : 1) * + ThisAdjustment.getQuantity()); } return llvm::ConstantStruct::getAnon(MemPtr); } +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP, + QualType MPType) { + const MemberPointerType *MPT = MPType->castAs(); + const ValueDecl *MPD = MP.getMemberPointerDecl(); + if (!MPD) + return EmitNullMemberPointer(MPT); + + // Compute the this-adjustment. + CharUnits ThisAdjustment = CharUnits::Zero(); + ArrayRef Path = MP.getMemberPointerPath(); + bool DerivedMember = MP.isMemberPointerToDerivedMember(); + const CXXRecordDecl *RD = cast(MPD->getDeclContext()); + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + const CXXRecordDecl *Base = RD; + const CXXRecordDecl *Derived = Path[I]; + if (DerivedMember) + std::swap(Base, Derived); + ThisAdjustment += + getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base); + RD = Path[I]; + } + if (DerivedMember) + ThisAdjustment = -ThisAdjustment; + + if (const CXXMethodDecl *MD = dyn_cast(MPD)) + return BuildMemberPointer(MD, ThisAdjustment); + + CharUnits FieldOffset = + getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD)); + return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset); +} + /// The comparison algorithm is pretty easy: the member pointers are /// the same if they're either bitwise identical *or* both null. /// diff --git a/test/CodeGen/2007-09-28-PackedUnionMember.c b/test/CodeGen/2007-09-28-PackedUnionMember.c index 943480e4d8..f0183063dd 100644 --- a/test/CodeGen/2007-09-28-PackedUnionMember.c +++ b/test/CodeGen/2007-09-28-PackedUnionMember.c @@ -27,6 +27,7 @@ extern long bork(FuncPtr handler, const struct E *list); static long hndlr() { struct H cmd = { 4, 412 }; + struct H cmd2 = { 4, 412, 0 }; return 0; } void foo(void *inWindow) { @@ -35,4 +36,3 @@ void foo(void *inWindow) { }; bork(hndlr, events); } - diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp index 921d94a138..3d7fcfddbe 100644 --- a/test/CodeGenCXX/blocks.cpp +++ b/test/CodeGenCXX/blocks.cpp @@ -203,3 +203,11 @@ namespace test6 { // CHECK-NEXT: call void @_ZN5test63barEv() // CHECK-NEXT: ret void } + +namespace test7 { + int f() { + static int n; + int *const p = &n; + return ^{ return *p; }(); + } +} diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 5ec9a690f9..fb5d2cce00 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -1,5 +1,193 @@ // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s +// FIXME: The padding in all these objects should be zero-initialized. +namespace StructUnion { + struct A { + int n; + double d; + union U { + constexpr U(int x) : x(x) {} + constexpr U(const char *y) : y(y) {} + int x; + const char *y; + } u; + + constexpr A(int n, double d, int x) : n(n), d(d), u(x) {} + constexpr A(int n, double d, const char *y) : n(n), d(d), u(y) {} + }; + + // CHECK: @_ZN11StructUnion1aE = global {{.*}} { i32 1, double 2.000000e+00, {{.*}} { i32 3, [4 x i8] undef } } + extern constexpr A a(1, 2.0, 3); + + // CHECK: @_ZN11StructUnion1bE = global {{.*}} { i32 4, double 5.000000e+00, {{.*}} { i8* getelementptr inbounds ([6 x i8]* @{{.*}}, i32 0, i32 0) } } + extern constexpr A b(4, 5, "hello"); + + struct B { + int n; + }; + + // CHECK: @_ZN11StructUnion1cE = global {{.*}} zeroinitializer + // CHECK: @_ZN11StructUnion2c2E = global {{.*}} zeroinitializer + B c; + B c2 = B(); + + // CHECK: @_ZN11StructUnion1dE = global {{.*}} zeroinitializer + B d[10]; + + struct C { + constexpr C() : c(0) {} + int c; + }; + + // CHECK: @_ZN11StructUnion1eE = global {{.*}} zeroinitializer + C e[10]; + + struct D { + constexpr D() : d(5) {} + int d; + }; + + // CHECK: @_ZN11StructUnion1fE = global {{.*}} { i32 5 } + D f; +} + +namespace BaseClass { + template struct X : T {}; + struct C { char c = 1; }; + template struct Cs : X... {}; + struct N { int n = 3; }; + struct D { double d = 4.0; }; + + template + struct Test : Ts... { constexpr Test() : Ts()..., n(5) {} int n; }; + + using Test1 = Test, D, X>; + // CHECK: @_ZN9BaseClass2t1E = global {{.*}} { i32 3, i8 1, i8 1, i8 1, double 4.000000e+00, i8 1, i32 5 }, align 8 + extern constexpr Test1 t1 = Test1(); + + struct DN : D, N {}; + struct DND : DN, X {}; + struct DNN : DN, X {}; + // CHECK: @_ZN9BaseClass3dndE = global {{.*}} { double 4.000000e+00, i32 3, double 4.000000e+00 } + extern constexpr DND dnd = DND(); + // Note, N subobject is laid out in DN subobject's tail padding. + // CHECK: @_ZN9BaseClass3dnnE = global {{.*}} { double 4.000000e+00, i32 3, i32 3 } + extern constexpr DNN dnn = DNN(); + + struct E {}; + struct Test2 : X, X, X, X {}; + // CHECK: @_ZN9BaseClass2t2E = global {{.*}} { [4 x i8] undef } + extern constexpr Test2 t2 = Test2(); +} + +namespace Array { + // CHECK: @_ZN5Array3arrE = constant [2 x i32] [i32 4, i32 0] + extern constexpr int arr[2] = { 4 }; + + // CHECK: @_ZN5Array1cE = constant [6 x [4 x i8]] [{{.*}} c"foo\00", [4 x i8] c"a\00\00\00", [4 x i8] c"bar\00", [4 x i8] c"xyz\00", [4 x i8] c"b\00\00\00", [4 x i8] c"123\00"] + extern constexpr char c[6][4] = { "foo", "a", { "bar" }, { 'x', 'y', 'z' }, { "b" }, '1', '2', '3' }; + + struct C { constexpr C() : n(5) {} int n, m = 3 * n + 1; }; + // CHECK: @_ZN5Array5ctorsE = global [3 x {{.*}}] [{{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }] + extern const C ctors[3]; + constexpr C ctors[3]; + + // CHECK: @_ZN5Array1dE = constant {{.*}} { [2 x i32] [i32 1, i32 2], [3 x i32] [i32 3, i32 4, i32 5] } + struct D { int n[2]; int m[3]; } extern constexpr d = { 1, 2, 3, 4, 5 }; +} + +namespace MemberPtr { + struct B1 { + int a, b; + virtual void f(); + void g(); + }; + struct B2 { + int c, d; + virtual void h(); + void i(); + }; + struct C : B1 { + int e; + virtual void j(); + void k(); + }; + struct D : C, B2 { + int z; + virtual void l(); + void m(); + }; + + // CHECK: @_ZN9MemberPtr2daE = constant i64 8 + // CHECK: @_ZN9MemberPtr2dbE = constant i64 12 + // CHECK: @_ZN9MemberPtr2dcE = constant i64 32 + // CHECK: @_ZN9MemberPtr2ddE = constant i64 36 + // CHECK: @_ZN9MemberPtr2deE = constant i64 16 + // CHECK: @_ZN9MemberPtr2dzE = constant i64 40 + extern constexpr int (D::*da) = &B1::a; + extern constexpr int (D::*db) = &C::b; + extern constexpr int (D::*dc) = &B2::c; + extern constexpr int (D::*dd) = &D::d; + extern constexpr int (D::*de) = &C::e; + extern constexpr int (D::*dz) = &D::z; + + // CHECK: @_ZN9MemberPtr2baE = constant i64 8 + // CHECK: @_ZN9MemberPtr2bbE = constant i64 12 + // CHECK: @_ZN9MemberPtr2bcE = constant i64 8 + // CHECK: @_ZN9MemberPtr2bdE = constant i64 12 + // CHECK: @_ZN9MemberPtr2beE = constant i64 16 + // CHECK: @_ZN9MemberPtr3b1zE = constant i64 40 + // CHECK: @_ZN9MemberPtr3b2zE = constant i64 16 + extern constexpr int (B1::*ba) = (int(B1::*))&B1::a; + extern constexpr int (B1::*bb) = (int(B1::*))&C::b; + extern constexpr int (B2::*bc) = (int(B2::*))&B2::c; + extern constexpr int (B2::*bd) = (int(B2::*))&D::d; + extern constexpr int (B1::*be) = (int(B1::*))&C::e; + extern constexpr int (B1::*b1z) = (int(B1::*))&D::z; + extern constexpr int (B2::*b2z) = (int(B2::*))&D::z; + + // CHECK: @_ZN9MemberPtr2dfE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2dgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2dhE = constant {{.*}} { i64 1, i64 24 } + // CHECK: @_ZN9MemberPtr2diE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 24 } + // CHECK: @_ZN9MemberPtr2djE = constant {{.*}} { i64 9, i64 0 } + // CHECK: @_ZN9MemberPtr2dkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2dlE = constant {{.*}} { i64 17, i64 0 } + // CHECK: @_ZN9MemberPtr2dmE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 } + extern constexpr void (D::*df)() = &C::f; + extern constexpr void (D::*dg)() = &B1::g; + extern constexpr void (D::*dh)() = &B2::h; + extern constexpr void (D::*di)() = &D::i; + extern constexpr void (D::*dj)() = &C::j; + extern constexpr void (D::*dk)() = &C::k; + extern constexpr void (D::*dl)() = &D::l; + extern constexpr void (D::*dm)() = &D::m; + + // CHECK: @_ZN9MemberPtr2bfE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2bgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2bhE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2biE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2bjE = constant {{.*}} { i64 9, i64 0 } + // CHECK: @_ZN9MemberPtr2bkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr3b1lE = constant {{.*}} { i64 17, i64 0 } + // CHECK: @_ZN9MemberPtr3b1mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr3b2lE = constant {{.*}} { i64 17, i64 -24 } + // CHECK: @_ZN9MemberPtr3b2mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 -24 } + extern constexpr void (B1::*bf)() = (void(B1::*)())&C::f; + extern constexpr void (B1::*bg)() = (void(B1::*)())&B1::g; + extern constexpr void (B2::*bh)() = (void(B2::*)())&B2::h; + extern constexpr void (B2::*bi)() = (void(B2::*)())&D::i; + extern constexpr void (B1::*bj)() = (void(B1::*)())&C::j; + extern constexpr void (B1::*bk)() = (void(B1::*)())&C::k; + extern constexpr void (B1::*b1l)() = (void(B1::*)())&D::l; + extern constexpr void (B1::*b1m)() = (void(B1::*)())&D::m; + extern constexpr void (B2::*b2l)() = (void(B2::*)())&D::l; + extern constexpr void (B2::*b2m)() = (void(B2::*)())&D::m; +} + +// Constant initialization tests go before this point, +// dynamic initialization tests go after. + namespace CrossFuncLabelDiff { // Make sure we refuse to constant-fold the variable b. constexpr long a() { return (long)&&lbl + (0 && ({lbl: 0;})); } diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp index 145fd4e424..f625f48c33 100644 --- a/test/CodeGenCXX/pr9965.cpp +++ b/test/CodeGenCXX/pr9965.cpp @@ -3,6 +3,7 @@ template struct X { X() = default; + ~X() {} // not a literal type }; X x; -- 2.40.0