Add two new AST nodes to represent initialization of an array in terms of

initialization of each array element:

 * ArrayInitLoopExpr is a prvalue of array type with two subexpressions:
   a common expression (an OpaqueValueExpr) that represents the up-front
   computation of the source of the initialization, and a subexpression
   representing a per-element initializer
 * ArrayInitIndexExpr is a prvalue of type size_t representing the current
   position in the loop

This will be used to replace the creation of explicit index variables in lambda
capture of arrays and copy/move construction of classes with array elements,
and also C++17 structured bindings of arrays by value (which inexplicably allow
copying an array by value, unlike all of C++'s other array declarations).

No uses of these nodes are introduced by this change, however.

llvm-svn: 289413
This commit is contained in:
Richard Smith 2016-12-12 02:53:20 +00:00
parent 8c9cc8c86b
commit 410306bf6e
22 changed files with 545 additions and 29 deletions

View File

@ -4333,6 +4333,98 @@ public:
}
};
/// \brief Represents a loop initializing the elements of an array.
///
/// The need to initialize the elements of an array occurs in a number of
/// contexts:
///
/// * in the implicit copy/move constructor for a class with an array member
/// * when a lambda-expression captures an array by value
/// * when a decomposition declaration decomposes an array
///
/// There are two subexpressions: a common expression (the source array)
/// that is evaluated once up-front, and a per-element initializer that
/// runs once for each array element.
///
/// Within the per-element initializer, the common expression may be referenced
/// via an OpaqueValueExpr, and the current index may be obtained via an
/// ArrayInitIndexExpr.
class ArrayInitLoopExpr : public Expr {
Stmt *SubExprs[2];
explicit ArrayInitLoopExpr(EmptyShell Empty)
: Expr(ArrayInitLoopExprClass, Empty), SubExprs{} {}
public:
explicit ArrayInitLoopExpr(QualType T, Expr *CommonInit, Expr *ElementInit)
: Expr(ArrayInitLoopExprClass, T, VK_RValue, OK_Ordinary, false,
CommonInit->isValueDependent() || ElementInit->isValueDependent(),
T->isInstantiationDependentType(),
CommonInit->containsUnexpandedParameterPack() ||
ElementInit->containsUnexpandedParameterPack()),
SubExprs{CommonInit, ElementInit} {}
/// Get the common subexpression shared by all initializations (the source
/// array).
OpaqueValueExpr *getCommonExpr() const {
return cast<OpaqueValueExpr>(SubExprs[0]);
}
/// Get the initializer to use for each array element.
Expr *getSubExpr() const { return cast<Expr>(SubExprs[1]); }
llvm::APInt getArraySize() const {
return cast<ConstantArrayType>(getType()->castAsArrayTypeUnsafe())
->getSize();
}
static bool classof(const Stmt *S) {
return S->getStmtClass() == ArrayInitLoopExprClass;
}
SourceLocation getLocStart() const LLVM_READONLY {
return getCommonExpr()->getLocStart();
}
SourceLocation getLocEnd() const LLVM_READONLY {
return getCommonExpr()->getLocEnd();
}
child_range children() {
return child_range(SubExprs, SubExprs + 2);
}
friend class ASTReader;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
/// \brief Represents the index of the current element of an array being
/// initialized by an ArrayInitLoopExpr. This can only appear within the
/// subexpression of an ArrayInitLoopExpr.
class ArrayInitIndexExpr : public Expr {
explicit ArrayInitIndexExpr(EmptyShell Empty)
: Expr(ArrayInitIndexExprClass, Empty) {}
public:
explicit ArrayInitIndexExpr(QualType T)
: Expr(ArrayInitIndexExprClass, T, VK_RValue, OK_Ordinary,
false, false, false, false) {}
static bool classof(const Stmt *S) {
return S->getStmtClass() == ArrayInitIndexExprClass;
}
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
child_range children() {
return child_range(child_iterator(), child_iterator());
}
friend class ASTReader;
friend class ASTStmtReader;
};
/// \brief Represents an implicitly-generated value initialization of
/// an object of a given type.
///

View File

@ -2399,6 +2399,8 @@ DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
DEF_TRAVERSE_STMT(GNUNullExpr, {})
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
DEF_TRAVERSE_STMT(NoInitExpr, {})
DEF_TRAVERSE_STMT(ArrayInitLoopExpr, {})
DEF_TRAVERSE_STMT(ArrayInitIndexExpr, {})
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {

View File

@ -85,6 +85,8 @@ def DesignatedInitExpr : DStmt<Expr>;
def DesignatedInitUpdateExpr : DStmt<Expr>;
def ImplicitValueInitExpr : DStmt<Expr>;
def NoInitExpr : DStmt<Expr>;
def ArrayInitLoopExpr : DStmt<Expr>;
def ArrayInitIndexExpr : DStmt<Expr>;
def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;

View File

@ -120,6 +120,16 @@ private:
bool NRVO;
};
struct VD {
/// \brief The VarDecl, FieldDecl, or BindingDecl being initialized.
ValueDecl *VariableOrMember;
/// \brief When Kind == EK_Member, whether this is an implicit member
/// initialization in a copy or move constructor. These can perform array
/// copies.
bool IsImplicitFieldInit;
};
struct C {
/// \brief The name of the variable being captured by an EK_LambdaCapture.
IdentifierInfo *VarID;
@ -129,9 +139,8 @@ private:
};
union {
/// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the VarDecl,
/// FieldDecl or BindingDecl, respectively.
ValueDecl *VariableOrMember;
/// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the variable.
VD Variable;
/// \brief When Kind == EK_RelatedResult, the ObjectiveC method where
/// result type was implicitly changed to accommodate ARC semantics.
@ -165,7 +174,7 @@ private:
/// \brief Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
: Kind(EK), Parent(nullptr), Type(Var->getType()),
ManglingNumber(0), VariableOrMember(Var) { }
ManglingNumber(0), Variable{Var, false} { }
/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
@ -179,9 +188,11 @@ private:
}
/// \brief Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent,
bool Implicit)
: Kind(EK_Member), Parent(Parent), Type(Member->getType()),
ManglingNumber(0), VariableOrMember(Member) { }
ManglingNumber(0), Variable{Member, Implicit} {
}
/// \brief Create the initialization entity for an array element.
InitializedEntity(ASTContext &Context, unsigned Index,
@ -299,15 +310,17 @@ public:
/// \brief Create the initialization entity for a member subobject.
static InitializedEntity
InitializeMember(FieldDecl *Member,
const InitializedEntity *Parent = nullptr) {
return InitializedEntity(Member, Parent);
const InitializedEntity *Parent = nullptr,
bool Implicit = false) {
return InitializedEntity(Member, Parent, Implicit);
}
/// \brief Create the initialization entity for a member subobject.
static InitializedEntity
InitializeMember(IndirectFieldDecl *Member,
const InitializedEntity *Parent = nullptr) {
return InitializedEntity(Member->getAnonField(), Parent);
const InitializedEntity *Parent = nullptr,
bool Implicit = false) {
return InitializedEntity(Member->getAnonField(), Parent, Implicit);
}
/// \brief Create the initialization entity for an array element.
@ -401,6 +414,12 @@ public:
getType()->getAsArrayTypeUnsafe());
}
/// \brief Is this the implicit initialization of a member of a class from
/// a defaulted constructor?
bool isImplicitMemberInitializer() const {
return getKind() == EK_Member && Variable.IsImplicitFieldInit;
}
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
@ -708,6 +727,10 @@ public:
/// \brief An initialization that "converts" an Objective-C object
/// (not a point to an object) to another Objective-C object type.
SK_ObjCObjectConversion,
/// \brief Array indexing for initialization by elementwise copy.
SK_ArrayLoopIndex,
/// \brief Array initialization by elementwise copy.
SK_ArrayLoopInit,
/// \brief Array initialization (from an array rvalue).
/// This is a GNU C extension.
SK_ArrayInit,
@ -1096,6 +1119,9 @@ public:
/// always a no-op.
void AddObjCObjectConversionStep(QualType T);
/// \brief Add an array initialization loop step.
void AddArrayInitLoopStep(QualType T, QualType EltTy);
/// \brief Add an array initialization step.
void AddArrayInitStep(QualType T);

