summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-12-12 02:53:20 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-12-12 02:53:20 +0000
commit410306bf6ed906af77978caa199e5d96376bae66 (patch)
tree811f32246733190c960c7785c3dd02587d43be1d /clang/lib
parent8c9cc8c86be80abd4224341314725d03551460d6 (diff)
downloadbcm5719-llvm-410306bf6ed906af77978caa199e5d96376bae66.tar.gz
bcm5719-llvm-410306bf6ed906af77978caa199e5d96376bae66.zip
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
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTDumper.cpp10
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprClassification.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp60
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp2
-rw-r--r--clang/lib/AST/StmtPrinter.cpp12
-rw-r--r--clang/lib/AST/StmtProfile.cpp8
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp80
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp6
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h35
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp2
-rw-r--r--clang/lib/Sema/SemaInit.cpp154
-rw-r--r--clang/lib/Sema/TreeTransform.h17
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp18
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp2
16 files changed, 405 insertions, 17 deletions
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 248128861e2..62261ccc905 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -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")
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 776a7f996d0..0307648fa80 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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:
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index aa4651d6f43..adb74b80b19 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -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:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 949ec6382fd..61bb2b9bc91 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 0916c010408..ab3e49d903c 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -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:
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 2c0b74ab016..65e9f824999 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -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) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index d8185d35dd0..b55250056c2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -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");
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index c0989883e17..d756eca64f1 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -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());
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 2b54370c296..c15e580cd30 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -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());
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 071bcb86866..b9b33a8783d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -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);
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 3561bd02b95..781f78018b4 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -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:
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 50e7b8eb058..34531287884 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -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;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1a07e719f12..af60a56564c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -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();
@@ -9047,6 +9050,20 @@ TreeTransform<Derived>::TransformNoInitExpr(
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(
ImplicitValueInitExpr *E) {
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 032ceefbf34..461bb9f8d46 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -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;
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 46acfad9b83..fbe1d843cd6 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -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;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 91946b8feda..93f6939c2e5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -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:
OpenPOWER on IntegriCloud