/// B(A& a) : A(a), f(3.14159) { }
/// };
/// \endcode
-class CXXCtorInitializer final
- : private llvm::TrailingObjects<CXXCtorInitializer, VarDecl *> {
+class CXXCtorInitializer final {
/// \brief Either the base class name/delegating constructor type (stored as
/// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
/// (IndirectFieldDecl*) being initialized.
unsigned IsWritten : 1;
/// If IsWritten is true, then this number keeps track of the textual order
- /// of this initializer in the original sources, counting from 0; otherwise,
- /// it stores the number of array index variables stored after this object
- /// in memory.
- unsigned SourceOrderOrNumArrayIndices : 13;
-
- CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
- SourceLocation MemberLoc, SourceLocation L, Expr *Init,
- SourceLocation R, VarDecl **Indices, unsigned NumIndices);
+ /// of this initializer in the original sources, counting from 0.
+ unsigned SourceOrder : 13;
public:
/// \brief Creates a new base-class initializer.
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo,
SourceLocation L, Expr *Init, SourceLocation R);
- /// \brief Creates a new member initializer that optionally contains
- /// array indices used to describe an elementwise initialization.
- static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member,
- SourceLocation MemberLoc, SourceLocation L,
- Expr *Init, SourceLocation R,
- VarDecl **Indices, unsigned NumIndices);
-
/// \brief Determine whether this initializer is initializing a base class.
bool isBaseInitializer() const {
return Initializee.is<TypeSourceInfo*>() && !IsDelegating;
/// \brief Return the source position of the initializer, counting from 0.
/// If the initializer was implicit, -1 is returned.
int getSourceOrder() const {
- return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1;
+ return IsWritten ? static_cast<int>(SourceOrder) : -1;
}
/// \brief Set the source order of this initializer.
///
/// This assumes that the initializer was written in the source code, and
/// ensures that isWritten() returns true.
- void setSourceOrder(int pos) {
+ void setSourceOrder(int Pos) {
assert(!IsWritten &&
+ "setSourceOrder() used on implicit initializer");
+ assert(SourceOrder == 0 &&
"calling twice setSourceOrder() on the same initializer");
- assert(SourceOrderOrNumArrayIndices == 0 &&
- "setSourceOrder() used when there are implicit array indices");
- assert(pos >= 0 &&
+ assert(Pos >= 0 &&
"setSourceOrder() used to make an initializer implicit");
IsWritten = true;
- SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos);
+ SourceOrder = static_cast<unsigned>(Pos);
}
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
- /// \brief Determine the number of implicit array indices used while
- /// described an array member initialization.
- unsigned getNumArrayIndices() const {
- return IsWritten ? 0 : SourceOrderOrNumArrayIndices;
- }
-
- /// \brief Retrieve a particular array index variable used to
- /// describe an array member initialization.
- VarDecl *getArrayIndex(unsigned I) {
- assert(I < getNumArrayIndices() && "Out of bounds member array index");
- return getTrailingObjects<VarDecl *>()[I];
- }
- const VarDecl *getArrayIndex(unsigned I) const {
- assert(I < getNumArrayIndices() && "Out of bounds member array index");
- return getTrailingObjects<VarDecl *>()[I];
- }
- void setArrayIndex(unsigned I, VarDecl *Index) {
- assert(I < getNumArrayIndices() && "Out of bounds member array index");
- getTrailingObjects<VarDecl *>()[I] = Index;
- }
- ArrayRef<VarDecl *> getArrayIndices() {
- return llvm::makeArrayRef(getTrailingObjects<VarDecl *>(),
- getNumArrayIndices());
- }
-
/// \brief Get the initializer.
Expr *getInit() const { return static_cast<Expr*>(Init); }
-
- friend TrailingObjects;
};
/// Description of a constructor that was inherited from a base class.
/// C++1y introduces a new form of "capture" called an init-capture that
/// includes an initializing expression (rather than capturing a variable),
/// and which can never occur implicitly.
-class LambdaExpr final
- : public Expr,
- private llvm::TrailingObjects<LambdaExpr, Stmt *, unsigned, VarDecl *> {
+class LambdaExpr final : public Expr,
+ private llvm::TrailingObjects<LambdaExpr, Stmt *> {
/// \brief The source range that covers the lambda introducer ([...]).
SourceRange IntroducerRange;
/// \brief Whether this lambda had the result type explicitly specified.
unsigned ExplicitResultType : 1;
- /// \brief Whether there are any array index variables stored at the end of
- /// this lambda expression.
- unsigned HasArrayIndexVars : 1;
-
/// \brief The location of the closing brace ('}') that completes
/// the lambda.
///
/// module file just to determine the source range.
SourceLocation ClosingBrace;
- size_t numTrailingObjects(OverloadToken<Stmt *>) const {
- return NumCaptures + 1;
- }
-
- size_t numTrailingObjects(OverloadToken<unsigned>) const {
- return HasArrayIndexVars ? NumCaptures + 1 : 0;
- }
-
/// \brief Construct a lambda expression.
LambdaExpr(QualType T, SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc, ArrayRef<LambdaCapture> Captures,
bool ExplicitParams, bool ExplicitResultType,
- ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace,
+ ArrayRef<Expr *> CaptureInits, SourceLocation ClosingBrace,
bool ContainsUnexpandedParameterPack);
/// \brief Construct an empty lambda expression.
- LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
+ LambdaExpr(EmptyShell Empty, unsigned NumCaptures)
: Expr(LambdaExprClass, Empty),
NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false),
- ExplicitResultType(false), HasArrayIndexVars(true) {
+ ExplicitResultType(false) {
getStoredStmts()[NumCaptures] = nullptr;
}
Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); }
- /// \brief Retrieve the mapping from captures to the first array index
- /// variable.
- unsigned *getArrayIndexStarts() { return getTrailingObjects<unsigned>(); }
-
- const unsigned *getArrayIndexStarts() const {
- return getTrailingObjects<unsigned>();
- }
-
- /// \brief Retrieve the complete set of array-index variables.
- VarDecl **getArrayIndexVars() { return getTrailingObjects<VarDecl *>(); }
-
- VarDecl *const *getArrayIndexVars() const {
- return getTrailingObjects<VarDecl *>();
- }
-
public:
/// \brief Construct a new lambda expression.
static LambdaExpr *
LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc,
ArrayRef<LambdaCapture> Captures, bool ExplicitParams,
bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace,
- bool ContainsUnexpandedParameterPack);
+ SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack);
/// \brief Construct a new lambda expression that will be deserialized from
/// an external source.
static LambdaExpr *CreateDeserialized(const ASTContext &C,
- unsigned NumCaptures,
- unsigned NumArrayIndexVars);
+ unsigned NumCaptures);
/// \brief Determine the default capture kind for this lambda.
LambdaCaptureDefault getCaptureDefault() const {
return capture_init_begin() + NumCaptures;
}
- /// \brief Retrieve the set of index variables used in the capture
- /// initializer of an array captured by copy.
- ///
- /// \param Iter The iterator that points at the capture initializer for
- /// which we are extracting the corresponding index variables.
- ArrayRef<VarDecl *>
- getCaptureInitIndexVars(const_capture_init_iterator Iter) const;
-
/// \brief Retrieve the source range covering the lambda introducer,
/// which contains the explicit capture list surrounded by square
/// brackets ([...]).
if (Init->isWritten() || getDerived().shouldVisitImplicitCode())
TRY_TO(TraverseStmt(Init->getInit()));
- if (getDerived().shouldVisitImplicitCode())
- // The braces for this one-line loop are required for MSVC2013. It
- // refuses to compile
- // for (int i : int_vec)
- // do {} while(false);
- // without braces on the for loop.
- for (VarDecl *VD : Init->getArrayIndices()) {
- TRY_TO(TraverseDecl(VD));
- }
-
return true;
}
DEF_TRAVERSE_STMT(GNUNullExpr, {})
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
DEF_TRAVERSE_STMT(NoInitExpr, {})
-DEF_TRAVERSE_STMT(ArrayInitLoopExpr, {})
+DEF_TRAVERSE_STMT(ArrayInitLoopExpr, {
+ // FIXME: The source expression of the OVE should be listed as
+ // a child of the ArrayInitLoopExpr.
+ if (OpaqueValueExpr *OVE = S->getCommonExpr())
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(OVE->getSourceExpr());
+})
DEF_TRAVERSE_STMT(ArrayInitIndexExpr, {})
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
Expr *VisitMemberExpr(MemberExpr *E);
Expr *VisitCallExpr(CallExpr *E);
Expr *VisitInitListExpr(InitListExpr *E);
+ Expr *VisitArrayInitLoopExpr(ArrayInitLoopExpr *E);
+ Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
Expr *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E);
Expr *VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
return To;
}
+Expr *ASTNodeImporter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) {
+ QualType ToType = Importer.Import(E->getType());
+ if (ToType.isNull())
+ return nullptr;
+
+ Expr *ToCommon = Importer.Import(E->getCommonExpr());
+ if (!ToCommon && E->getCommonExpr())
+ return nullptr;
+
+ Expr *ToSubExpr = Importer.Import(E->getSubExpr());
+ if (!ToSubExpr && E->getSubExpr())
+ return nullptr;
+
+ return new (Importer.getToContext())
+ ArrayInitLoopExpr(ToType, ToCommon, ToSubExpr);
+}
+
+Expr *ASTNodeImporter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) {
+ QualType ToType = Importer.Import(E->getType());
+ if (ToType.isNull())
+ return nullptr;
+ return new (Importer.getToContext()) ArrayInitIndexExpr(ToType);
+}
+
Expr *ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
FieldDecl *ToField = llvm::dyn_cast_or_null<FieldDecl>(
Importer.Import(DIE->getField()));
return new (ToContext)
CXXCtorInitializer(ToContext, ToTInfo, Import(From->getLParenLoc()),
ToExpr, Import(From->getRParenLoc()));
- } else if (unsigned NumArrayIndices = From->getNumArrayIndices()) {
- FieldDecl *ToField =
- llvm::cast_or_null<FieldDecl>(Import(From->getMember()));
- if (!ToField && From->getMember())
- return nullptr;
-
- SmallVector<VarDecl *, 4> ToAIs(NumArrayIndices);
-
- for (unsigned AII = 0; AII < NumArrayIndices; ++AII) {
- VarDecl *ToArrayIndex =
- dyn_cast_or_null<VarDecl>(Import(From->getArrayIndex(AII)));
- if (!ToArrayIndex && From->getArrayIndex(AII))
- return nullptr;
- }
-
- return CXXCtorInitializer::Create(
- ToContext, ToField, Import(From->getMemberLocation()),
- Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc()),
- ToAIs.data(), NumArrayIndices);
} else {
return nullptr;
}
SourceLocation EllipsisLoc)
: Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual),
- IsWritten(false), SourceOrderOrNumArrayIndices(0)
+ IsWritten(false), SourceOrder(0)
{
}
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
- IsWritten(false), SourceOrderOrNumArrayIndices(0)
+ IsWritten(false), SourceOrder(0)
{
}
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
- IsWritten(false), SourceOrderOrNumArrayIndices(0)
+ IsWritten(false), SourceOrder(0)
{
}
SourceLocation R)
: Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init),
LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false),
- IsWritten(false), SourceOrderOrNumArrayIndices(0)
+ IsWritten(false), SourceOrder(0)
{
}
-CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
- FieldDecl *Member,
- SourceLocation MemberLoc,
- SourceLocation L, Expr *Init,
- SourceLocation R,
- VarDecl **Indices,
- unsigned NumIndices)
- : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
- LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
- IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
-{
- std::uninitialized_copy(Indices, Indices + NumIndices,
- getTrailingObjects<VarDecl *>());
-}
-
-CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context,
- FieldDecl *Member,
- SourceLocation MemberLoc,
- SourceLocation L, Expr *Init,
- SourceLocation R,
- VarDecl **Indices,
- unsigned NumIndices) {
- void *Mem = Context.Allocate(totalSizeToAlloc<VarDecl *>(NumIndices),
- alignof(CXXCtorInitializer));
- return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R,
- Indices, NumIndices);
-}
-
TypeLoc CXXCtorInitializer::getBaseClassLoc() const {
if (isBaseInitializer())
return Initializee.get<TypeSourceInfo*>()->getTypeLoc();
SourceLocation CaptureDefaultLoc,
ArrayRef<LambdaCapture> Captures, bool ExplicitParams,
bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
bool ContainsUnexpandedParameterPack)
: Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(),
// Copy the body of the lambda.
*Stored++ = getCallOperator()->getBody();
-
- // Copy the array index variables, if any.
- HasArrayIndexVars = !ArrayIndexVars.empty();
- if (HasArrayIndexVars) {
- assert(ArrayIndexStarts.size() == NumCaptures);
- memcpy(getArrayIndexVars(), ArrayIndexVars.data(),
- sizeof(VarDecl *) * ArrayIndexVars.size());
- memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(),
- sizeof(unsigned) * Captures.size());
- getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
- }
}
LambdaExpr *LambdaExpr::Create(
SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc, ArrayRef<LambdaCapture> Captures,
bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
QualType T = Context.getTypeDeclType(Class);
- unsigned Size = totalSizeToAlloc<Stmt *, unsigned, VarDecl *>(
- Captures.size() + 1, ArrayIndexVars.empty() ? 0 : Captures.size() + 1,
- ArrayIndexVars.size());
+ unsigned Size = totalSizeToAlloc<Stmt *>(Captures.size() + 1);
void *Mem = Context.Allocate(Size);
- return new (Mem) LambdaExpr(T, IntroducerRange,
- CaptureDefault, CaptureDefaultLoc, Captures,
- ExplicitParams, ExplicitResultType,
- CaptureInits, ArrayIndexVars, ArrayIndexStarts,
- ClosingBrace, ContainsUnexpandedParameterPack);
+ return new (Mem)
+ LambdaExpr(T, IntroducerRange, CaptureDefault, CaptureDefaultLoc,
+ Captures, ExplicitParams, ExplicitResultType, CaptureInits,
+ ClosingBrace, ContainsUnexpandedParameterPack);
}
LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C,
- unsigned NumCaptures,
- unsigned NumArrayIndexVars) {
- unsigned Size = totalSizeToAlloc<Stmt *, unsigned, VarDecl *>(
- NumCaptures + 1, NumArrayIndexVars ? NumCaptures + 1 : 0,
- NumArrayIndexVars);
+ unsigned NumCaptures) {
+ unsigned Size = totalSizeToAlloc<Stmt *>(NumCaptures + 1);
void *Mem = C.Allocate(Size);
- return new (Mem) LambdaExpr(EmptyShell(), NumCaptures, NumArrayIndexVars > 0);
+ return new (Mem) LambdaExpr(EmptyShell(), NumCaptures);
}
bool LambdaExpr::isInitCapture(const LambdaCapture *C) const {
return capture_range(implicit_capture_begin(), implicit_capture_end());
}
-ArrayRef<VarDecl *>
-LambdaExpr::getCaptureInitIndexVars(const_capture_init_iterator Iter) const {
- assert(HasArrayIndexVars && "No array index-var data?");
-
- unsigned Index = Iter - capture_init_begin();
- assert(Index < getLambdaClass()->getLambdaData().NumCaptures &&
- "Capture index out-of-range");
- VarDecl *const *IndexVars = getArrayIndexVars();
- const unsigned *IndexStarts = getArrayIndexStarts();
- return llvm::makeArrayRef(IndexVars + IndexStarts[Index],
- IndexVars + IndexStarts[Index + 1]);
-}
-
CXXRecordDecl *LambdaExpr::getLambdaClass() const {
return getType()->getAsCXXRecordDecl();
}
isBaseVirtual);
}
-/// Initialize a member of aggregate type using the given expression
-/// as an initializer.
-///
-/// The member may be an array. If so:
-/// - the destination l-value will be a pointer of the *base* element type,
-/// - ArrayIndexVar will be a pointer to a variable containing the current
-/// index within the destination array, and
-/// - ArrayIndexes will be an array of index variables, one for each level
-/// of array nesting, which will need to be updated as appropriate for the
-/// array structure.
-///
-/// On an array, this function will invoke itself recursively. Each time,
-/// it drills into one nesting level of the member type and sets up a
-/// loop updating the appropriate array index variable.
-static void EmitAggMemberInitializer(CodeGenFunction &CGF,
- LValue LHS,
- Expr *Init,
- Address ArrayIndexVar,
- QualType T,
- ArrayRef<VarDecl *> ArrayIndexes,
- unsigned Index) {
- assert(ArrayIndexVar.isValid() == (ArrayIndexes.size() != 0));
-
- if (Index == ArrayIndexes.size()) {
- LValue LV = LHS;
-
- Optional<CodeGenFunction::RunCleanupsScope> Scope;
-
- if (ArrayIndexVar.isValid()) {
- // When we're processing an array, the temporaries from each
- // element's construction are destroyed immediately.
- Scope.emplace(CGF);
-
- // If we have an array index variable, load it and use it as an offset.
- // Then, increment the value.
- llvm::Value *Dest = LHS.getPointer();
- llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
- Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
- llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
- Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
- CGF.Builder.CreateStore(Next, ArrayIndexVar);
-
- // Update the LValue.
- CharUnits EltSize = CGF.getContext().getTypeSizeInChars(T);
- CharUnits Align = LV.getAlignment().alignmentOfArrayElement(EltSize);
- LV.setAddress(Address(Dest, Align));
-
- // Enter a partial-array EH cleanup to destroy previous members
- // of the array if this initialization throws.
- if (CGF.CGM.getLangOpts().Exceptions) {
- if (auto DtorKind = T.isDestructedType()) {
- if (CGF.needsEHCleanup(DtorKind)) {
- CGF.pushRegularPartialArrayCleanup(LHS.getPointer(),
- LV.getPointer(), T,
- LV.getAlignment(),
- CGF.getDestroyer(DtorKind));
- }
- }
- }
- }
-
- switch (CGF.getEvaluationKind(T)) {
- case TEK_Scalar:
- CGF.EmitScalarInit(Init, /*decl*/ nullptr, LV, false);
- break;
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
- break;
- case TEK_Aggregate: {
- AggValueSlot Slot =
- AggValueSlot::forLValue(LV,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
-
- CGF.EmitAggExpr(Init, Slot);
- break;
- }
- }
-
- return;
- }
-
- const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
- assert(Array && "Array initialization without the array type?");
- Address IndexVar = CGF.GetAddrOfLocalVar(ArrayIndexes[Index]);
-
- // Initialize this index variable to zero.
- llvm::Value* Zero
- = llvm::Constant::getNullValue(IndexVar.getElementType());
- CGF.Builder.CreateStore(Zero, IndexVar);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
-
- CGF.EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements) fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = Array->getSize().getZExtValue();
- llvm::Value *Counter = CGF.Builder.CreateLoad(IndexVar);
- llvm::Value *NumElementsPtr =
- llvm::ConstantInt::get(Counter->getType(), NumElements);
- llvm::Value *IsLess = CGF.Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
-
- // If the condition is true, execute the body.
- CGF.Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- CGF.EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
-
- // Inside the loop body recurse to emit the inner loop or, eventually, the
- // constructor call.
- EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
- Array->getElementType(), ArrayIndexes, Index + 1);
-
- CGF.EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = CGF.Builder.CreateLoad(IndexVar);
- NextVal = CGF.Builder.CreateAdd(Counter, NextVal, "inc");
- CGF.Builder.CreateStore(NextVal, IndexVar);
-
- // Finally, branch back up to the condition for the next iteration.
- CGF.EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- CGF.EmitBlock(AfterFor, true);
-}
-
static bool isMemcpyEquivalentSpecialMember(const CXXMethodDecl *D) {
auto *CD = dyn_cast<CXXConstructorDecl>(D);
if (!(CD && CD->isCopyOrMoveConstructor()) &&
}
}
- ArrayRef<VarDecl *> ArrayIndexes;
- if (MemberInit->getNumArrayIndices())
- ArrayIndexes = MemberInit->getArrayIndices();
- CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes);
+ CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit());
}
void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
- Expr *Init, ArrayRef<VarDecl *> ArrayIndexes) {
+ Expr *Init) {
QualType FieldType = Field->getType();
switch (getEvaluationKind(FieldType)) {
case TEK_Scalar:
EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
break;
case TEK_Aggregate: {
- Address ArrayIndexVar = Address::invalid();
- if (ArrayIndexes.size()) {
- // The LHS is a pointer to the first object we'll be constructing, as
- // a flat array.
- QualType BaseElementTy = getContext().getBaseElementType(FieldType);
- llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- Address BaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- LHS = MakeAddrLValue(BaseAddrPtr, BaseElementTy);
-
- // Create an array index that will be used to walk over all of the
- // objects we're constructing.
- ArrayIndexVar = CreateMemTemp(getContext().getSizeType(), "object.index");
- llvm::Value *Zero =
- llvm::Constant::getNullValue(ArrayIndexVar.getElementType());
- Builder.CreateStore(Zero, ArrayIndexVar);
-
- // Emit the block variables for the array indices, if any.
- for (unsigned I = 0, N = ArrayIndexes.size(); I != N; ++I)
- EmitAutoVarDecl(*ArrayIndexes[I]);
- }
-
- EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
- ArrayIndexes, 0);
+ AggValueSlot Slot =
+ AggValueSlot::forLValue(LHS,
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(Init, Slot);
+ break;
}
}
llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getPointer(), indices,
"arrayinit.begin");
- QualType elementType = E->getSubExpr()->getType();
+ QualType elementType =
+ CGF.getContext().getAsArrayType(E->getType())->getElementType();
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
destPtr.getAlignment().alignmentOfArrayElement(elementSize);
- // Prepare for a cleanup.
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- Address endOfInit = Address::invalid();
- EHScopeStack::stable_iterator cleanup;
- llvm::Instruction *cleanupDominator = nullptr;
- if (CGF.needsEHCleanup(dtorKind)) {
- endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
- "arrayinit.endOfInit");
- CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
- elementAlign,
- CGF.getDestroyer(dtorKind));
- cleanup = CGF.EHStack.stable_begin();
- } else {
- dtorKind = QualType::DK_none;
- }
-
llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
index->addIncoming(zero, entryBB);
llvm::Value *element = Builder.CreateInBoundsGEP(begin, index);
- // Tell the EH cleanup that we finished with the last element.
- if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
+ // Prepare for a cleanup.
+ QualType::DestructionKind dtorKind = elementType.isDestructedType();
+ EHScopeStack::stable_iterator cleanup;
+ if (CGF.needsEHCleanup(dtorKind)) {
+ CGF.pushRegularPartialArrayCleanup(
+ begin, element, elementType, elementAlign, CGF.getDestroyer(dtorKind));
+ cleanup = CGF.EHStack.stable_begin();
+ } else {
+ dtorKind = QualType::DK_none;
+ }
// Emit the actual filler expression.
{
+ // Temporaries created in an array initialization loop are destroyed
+ // at the end of each iteration.
+ CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
CodeGenFunction::ArrayInitLoopExprScope Scope(CGF, index);
LValue elementLV =
CGF.MakeAddrLValue(Address(element, elementAlign), elementType);
CGF.EmitBlock(endBB);
// Leave the partial-array cleanup if we entered one.
- if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
+ if (dtorKind)
+ CGF.DeactivateCleanupBlock(cleanup, index);
}
void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
auto VAT = CurField->getCapturedVLAType();
EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
} else {
- ArrayRef<VarDecl *> ArrayIndexes;
- if (CurField->getType()->isArrayType())
- ArrayIndexes = E->getCaptureInitIndexVars(i);
- EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ EmitInitializerForField(*CurField, LV, *i);
}
}
}
auto VAT = CurField->getCapturedVLAType();
EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
} else {
- EmitInitializerForField(*CurField, LV, *I, None);
+ EmitInitializerForField(*CurField, LV, *I);
}
}
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
FunctionArgList &Args);
- void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init,
- ArrayRef<VarDecl *> ArrayIndexes);
+ void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init);
/// Struct with all informations about dynamic [sub]class needed to set vptr.
struct VPtr {
CtorArg = CastForMoving(SemaRef, CtorArg.get());
}
- // When the field we are copying is an array, create index variables for
- // each dimension of the array. We use these index variables to subscript
- // the source array, and other clients (e.g., CodeGen) will perform the
- // necessary iteration with these index variables.
- SmallVector<VarDecl *, 4> IndexVariables;
- QualType BaseType = Field->getType();
- QualType SizeType = SemaRef.Context.getSizeType();
- bool InitializingArray = false;
- while (const ConstantArrayType *Array
- = SemaRef.Context.getAsConstantArrayType(BaseType)) {
- InitializingArray = true;
- // Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = nullptr;
- {
- SmallString<8> Str;
- llvm::raw_svector_ostream OS(Str);
- OS << "__i" << IndexVariables.size();
- IterationVarName = &SemaRef.Context.Idents.get(OS.str());
- }
- VarDecl *IterationVar
- = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc,
- IterationVarName, SizeType,
- SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None);
- IndexVariables.push_back(IterationVar);
-
- // Create a reference to the iteration variable.
- ExprResult IterationVarRef
- = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
- assert(!IterationVarRef.isInvalid() &&
- "Reference to invented variable cannot fail!");
- IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.get());
- assert(!IterationVarRef.isInvalid() &&
- "Conversion of invented variable cannot fail!");
-
- // Subscript the array with this iteration variable.
- CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.get(), Loc,
- IterationVarRef.get(),
- Loc);
- if (CtorArg.isInvalid())
- return true;
-
- BaseType = Array->getElementType();
- }
-
- // The array subscript expression is an lvalue, which is wrong for moving.
- if (Moving && InitializingArray)
- CtorArg = CastForMoving(SemaRef, CtorArg.get());
+ InitializedEntity Entity =
+ Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr,
+ /*Implicit*/ true)
+ : InitializedEntity::InitializeMember(Field, nullptr,
+ /*Implicit*/ true);
- // Construct the entity that we will be initializing. For an array, this
- // will be first element in the array, which may require several levels
- // of array-subscript entities.
- SmallVector<InitializedEntity, 4> Entities;
- Entities.reserve(1 + IndexVariables.size());
- if (Indirect)
- Entities.push_back(InitializedEntity::InitializeMember(Indirect));
- else
- Entities.push_back(InitializedEntity::InitializeMember(Field));
- for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
- Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context,
- 0,
- Entities.back()));
-
// Direct-initialize to use the copy constructor.
InitializationKind InitKind =
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
Expr *CtorArgE = CtorArg.getAs<Expr>();
- InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
- CtorArgE);
-
- ExprResult MemberInit
- = InitSeq.Perform(SemaRef, Entities.back(), InitKind,
- MultiExprArg(&CtorArgE, 1));
+ InitializationSequence InitSeq(SemaRef, Entity, InitKind, CtorArgE);
+ ExprResult MemberInit =
+ InitSeq.Perform(SemaRef, Entity, InitKind, MultiExprArg(&CtorArgE, 1));
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
return true;
- if (Indirect) {
- assert(IndexVariables.size() == 0 &&
- "Indirect field improperly initialized");
- CXXMemberInit
- = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
- Loc, Loc,
- MemberInit.getAs<Expr>(),
- Loc);
- } else
- CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc,
- Loc, MemberInit.getAs<Expr>(),
- Loc,
- IndexVariables.data(),
- IndexVariables.size());
+ if (Indirect)
+ CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(
+ SemaRef.Context, Indirect, Loc, Loc, MemberInit.getAs<Expr>(), Loc);
+ else
+ CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(
+ SemaRef.Context, Field, Loc, Loc, MemberInit.getAs<Expr>(), Loc);
return false;
}
SemaRef.Context.getBaseElementType(Field->getType());
if (FieldBaseElementType->isRecordType()) {
- InitializedEntity InitEntity
- = Indirect? InitializedEntity::InitializeMember(Indirect)
- : InitializedEntity::InitializeMember(Field);
+ InitializedEntity InitEntity =
+ Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr,
+ /*Implicit*/ true)
+ : InitializedEntity::InitializeMember(Field, nullptr,
+ /*Implicit*/ true);
InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
InitializedEntity::InitializeElement(S.Context, 0, Entity);
QualType InitEltT =
Context.getAsArrayType(Initializer->getType())->getElementType();
- OpaqueValueExpr OVE(SourceLocation(), InitEltT,
- Initializer->getValueKind());
+ OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT,
+ Initializer->getValueKind(),
+ Initializer->getObjectKind());
Expr *OVEAsExpr = &OVE;
InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList,
TreatUnavailableAsInvalid);
}
static ExprResult performLambdaVarCaptureInitialization(
- Sema &S, LambdaScopeInfo::Capture &Capture,
- FieldDecl *Field,
- SmallVectorImpl<VarDecl *> &ArrayIndexVars,
- SmallVectorImpl<unsigned> &ArrayIndexStarts) {
+ Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {
assert(Capture.isVariableCapture() && "not a variable capture");
auto *Var = Capture.getVariable();
return ExprError();
Expr *Ref = RefResult.get();
- QualType FieldType = Field->getType();
-
- // When the variable has array type, create index variables for each
- // dimension of the array. We use these index variables to subscript
- // the source array, and other clients (e.g., CodeGen) will perform
- // the necessary iteration with these index variables.
- //
- // FIXME: This is dumb. Add a proper AST representation for array
- // copy-construction and use it here.
- SmallVector<VarDecl *, 4> IndexVariables;
- QualType BaseType = FieldType;
- QualType SizeType = S.Context.getSizeType();
- ArrayIndexStarts.push_back(ArrayIndexVars.size());
- while (const ConstantArrayType *Array
- = S.Context.getAsConstantArrayType(BaseType)) {
- // Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = nullptr;
- {
- SmallString<8> Str;
- llvm::raw_svector_ostream OS(Str);
- OS << "__i" << IndexVariables.size();
- IterationVarName = &S.Context.Idents.get(OS.str());
- }
- VarDecl *IterationVar = VarDecl::Create(
- S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType,
- S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None);
- IterationVar->setImplicit();
- IndexVariables.push_back(IterationVar);
- ArrayIndexVars.push_back(IterationVar);
-
- // Create a reference to the iteration variable.
- ExprResult IterationVarRef =
- S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
- assert(!IterationVarRef.isInvalid() &&
- "Reference to invented variable cannot fail!");
- IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
- assert(!IterationVarRef.isInvalid() &&
- "Conversion of invented variable cannot fail!");
-
- // Subscript the array with this iteration variable.
- ExprResult Subscript =
- S.CreateBuiltinArraySubscriptExpr(Ref, Loc, IterationVarRef.get(), Loc);
- if (Subscript.isInvalid())
- return ExprError();
-
- Ref = Subscript.get();
- BaseType = Array->getElementType();
- }
-
- // Construct the entity that we will be initializing. For an array, this
- // will be first element in the array, which may require several levels
- // of array-subscript entities.
- SmallVector<InitializedEntity, 4> Entities;
- Entities.reserve(1 + IndexVariables.size());
- Entities.push_back(InitializedEntity::InitializeLambdaCapture(
- Var->getIdentifier(), FieldType, Loc));
- for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
- Entities.push_back(
- InitializedEntity::InitializeElement(S.Context, 0, Entities.back()));
-
+ auto Entity = InitializedEntity::InitializeLambdaCapture(
+ Var->getIdentifier(), Field->getType(), Loc);
InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, Entities.back(), InitKind, Ref);
- return Init.Perform(S, Entities.back(), InitKind, Ref);
+ InitializationSequence Init(S, Entity, InitKind, Ref);
+ return Init.Perform(S, Entity, InitKind, Ref);
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
bool ExplicitResultType;
CleanupInfo LambdaCleanup;
bool ContainsUnexpandedParameterPack;
- SmallVector<VarDecl *, 4> ArrayIndexVars;
- SmallVector<unsigned, 4> ArrayIndexStarts;
{
CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
LambdaCapture(From.getLocation(), IsImplicit,
From.isCopyCapture() ? LCK_StarThis : LCK_This));
CaptureInits.push_back(From.getInitExpr());
- ArrayIndexStarts.push_back(ArrayIndexVars.size());
continue;
}
if (From.isVLATypeCapture()) {
Captures.push_back(
LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
CaptureInits.push_back(nullptr);
- ArrayIndexStarts.push_back(ArrayIndexVars.size());
continue;
}
Var, From.getEllipsisLoc()));
Expr *Init = From.getInitExpr();
if (!Init) {
- auto InitResult = performLambdaVarCaptureInitialization(
- *this, From, *CurField, ArrayIndexVars, ArrayIndexStarts);
+ auto InitResult =
+ performLambdaVarCaptureInitialization(*this, From, *CurField);
if (InitResult.isInvalid())
return ExprError();
Init = InitResult.get();
- } else {
- ArrayIndexStarts.push_back(ArrayIndexVars.size());
}
CaptureInits.push_back(Init);
}
CaptureDefault, CaptureDefaultLoc,
Captures,
ExplicitParams, ExplicitResultType,
- CaptureInits, ArrayIndexVars,
- ArrayIndexStarts, EndLoc,
+ CaptureInits, EndLoc,
ContainsUnexpandedParameterPack);
// If the lambda expression's call operator is not explicitly marked constexpr
// and we are not in a dependent context, analyze the call operator to infer
Expr *Init = ReadExpr(F);
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
- bool IsWritten = Record[Idx++];
- unsigned SourceOrderOrNumArrayIndices;
- SmallVector<VarDecl *, 8> Indices;
- if (IsWritten) {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- } else {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- Indices.reserve(SourceOrderOrNumArrayIndices);
- for (unsigned i = 0; i != SourceOrderOrNumArrayIndices; ++i)
- Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
- }
CXXCtorInitializer *BOMInit;
- if (Type == CTOR_INITIALIZER_BASE) {
+ if (Type == CTOR_INITIALIZER_BASE)
BOMInit = new (Context)
CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init,
RParenLoc, MemberOrEllipsisLoc);
- } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ else if (Type == CTOR_INITIALIZER_DELEGATING)
BOMInit = new (Context)
CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc);
- } else if (IsWritten) {
- if (Member)
- BOMInit = new (Context) CXXCtorInitializer(
- Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc);
- else
- BOMInit = new (Context)
- CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc);
- } else {
- if (IndirectMember) {
- assert(Indices.empty() && "Indirect field improperly initialized");
- BOMInit = new (Context)
- CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc);
- } else {
- BOMInit = CXXCtorInitializer::Create(
- Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc,
- Indices.data(), Indices.size());
- }
+ else if (Member)
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc,
+ Init, RParenLoc);
+ else
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+
+ if (bool IsWritten = Record[Idx++]) {
+ unsigned SourceOrder = Record[Idx++];
+ BOMInit->setSourceOrder(SourceOrder);
}
- if (IsWritten)
- BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
CtorInitializers[i] = BOMInit;
}
VisitExpr(E);
unsigned NumCaptures = Record[Idx++];
assert(NumCaptures == E->NumCaptures);(void)NumCaptures;
- unsigned NumArrayIndexVars = Record[Idx++];
E->IntroducerRange = ReadSourceRange(Record, Idx);
E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record[Idx++]);
E->CaptureDefaultLoc = ReadSourceLocation(Record, Idx);
CEnd = E->capture_init_end();
C != CEnd; ++C)
*C = Reader.ReadSubExpr();
-
- // Read array capture index variables.
- if (NumArrayIndexVars > 0) {
- unsigned *ArrayIndexStarts = E->getArrayIndexStarts();
- for (unsigned I = 0; I != NumCaptures + 1; ++I)
- ArrayIndexStarts[I] = Record[Idx++];
-
- VarDecl **ArrayIndexVars = E->getArrayIndexVars();
- for (unsigned I = 0; I != NumArrayIndexVars; ++I)
- ArrayIndexVars[I] = ReadDeclAs<VarDecl>(Record, Idx);
- }
}
void
case EXPR_LAMBDA: {
unsigned NumCaptures = Record[ASTStmtReader::NumExprFields];
- unsigned NumArrayIndexVars = Record[ASTStmtReader::NumExprFields + 1];
- S = LambdaExpr::CreateDeserialized(Context, NumCaptures,
- NumArrayIndexVars);
+ S = LambdaExpr::CreateDeserialized(Context, NumCaptures);
break;
}
}
Writer.AddSourceLocation(Init->getLParenLoc());
Writer.AddSourceLocation(Init->getRParenLoc());
Writer.push_back(Init->isWritten());
- if (Init->isWritten()) {
+ if (Init->isWritten())
Writer.push_back(Init->getSourceOrder());
- } else {
- Writer.push_back(Init->getNumArrayIndices());
- for (auto *VD : Init->getArrayIndices())
- Writer.AddDeclRef(VD);
- }
}
return Writer.Emit(serialization::DECL_CXX_CTOR_INITIALIZERS);
void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
VisitExpr(E);
Record.push_back(E->NumCaptures);
- unsigned NumArrayIndexVars = 0;
- if (E->HasArrayIndexVars)
- NumArrayIndexVars = E->getArrayIndexStarts()[E->NumCaptures];
- Record.push_back(NumArrayIndexVars);
Record.AddSourceRange(E->IntroducerRange);
Record.push_back(E->CaptureDefault); // FIXME: stable encoding
Record.AddSourceLocation(E->CaptureDefaultLoc);
Record.AddStmt(*C);
}
- // Add array index variables, if any.
- if (NumArrayIndexVars) {
- Record.append(E->getArrayIndexStarts(),
- E->getArrayIndexStarts() + E->NumCaptures + 1);
- VarDecl **ArrayIndexVars = E->getArrayIndexVars();
- for (unsigned I = 0; I != NumArrayIndexVars; ++I)
- Record.AddDeclRef(ArrayIndexVars[I]);
- }
-
Code = serialization::EXPR_LAMBDA;
}
}
SVal InitVal;
- if (BMI->getNumArrayIndices() > 0) {
+ if (Init->getType()->isArrayType()) {
// Handle arrays of trivial type. We can represent this with a
// primitive load/copy from the base array region.
const ArraySubscriptExpr *ASE;
if (Init.getAs<nonloc::LazyCompoundVal>())
return bindAggregate(B, R, Init);
- // Remaining case: explicit compound values.
-
if (Init.isUnknown())
- return setImplicitDefaultValue(B, R, ElementTy);
+ return bindAggregate(B, R, UnknownVal());
+ // Remaining case: explicit compound values.
const nonloc::CompoundVal& CV = Init.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
if (type->isIntegralOrEnumerationType())
return makeIntVal(0, type);
+ if (type->isArrayType() || type->isRecordType() || type->isVectorType() ||
+ type->isAnyComplexType())
+ return makeCompoundVal(type, BasicVals.getEmptySValList());
+
// FIXME: Handle floats.
- // FIXME: Handle structs.
return UnknownVal();
}
// CHECK-CTOR: call {{.*}} @_ZN1FC1EOS_
// CHECK-CTOR: call {{.*}} @_ZN1EC1EOS_
// array loop
-// CHECK-CTOR: br i1
// CHECK-CTOR: call {{.*}} @_ZN1FC1EOS_
+// CHECK-CTOR: br i1
// CHECK-CTOR: define linkonce_odr {{.*}} @_ZN1GC2EOS_
// CHECK-CTOR: call {{.*}} @_ZN1EC1EOS_
// CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_
// CHECK-PR10720-NOT: ret
- // CHECK-PR10720: load
- // CHECK-PR10720: icmp ult
- // CHECK-PR10720-NEXT: br i1
// CHECK-PR10720: call void @_ZN7PR107201XC1ERKS0_
- // CHECK-PR10720-NEXT: br label
+ // CHECK-PR10720: icmp eq
+ // CHECK-PR10720-NEXT: br i1
// CHECK-PR10720: ret void
// CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_
// CHECK-PR10720-NOT: ret
// CHECK-PR10720: load
- // CHECK-PR10720: icmp ult
- // CHECK-PR10720-NEXT: br i1
// CHECK-PR10720: call void @_ZN7PR107201XC1EOS0_
- // CHECK-PR10720-NEXT: br label
+ // CHECK-PR10720: icmp eq
+ // CHECK-PR10720-NEXT: br i1
// CHECK-PR10720: ret void
pair2(pair2&&) = default;
// CHECK: call void @_ZN1BC2ERS_
// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 28}}
// CHECK: call void @_ZN1BC1ERS_
-// CHECK: br
-// CHECK: {{icmp ult.*, 2}}
-// CHECK: {{icmp ult.*, 3}}
+// CHECK: br label
// CHECK: call void @_ZN1AC1Ev
// CHECK: call void @_ZN1CC1ERS_1A
// CHECK: call void @_ZN1AD1Ev
+// CHECK: {{icmp eq.*, 3}}
+// CHECK: br i1
+// CHECK: {{icmp eq.*, 2}}
+// CHECK: br i1
// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 300}}
// CHECK: ret void
// CHECK: ret i32
struct D { D(); D(const D&); int x; };
-int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
+int d(int x) { D y[10]; return [x,y] { return y[x].x; }(); }
// CHECK-LABEL: define i32 @_Z1di
// CHECK: call void @_ZN1DC1Ev
-// CHECK: icmp ult i64 %{{.*}}, 10
+// CHECK: br label
// CHECK: call void @_ZN1DC1ERKS_
+// CHECK: icmp eq i64 %{{.*}}, 10
+// CHECK: br i1
// CHECK: call i32 @"_ZZ1diENK3$_4clEv"
// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_4clEv"
// CHECK: load i32, i32*
// CHECK: ret i32
struct E { E(); E(const E&); ~E(); int x; };
-int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); }
+int e(E a, E b, bool cond) { return [a,b,cond](){ return (cond ? a : b).x; }(); }
// CHECK-LABEL: define i32 @_Z1e1ES_b
// CHECK: call void @_ZN1EC1ERKS_
// CHECK: invoke void @_ZN1EC1ERKS_
~A();
};
+ void after_init() noexcept;
+
// CHECK-LABEL: define void @_ZN7pr285954testEv()
void test() {
- // CHECK: [[ARRAY:%.*]] = alloca [3 x [5 x [[A:%.*]]]], align 1
- // CHECK: [[DESTIDX:%.*]] = alloca i64, align 8
- // CHECK: [[I0:%.*]] = alloca i64, align 8
- // CHECK: [[I1:%.*]] = alloca i64, align 8
+ // CHECK: %[[SRC:.*]] = alloca [3 x [5 x %[[A:.*]]]], align 1
A array[3][5];
- // CHECK: [[DESTBASE:%.*]] = bitcast [3 x [5 x [[A]]]]* {{.*}} to [[A]]*
- // CHECK: store i64 0, i64* [[DESTIDX]], align 8
- // CHECK: store i64 0, i64* [[I0]], align 8
+ // Skip over the initialization loop.
+ // CHECK: call {{.*}}after_init
+ after_init();
+
+ // CHECK: %[[DST_0:.*]] = getelementptr inbounds [3 x [5 x %[[A]]]], {{.*}}, i64 0, i64 0
// CHECK: br label
- // CHECK: icmp ult
- // CHECK: store i64 0, i64* [[I1]], align 8
+ // CHECK: %[[I:.*]] = phi i64 [ 0, %{{.*}} ], [ %[[I_NEXT:.*]], {{.*}} ]
+ // CHECK: %[[DST_I:.*]] = getelementptr {{.*}} [5 x %[[A]]]* %[[DST_0]], i64 %[[I]]
+ // CHECK: %[[SRC_I:.*]] = getelementptr {{.*}} [3 x [5 x %[[A]]]]* %[[SRC]], i64 0, i64 %[[I]]
+ //
+ // CHECK: %[[DST_I_0:.*]] = getelementptr {{.*}} [5 x %[[A]]]* %[[DST_I]], i64 0, i64 0
// CHECK: br label
- // CHECK: icmp ult
- // CHECK: [[T0:%.*]] = load i64, i64* [[DESTIDX]], align 8
- // CHECK: [[DEST:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DESTBASE]], i64 [[T0]]
+ // CHECK: %[[J:.*]] = phi i64 [ 0, %{{.*}} ], [ %[[J_NEXT:.*]], {{.*}} ]
+ // CHECK: %[[DST_I_J:.*]] = getelementptr {{.*}} %[[A]]* %[[DST_I_0]], i64 %[[J]]
+ // CHECK: %[[SRC_I_J:.*]] = getelementptr {{.*}} [5 x %[[A]]]* %[[SRC_I]], i64 0, i64 %[[J]]
+ //
// CHECK: invoke void @_ZN7pr285954TempC1Ev
// CHECK: invoke void @_ZN7pr285951AC1ERKS0_RKNS_4TempE
// CHECK: invoke void @_ZN7pr285954TempD1Ev
+ //
+ // CHECK: add nuw i64 %[[J]], 1
+ // CHECK: icmp eq
+ // CHECK: br i1
+ //
+ // CHECK: add nuw i64 %[[I]], 1
+ // CHECK: icmp eq
+ // CHECK: br i1
+ //
+ // CHECK: ret void
+ //
// CHECK: landingpad
// CHECK: landingpad
- // CHECK: br label [[CLEANUP:%.*]]{{$}}
+ // CHECK: br label %[[CLEANUP:.*]]{{$}}
// CHECK: landingpad
// CHECK: invoke void @_ZN7pr285954TempD1Ev
- // CHECK: br label [[CLEANUP]]
- // CHECK: icmp eq [[A]]* [[DESTBASE]], [[DEST]]
- // CHECK: [[T0:%.*]] = phi [[A]]*
- // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[T0]], i64 -1
- // CHECK: call void @_ZN7pr285951AD1Ev([[A]]* [[T1]])
- // CHECK: icmp eq [[A]]* [[T1]], [[DESTBASE]]
+ // CHECK: br label %[[CLEANUP]]
+ //
+ // FIXME: only emit a single cleanup loop here
+ // CHECK: [[CLEANUP]]:
+ // CHECK: icmp eq %[[A]]* %[[DST_I_0]], %[[DST_I_J]]
+ // CHECK: %[[T0:.*]] = phi %[[A]]*
+ // CHECK: %[[T1:.*]] = getelementptr inbounds %[[A]], %[[A]]* %[[T0]], i64 -1
+ // CHECK: call void @_ZN7pr285951AD1Ev(%[[A]]* %[[T1]])
+ // CHECK: icmp eq %[[A]]* %[[T1]], %[[DST_I_0]]
+ //
+ // CHECK: %[[BEGIN:.*]] = getelementptr {{.*}} %[[DST_0]], i64 0, i64 0
+ // CHECK: %[[END:.*]] = getelementptr {{.*}} %[[DST_I]], i64 0, i64 0
+ // CHECK: icmp eq %[[A]]* %[[BEGIN]], %[[END]]
+ // CHECK: %[[T0:.*]] = phi %[[A]]*
+ // CHECK: %[[T1:.*]] = getelementptr inbounds %[[A]], %[[A]]* %[[T0]], i64 -1
+ // CHECK: call void @_ZN7pr285951AD1Ev(%[[A]]* %[[T1]])
+ // CHECK: icmp eq %[[A]]* %[[T1]], %[[BEGIN]]
(void) [array]{};
-
- // Skip over the initialization loop.
- // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [5 x [[A]]]], [3 x [5 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
}
}
// Implicitly-generated copy constructor for ObjCArrayMember
// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCArrayMemberC2ERKS_
-// CHECK: br i1
// CHECK: call i8* @objc_retain
// CHECK-NEXT: store i8*
-// CHECK-NEXT: br label
+// CHECK: br i1
// CHECK: ret
// Implicitly-generated default constructor for ObjCBlockMember
// CHECK: call void @_ZN1BC2ERS_
// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
// CHECK: call void @_ZN1BC1ERS_
-// CHECK: br
-// CHECK: {{icmp ult.*, 2}}
-// CHECK: {{icmp ult.*, 3}}
+// CHECK: br label
// CHECK: call void @_ZN1AC1Ev
// CHECK: call void @_ZN1CC1ERS_1A
// CHECK: call void @_ZN1AD1Ev
+// CHECK: {{icmp eq.*, 3}}
+// CHECK: br i1
+// CHECK: {{icmp eq.*, 2}}
+// CHECK: br i1
// CHECK: {{call.*@objc_memmove_collectable}}
// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
// CHECK: ret void
};
static_assert(ArrayRVal().elems[3].f() == 0, "");
+namespace CopyCtor {
+ struct A {
+ constexpr A() {}
+ constexpr A(const A &) {}
+ };
+ struct B {
+ A a;
+ int arr[10];
+ };
+ constexpr B b{{}, {1, 2, 3, 4, 5}};
+ constexpr B c = b;
+ static_assert(c.arr[2] == 3, "");
+ static_assert(c.arr[7] == 0, "");
+}
+
constexpr int selfref[2][2][2] = {
selfref[1][1][1] + 1, selfref[0][0][0] + 1,
selfref[1][0][1] + 1, selfref[0][1][0] + 1,
"};\n"));
}
-// Check to ensure that VarDecls are visited.
-class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
-public:
- bool VisitVarDecl(VarDecl *VD) {
- Match(VD->getNameAsString(), VD->getLocStart());
- return true;
- }
-};
-
-TEST(RecursiveASTVisitor, ArrayInitializersAreVisited) {
- VarDeclVisitor Visitor;
- Visitor.ExpectMatch("__i0", 1, 8);
- EXPECT_TRUE(
- Visitor.runOver("struct MyClass {\n"
- " int c[1];\n"
- " static MyClass Create() { return MyClass(); }\n"
- "};\n"));
-}
-
// Check to ensure that implicit default argument expressions are visited.
class IntegerLiteralVisitor
: public ExpectedLocationVisitor<IntegerLiteralVisitor> {