View File

@ -1292,10 +1292,14 @@ namespace clang {
EXPR_DESIGNATED_INIT,
/// \brief A DesignatedInitUpdateExpr record.
EXPR_DESIGNATED_INIT_UPDATE,
/// \brief An ImplicitValueInitExpr record.
EXPR_IMPLICIT_VALUE_INIT,
/// \brief An NoInitExpr record.
EXPR_NO_INIT,
/// \brief An ArrayInitLoopExpr record.
EXPR_ARRAY_INIT_LOOP,
/// \brief An ArrayInitIndexExpr record.
EXPR_ARRAY_INIT_INDEX,
/// \brief An ImplicitValueInitExpr record.
EXPR_IMPLICIT_VALUE_INIT,
/// \brief A VAArgExpr record.
EXPR_VA_ARG,
/// \brief An AddrLabelExpr record.

View File

@ -517,6 +517,8 @@ namespace {
void VisitFloatingLiteral(const FloatingLiteral *Node);
void VisitStringLiteral(const StringLiteral *Str);
void VisitInitListExpr(const InitListExpr *ILE);
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *ILE);
void VisitArrayInitIndexExpr(const ArrayInitIndexExpr *ILE);
void VisitUnaryOperator(const UnaryOperator *Node);
void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(const MemberExpr *Node);
@ -2024,6 +2026,14 @@ void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) {
}
}
void ASTDumper::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
VisitExpr(E);
}
void ASTDumper::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) {
VisitExpr(E);
}
void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
VisitExpr(Node);
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")

