diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 3 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 8 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 15 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 13 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 22 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 14 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 527 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 10 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 49 | ||||
-rw-r--r-- | test/CodeGen/2007-09-28-PackedUnionMember.c | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/blocks.cpp | 8 | ||||
-rw-r--r-- | test/CodeGenCXX/const-init-cxx11.cpp | 188 | ||||
-rw-r--r-- | 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<PartialDiagnosticAt> &Notes) const; + /// not a constant expression. Returns a pointer to the value if evaluation + /// succeeded, 0 otherwise. + APValue *evaluateValue() const; + APValue *evaluateValue( + llvm::SmallVectorImpl<PartialDiagnosticAt> &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<PartialDiagnosticAt> &Notes) const { +APValue *VarDecl::evaluateValue() const { + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + return evaluateValue(Notes); +} + +APValue *VarDecl::evaluateValue( + llvm::SmallVectorImpl<PartialDiagnosticAt> &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<Expr>(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<PartialDiagnosticAt> &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<FieldDecl>(VD)) { + OffsetInBits = ::getFieldOffset(*this, FD); + } else { + const IndirectFieldDecl *IFD = cast<IndirectFieldDecl>(VD); + + OffsetInBits = 0; + for (IndirectFieldDecl::chain_iterator CI = IFD->chain_begin(), + CE = IFD->chain_end(); + CI != CE; ++CI) + OffsetInBits += ::getFieldOffset(*this, cast<FieldDecl>(*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<VarDecl>(*I)) { - llvm::SmallVector<PartialDiagnosticAt, 8> 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<RecordType>()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + if (CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(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<MsStructAttr>(); + + 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<llvm::ConstantInt>(EltInit)); + } + } +} + +llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) { + RecordDecl *RD = Ty->getAs<RecordType>()->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<llvm::StructType>(ILETy)) { - if (ILESTy->isLayoutIdentical(STy)) - STy = ILESTy; + Elements, Packed); + llvm::Type *ValTy = CGM.getTypes().ConvertType(Ty); + if (llvm::StructType *ValSTy = dyn_cast<llvm::StructType>(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<Expr*>(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<llvm::PointerType>(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<Expr*>(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<llvm::PointerType>(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<llvm::ArrayType>(DestTy)) { + assert(Offset->isNullValue() && "offset on array initializer"); + return ConstExprEmitter(*this, CGF).Visit( + const_cast<Expr*>(LVBase.get<const Expr*>())); + } - // 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<llvm::Constant *, 4> Inits; - unsigned NumElts = Result.Val.getVectorLength(); + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (isa<llvm::PointerType>(DestTy)) + return llvm::ConstantExpr::getBitCast(C, DestTy); - if (Context.getLangOptions().AltiVec && - isa<CastExpr>(E) && - cast<CastExpr>(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::Constant> - (llvm::ConstantInt::get(VMContext, Elt.getInt())) - : cast<llvm::Constant> - (llvm::ConstantFP::get(VMContext, Elt.getFloat())); + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (isa<llvm::PointerType>(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<llvm::Constant *, 4> 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<Expr*>(E)); - if (C && C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); - C = llvm::ConstantExpr::getZExt(C, BoolTy); + std::vector<llvm::Constant*> 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<llvm::Type*> 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<FieldDecl>(decl)) - fieldOffset = getFieldOffset(getContext(), field); - else { - const IndirectFieldDecl *ifield = cast<IndirectFieldDecl>(decl); - - fieldOffset = 0; - for (IndirectFieldDecl::chain_iterator ci = ifield->chain_begin(), - ce = ifield->chain_end(); ci != ce; ++ci) - fieldOffset += getFieldOffset(getContext(), cast<FieldDecl>(*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<FunctionProtoType>(); @@ -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<MemberPointerType>(); + const ValueDecl *MPD = MP.getMemberPointerDecl(); + if (!MPD) + return EmitNullMemberPointer(MPT); + + // Compute the this-adjustment. + CharUnits ThisAdjustment = CharUnits::Zero(); + ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath(); + bool DerivedMember = MP.isMemberPointerToDerivedMember(); + const CXXRecordDecl *RD = cast<CXXRecordDecl>(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<CXXMethodDecl>(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<typename T, unsigned> struct X : T {}; + struct C { char c = 1; }; + template<unsigned... Ns> struct Cs : X<C,Ns>... {}; + struct N { int n = 3; }; + struct D { double d = 4.0; }; + + template<typename ...Ts> + struct Test : Ts... { constexpr Test() : Ts()..., n(5) {} int n; }; + + using Test1 = Test<N, C, Cs<1,2>, D, X<C,1>>; + // 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<D,0> {}; + struct DNN : DN, X<N,0> {}; + // 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<E,0>, X<E,1>, X<E,2>, X<E,3> {}; + // 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<typename T> struct X { X() = default; + ~X() {} // not a literal type }; X<int> x; |