View File

@ -2899,6 +2899,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case UnaryExprOrTypeTraitExprClass:
case AddrLabelExprClass:
case GNUNullExprClass:
case ArrayInitIndexExprClass:
case NoInitExprClass:
case CXXBoolLiteralExprClass:
case CXXNullPtrLiteralExprClass:
@ -2975,6 +2976,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ExtVectorElementExprClass:
case DesignatedInitExprClass:
case DesignatedInitUpdateExprClass:
case ArrayInitLoopExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
case CXXStdInitializerListExprClass:

View File

@ -185,6 +185,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::AtomicExprClass:
case Expr::CXXFoldExprClass:
case Expr::ArrayInitLoopExprClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::CoyieldExprClass:

View File

@ -469,6 +469,10 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
/// The current array initialization index, if we're performing array
/// initialization.
uint64_t ArrayInitIndex = -1;
/// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
@ -803,6 +807,20 @@ namespace {
bool allowInvalidBaseExpr() const {
return EvalMode == EM_DesignatorFold;
}
class ArrayInitLoopIndex {
EvalInfo &Info;
uint64_t OuterIndex;
public:
ArrayInitLoopIndex(EvalInfo &Info)
: Info(Info), OuterIndex(Info.ArrayInitIndex) {
Info.ArrayInitIndex = 0;
}
~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
operator uint64_t&() { return Info.ArrayInitIndex; }
};
};
/// Object used to treat all foldable expressions as constant expressions.
@ -6190,6 +6208,7 @@ namespace {
return handleCallExpr(E, Result, &This);
}
bool VisitInitListExpr(const InitListExpr *E);
bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
@ -6272,6 +6291,35 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
FillerExpr) && Success;
}
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
if (E->getCommonExpr() &&
!Evaluate(Info.CurrentCall->createTemporary(E->getCommonExpr(), false),
Info, E->getCommonExpr()->getSourceExpr()))
return false;
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
uint64_t Elements = CAT->getSize().getZExtValue();
Result = APValue(APValue::UninitArray(), Elements, Elements);
LValue Subobject = This;
Subobject.addArray(Info, E, CAT);
bool Success = true;
for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) {
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
Info, Subobject, E->getSubExpr()) ||
!HandleLValueArrayAdjustment(Info, E, Subobject,
CAT->getElementType(), 1)) {
if (!Info.noteFailure())
return false;
Success = false;
}
}
return Success;
}
bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitCXXConstructExpr(E, This, &Result, E->getType());
}
@ -6427,6 +6475,16 @@ public:
bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) {
return Success(E->getValue(), E);
}
bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) {
if (Info.ArrayInitIndex == uint64_t(-1)) {
// We were asked to evaluate this subexpression independent of the
// enclosing ArrayInitLoopExpr. We can't do that.
Info.FFDiag(E);
return false;
}
return Success(Info.ArrayInitIndex, E);
}
// Note, GNU defines __null as an integer, not a pointer.
bool VisitGNUNullExpr(const GNUNullExpr *E) {
@ -9590,6 +9648,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ArrayInitLoopExprClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::ImplicitValueInitExprClass:

View File

@ -3301,6 +3301,8 @@ recurse:
case Expr::AddrLabelExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::ArrayInitLoopExprClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::ParenListExprClass:
case Expr::LambdaExprClass:

View File

@ -1705,6 +1705,18 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << "}";
}
void StmtPrinter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *Node) {
// There's no way to express this expression in any of our supported
// languages, so just emit something terse and (hopefully) clear.
OS << "{";
PrintExpr(Node->getSubExpr());
OS << "}";
}
void StmtPrinter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *Node) {
OS << "*";
}
void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) {
OS << "(";
for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) {

View File

@ -972,6 +972,14 @@ void StmtProfiler::VisitDesignatedInitUpdateExpr(
"initializer");
}
void StmtProfiler::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitNoInitExpr(const NoInitExpr *S) {
llvm_unreachable("Unexpected NoInitExpr in syntactic form of initializer");
}

View File

@ -164,6 +164,7 @@ public:
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
@ -1308,6 +1309,85 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
cleanupDominator->eraseFromParent();
}
void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
// Emit the common subexpression.
CodeGenFunction::OpaqueValueMapping binding(CGF, E->getCommonExpr());
Address destPtr = EnsureSlot(E->getType()).getAddress();
uint64_t numElements = E->getArraySize().getZExtValue();
if (!numElements)
return;
// FIXME: Dig through nested ArrayInitLoopExprs to find the overall array
// size, and only emit a single loop for a multidimensional array.
// destPtr is an array*. Construct an elementType* by drilling down a level.
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
llvm::Value *indices[] = {zero, zero};
llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getPointer(), indices,
"arrayinit.begin");
QualType elementType = E->getSubExpr()->getType();
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");
// Jump into the body.
CGF.EmitBlock(bodyBB);
llvm::PHINode *index =
Builder.CreatePHI(zero->getType(), 2, "arrayinit.index");
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);
// Emit the actual filler expression.
{
CodeGenFunction::ArrayInitLoopExprScope Scope(CGF, index);
LValue elementLV =
CGF.MakeAddrLValue(Address(element, elementAlign), elementType);
EmitInitializationToLValue(E->getSubExpr(), elementLV);
}
// Move on to the next element.
llvm::Value *nextIndex = Builder.CreateNUWAdd(
index, llvm::ConstantInt::get(CGF.SizeTy, 1), "arrayinit.next");
index->addIncoming(nextIndex, Builder.GetInsertBlock());
// Leave the loop if we're done.
llvm::Value *done = Builder.CreateICmpEQ(
nextIndex, llvm::ConstantInt::get(CGF.SizeTy, numElements),
"arrayinit.done");
llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
Builder.CreateCondBr(done, endBB, bodyBB);
CGF.EmitBlock(endBB);
// Leave the partial-array cleanup if we entered one.
if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}
void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
AggValueSlot Dest = EnsureSlot(E->getType());

View File

@ -311,6 +311,12 @@ public:
Value *VisitInitListExpr(InitListExpr *E);
Value *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) {
assert(CGF.getArrayInitIndex() &&
"ArrayInitIndexExpr not inside an ArrayInitLoopExpr?");
return CGF.getArrayInitIndex();
}
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
return EmitNullValue(E->getType());
}

View File

@ -918,6 +918,17 @@ public:
e->getCommon());
}
/// Build the opaque value mapping for an OpaqueValueExpr whose source
/// expression is set to the expression the OVE represents.
OpaqueValueMapping(CodeGenFunction &CGF, const OpaqueValueExpr *OV)
: CGF(CGF) {
if (OV) {
assert(OV->getSourceExpr() && "wrong form of OpaqueValueMapping used "
"for OVE with no source expression");
Data = OpaqueValueMappingData::bind(CGF, OV, OV->getSourceExpr());
}
}
OpaqueValueMapping(CodeGenFunction &CGF,
const OpaqueValueExpr *opaqueValue,
LValue lvalue)
@ -1183,6 +1194,23 @@ public:
CharUnits OldCXXThisAlignment;
};
/// The scope of an ArrayInitLoopExpr. Within this scope, the value of the
/// current loop index is overridden.
class ArrayInitLoopExprScope {
public:
ArrayInitLoopExprScope(CodeGenFunction &CGF, llvm::Value *Index)
: CGF(CGF), OldArrayInitIndex(CGF.ArrayInitIndex) {
CGF.ArrayInitIndex = Index;
}
~ArrayInitLoopExprScope() {
CGF.ArrayInitIndex = OldArrayInitIndex;
}
private:
CodeGenFunction &CGF;
llvm::Value *OldArrayInitIndex;
};
class InlinedInheritingConstructorScope {
public:
InlinedInheritingConstructorScope(CodeGenFunction &CGF, GlobalDecl GD)
@ -1251,6 +1279,10 @@ private:
/// this expression.
Address CXXDefaultInitExprThis = Address::invalid();
/// The current array initialization index when evaluating an
/// ArrayInitIndexExpr within an ArrayInitLoopExpr.
llvm::Value *ArrayInitIndex = nullptr;
/// The values of function arguments to use when evaluating
/// CXXInheritedCtorInitExprs within this context.
CallArgList CXXInheritedCtorInitExprArgs;
@ -1953,6 +1985,9 @@ public:
return it->second;
}
/// Get the index of the current ArrayInitLoopExpr, if any.
llvm::Value *getArrayInitIndex() { return ArrayInitIndex; }
/// getAccessedFieldNo - Given an encoded value and a result number, return
/// the input field number being accessed.
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);

View File

@ -1166,6 +1166,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ExprWithCleanupsClass:
case Expr::ExtVectorElementExprClass:
case Expr::InitListExprClass:
case Expr::ArrayInitLoopExprClass:
case Expr::MemberExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ObjCIvarRefExprClass:
@ -1259,6 +1260,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ImaginaryLiteralClass:
case Expr::ImplicitValueInitExprClass:
case Expr::IntegerLiteralClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCStringLiteralClass:

View File

@ -2910,7 +2910,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Variable:
case EK_Member:
case EK_Binding:
return VariableOrMember->getDeclName();
return Variable.VariableOrMember->getDeclName();
case EK_LambdaCapture:
return DeclarationName(Capture.VarID);
@ -2938,7 +2938,7 @@ ValueDecl *InitializedEntity::getDecl() const {
case EK_Variable:
case EK_Member:
case EK_Binding:
return VariableOrMember;
return Variable.VariableOrMember;
case EK_Parameter:
case EK_Parameter_CF_Audited:
@ -3065,6 +3065,8 @@ void InitializationSequence::Step::Destroy() {
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayLoopIndex:
case SK_ArrayLoopInit:
case SK_ArrayInit:
case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
@ -3307,6 +3309,17 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
Steps.push_back(S);
}
void InitializationSequence::AddArrayInitLoopStep(QualType T, QualType EltT) {
Step S;
S.Kind = SK_ArrayLoopIndex;
S.Type = EltT;
Steps.insert(Steps.begin(), S);
S.Kind = SK_ArrayLoopInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddParenthesizedArrayInitStep(QualType T) {
Step S;
S.Kind = SK_ParenthesizedArrayInit;
@ -3552,6 +3565,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
/// enumerates the constructors of the initialized entity and performs overload
/// resolution to select the best.
/// \param DestType The destination class type.
/// \param DestArrayType The destination type, which is either DestType or
/// a (possibly multidimensional) array of DestType.
/// \param IsListInit Is this list-initialization?
/// \param IsInitListCopy Is this non-list-initialization resulting from a
/// list-initialization from {x} where x is the same
@ -3560,6 +3576,7 @@ static void TryConstructorInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args, QualType DestType,
QualType DestArrayType,
InitializationSequence &Sequence,
bool IsListInit = false,
bool IsInitListCopy = false) {
@ -3703,7 +3720,7 @@ static void TryConstructorInitialization(Sema &S,
// subsumed by the initialization.
bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddConstructorInitializationStep(
Best->FoundDecl, CtorDecl, DestType, HadMultipleCandidates,
Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
}
@ -3871,8 +3888,9 @@ static void TryListInitialization(Sema &S,
S.IsDerivedFrom(InitList->getLocStart(), InitType, DestType)) {
Expr *InitListAsExpr = InitList;
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
Sequence, /*InitListSyntax*/ false,
/*IsInitListCopy*/ true);
DestType, Sequence,
/*InitListSyntax*/false,
/*IsInitListCopy*/true);
return;
}
}
@ -3927,7 +3945,7 @@ static void TryListInitialization(Sema &S,
// - Otherwise, if T is a class type, constructors are considered.
Expr *InitListAsExpr = InitList;
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
Sequence, /*InitListSyntax*/ true);
DestType, Sequence, /*InitListSyntax*/true);
} else
Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
return;
@ -4580,8 +4598,10 @@ static void TryValueInitialization(Sema &S,
MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0);
bool InitListSyntax = InitList;
return TryConstructorInitialization(S, Entity, Kind, Args, T, Sequence,
InitListSyntax);
// FIXME: Instead of creating a CXXConstructExpr of non-array type here,
// wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr.
return TryConstructorInitialization(
S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax);
}
}
@ -4604,7 +4624,8 @@ static void TryDefaultInitialization(Sema &S,
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) {
TryConstructorInitialization(S, Entity, Kind, None, DestType, Sequence);
TryConstructorInitialization(S, Entity, Kind, None, DestType,
Entity.getType(), Sequence);
return;
}
@ -5030,6 +5051,42 @@ static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) {
cast<FunctionDecl>(DRE->getDecl()));
}
/// Determine whether we can perform an elementwise array copy for this kind
/// of entity.
static bool canPerformArrayCopy(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_LambdaCapture:
// C++ [expr.prim.lambda]p24:
// For array members, the array elements are direct-initialized in
// increasing subscript order.
return true;
case InitializedEntity::EK_Variable:
// C++ [dcl.decomp]p1:
// [...] each element is copy-initialized or direct-initialized from the
// corresponding element of the assignment-expression [...]
return isa<DecompositionDecl>(Entity.getDecl());
case InitializedEntity::EK_Member:
// C++ [class.copy.ctor]p14:
// - if the member is an array, each element is direct-initialized with
// the corresponding subobject of x
return Entity.isImplicitMemberInitializer();
case InitializedEntity::EK_ArrayElement:
// All the above cases are intended to apply recursively, even though none
// of them actually say that.
if (auto *E = Entity.getParent())
return canPerformArrayCopy(*E);
break;
default:
break;
}
return false;
}
void InitializationSequence::InitializeFrom(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@ -5152,6 +5209,34 @@ void InitializationSequence::InitializeFrom(Sema &S,
}
}
// Some kinds of initialization permit an array to be initialized from
// another array of the same type, and perform elementwise initialization.
if (Initializer && isa<ConstantArrayType>(DestAT) &&
S.Context.hasSameUnqualifiedType(Initializer->getType(),
Entity.getType()) &&
canPerformArrayCopy(Entity)) {
// If source is a prvalue, use it directly.
if (Initializer->getValueKind() == VK_RValue) {
// FIXME: This produces a bogus extwarn
AddArrayInitStep(DestType);
return;
}
// Emit element-at-a-time copy loop.
InitializedEntity Element =
InitializedEntity::InitializeElement(S.Context, 0, Entity);
QualType InitEltT =
Context.getAsArrayType(Initializer->getType())->getElementType();
OpaqueValueExpr OVE(SourceLocation(), InitEltT,
Initializer->getValueKind());
Expr *OVEAsExpr = &OVE;
InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList,
TreatUnavailableAsInvalid);
if (!Failed())
AddArrayInitLoopStep(Entity.getType(), InitEltT);
return;
}
// Note: as an GNU C extension, we allow initialization of an
// array from a compound literal that creates an array of the same
// type, so long as the initializer has no side effects.
@ -5225,7 +5310,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
S.IsDerivedFrom(Initializer->getLocStart(), SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args,
DestType, *this);
DestType, DestType, *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
// user-defined conversion sequences that can convert from the source
// type to the destination type or (when a conversion function is
@ -5842,7 +5927,7 @@ PerformConstructorInitialization(Sema &S,
// If the entity allows NRVO, mark the construction as elidable
// unconditionally.
if (Entity.allowsNRVO())
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
CurInit = S.BuildCXXConstructExpr(Loc, Step.Type,
Step.Function.FoundDecl,
Constructor, /*Elidable=*/true,
ConstructorArgs,
@ -5853,7 +5938,7 @@ PerformConstructorInitialization(Sema &S,
ConstructKind,
ParenOrBraceRange);
else
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
CurInit = S.BuildCXXConstructExpr(Loc, Step.Type,
Step.Function.FoundDecl,
Constructor,
ConstructorArgs,
@ -6403,6 +6488,7 @@ InitializationSequence::Perform(Sema &S,
Entity.getType();
ExprResult CurInit((Expr *)nullptr);
SmallVector<Expr*, 4> ArrayLoopCommonExprs;
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
@ -6430,6 +6516,8 @@ InitializationSequence::Perform(Sema &S,
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayLoopIndex:
case SK_ArrayLoopInit:
case SK_ArrayInit:
case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
@ -6813,13 +6901,15 @@ InitializationSequence::Perform(Sema &S,
bool UseTemporary = Entity.getType()->isReferenceType();
bool IsStdInitListInit =
Step->Kind == SK_StdInitializerListConstructorCall;
Expr *Source = CurInit.get();
CurInit = PerformConstructorInitialization(
S, UseTemporary ? TempEntity : Entity, Kind, Args, *Step,
S, UseTemporary ? TempEntity : Entity, Kind,
Source ? MultiExprArg(Source) : Args, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/IsStdInitListInit,
/*IsStdInitListInitialization*/IsStdInitListInit,
/*LBraceLoc*/SourceLocation(),
/*RBraceLoc*/SourceLocation());
/*IsListInitialization*/ IsStdInitListInit,
/*IsStdInitListInitialization*/ IsStdInitListInit,
/*LBraceLoc*/ SourceLocation(),
/*RBraceLoc*/ SourceLocation());
break;
}
@ -6898,6 +6988,28 @@ InitializationSequence::Perform(Sema &S,
CurInit.get()->getValueKind());
break;
case SK_ArrayLoopIndex: {
Expr *Cur = CurInit.get();
Expr *BaseExpr = new (S.Context)
OpaqueValueExpr(Cur->getExprLoc(), Cur->getType(),
Cur->getValueKind(), Cur->getObjectKind(), Cur);
Expr *IndexExpr =
new (S.Context) ArrayInitIndexExpr(S.Context.getSizeType());
CurInit = S.CreateBuiltinArraySubscriptExpr(
BaseExpr, Kind.getLocation(), IndexExpr, Kind.getLocation());
ArrayLoopCommonExprs.push_back(BaseExpr);
break;
}
case SK_ArrayLoopInit: {
assert(!ArrayLoopCommonExprs.empty() &&
"mismatched SK_ArrayLoopIndex and SK_ArrayLoopInit");
Expr *Common = ArrayLoopCommonExprs.pop_back_val();
CurInit = new (S.Context) ArrayInitLoopExpr(Step->Type, Common,
CurInit.get());
break;
}
case SK_ArrayInit:
// Okay: we checked everything before creating this step. Note that
// this is a GNU extension.
@ -7851,6 +7963,14 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "Objective-C object conversion";
break;
case SK_ArrayLoopIndex:
OS << "indexing for array initialization loop";
break;
case SK_ArrayLoopInit:
OS << "array initialization loop";
break;
case SK_ArrayInit:
OS << "array initialization";
break;

View File

@ -3221,6 +3221,9 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
Init = ExprTemp->getSubExpr();
if (auto *AIL = dyn_cast<ArrayInitLoopExpr>(Init))
Init = AIL->getCommonExpr();
if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
Init = MTE->GetTemporaryExpr();
@ -9045,6 +9048,20 @@ TreeTransform<Derived>::TransformNoInitExpr(
return ExprError();
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformArrayInitLoopExpr(ArrayInitLoopExpr *E) {
llvm_unreachable("Unexpected ArrayInitLoopExpr outside of initializer");
return ExprError();
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformArrayInitIndexExpr(ArrayInitIndexExpr *E) {
llvm_unreachable("Unexpected ArrayInitIndexExpr outside of initializer");
return ExprError();
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformImplicitValueInitExpr(

View File

@ -845,6 +845,16 @@ void ASTStmtReader::VisitNoInitExpr(NoInitExpr *E) {
VisitExpr(E);
}
void ASTStmtReader::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) {
VisitExpr(E);
E->SubExprs[0] = Reader.ReadSubExpr();
E->SubExprs[1] = Reader.ReadSubExpr();
}
void ASTStmtReader::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) {
VisitExpr(E);
}
void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
VisitExpr(E);
}
@ -3231,6 +3241,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) NoInitExpr(Empty);
break;
case EXPR_ARRAY_INIT_LOOP:
S = new (Context) ArrayInitLoopExpr(Empty);
break;
case EXPR_ARRAY_INIT_INDEX:
S = new (Context) ArrayInitIndexExpr(Empty);
break;
case EXPR_VA_ARG:
S = new (Context) VAArgExpr(Empty);
break;

View File

@ -792,6 +792,18 @@ void ASTStmtWriter::VisitNoInitExpr(NoInitExpr *E) {
Code = serialization::EXPR_NO_INIT;
}
void ASTStmtWriter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) {
VisitExpr(E);
Record.AddStmt(E->SubExprs[0]);
Record.AddStmt(E->SubExprs[1]);
Code = serialization::EXPR_ARRAY_INIT_LOOP;
}
void ASTStmtWriter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) {
VisitExpr(E);
Code = serialization::EXPR_ARRAY_INIT_INDEX;
}
void ASTStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
VisitExpr(E);
Code = serialization::EXPR_IMPLICIT_VALUE_INIT;

View File

@ -905,6 +905,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
case Stmt::DesignatedInitUpdateExprClass:
case Stmt::ArrayInitLoopExprClass:
case Stmt::ArrayInitIndexExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImaginaryLiteralClass:
case Stmt::ObjCAtCatchStmtClass:

View File

@ -243,6 +243,8 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::ChooseExprClass:
case Stmt::DesignatedInitExprClass:
case Stmt::DesignatedInitUpdateExprClass:
case Stmt::ArrayInitLoopExprClass:
case Stmt::ArrayInitIndexExprClass:
case Stmt::ExprWithCleanupsClass:
case Stmt::ExpressionTraitExprClass:
case Stmt::ExtVectorElementExprClass: