Skip to content

Commit cb77930

Browse files
Yunzhong GaoYunzhong Gao
authored andcommitted
Implementing C99 partial re-initialization behavior (DR-253)
Based on previous discussion on the mailing list, clang currently lacks support for C99 partial re-initialization behavior: Reference: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2013-April/029188.html Reference: http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_253.htm This patch attempts to fix this problem. Given the following code snippet, struct P1 { char x[6]; }; struct LP1 { struct P1 p1; }; struct LP1 l = { .p1 = { "foo" }, .p1.x[2] = 'x' }; // this example is adapted from the example for "struct fred x[]" in DR-253; // currently clang produces in l: { "\0\0x" }, // whereas gcc 4.8 produces { "fox" }; // with this fix, clang will also produce: { "fox" }; Differential Review: http://reviews.llvm.org/D5789 llvm-svn: 239446
1 parent 7912d9b commit cb77930

28 files changed

+872
-45
lines changed

clang/include/clang/AST/DataRecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,9 +2204,11 @@ DEF_TRAVERSE_STMT(CXXThisExpr, {})
22042204
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
22052205
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
22062206
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
2207+
DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
22072208
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
22082209
DEF_TRAVERSE_STMT(GNUNullExpr, {})
22092210
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
2211+
DEF_TRAVERSE_STMT(NoInitExpr, {})
22102212
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
22112213
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
22122214
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())

clang/include/clang/AST/Expr.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4267,6 +4267,80 @@ class DesignatedInitExpr : public Expr {
42674267
}
42684268
};
42694269

4270+
/// \brief Represents a place-holder for an object not to be initialized by
4271+
/// anything.
4272+
///
4273+
/// This only makes sense when it appears as part of an updater of a
4274+
/// DesignatedInitUpdateExpr (see below). The base expression of a DIUE
4275+
/// initializes a big object, and the NoInitExpr's mark the spots within the
4276+
/// big object not to be overwritten by the updater.
4277+
///
4278+
/// \see DesignatedInitUpdateExpr
4279+
class NoInitExpr : public Expr {
4280+
public:
4281+
explicit NoInitExpr(QualType ty)
4282+
: Expr(NoInitExprClass, ty, VK_RValue, OK_Ordinary,
4283+
false, false, ty->isInstantiationDependentType(), false) { }
4284+
4285+
explicit NoInitExpr(EmptyShell Empty)
4286+
: Expr(NoInitExprClass, Empty) { }
4287+
4288+
static bool classof(const Stmt *T) {
4289+
return T->getStmtClass() == NoInitExprClass;
4290+
}
4291+
4292+
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
4293+
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
4294+
4295+
// Iterators
4296+
child_range children() { return child_range(); }
4297+
};
4298+
4299+
// In cases like:
4300+
// struct Q { int a, b, c; };
4301+
// Q *getQ();
4302+
// void foo() {
4303+
// struct A { Q q; } a = { *getQ(), .q.b = 3 };
4304+
// }
4305+
//
4306+
// We will have an InitListExpr for a, with type A, and then a
4307+
// DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE
4308+
// is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3"
4309+
//
4310+
class DesignatedInitUpdateExpr : public Expr {
4311+
// BaseAndUpdaterExprs[0] is the base expression;
4312+
// BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base.
4313+
Stmt *BaseAndUpdaterExprs[2];
4314+
4315+
public:
4316+
DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc,
4317+
Expr *baseExprs, SourceLocation rBraceLoc);
4318+
4319+
explicit DesignatedInitUpdateExpr(EmptyShell Empty)
4320+
: Expr(DesignatedInitUpdateExprClass, Empty) { }
4321+
4322+
SourceLocation getLocStart() const LLVM_READONLY;
4323+
SourceLocation getLocEnd() const LLVM_READONLY;
4324+
4325+
static bool classof(const Stmt *T) {
4326+
return T->getStmtClass() == DesignatedInitUpdateExprClass;
4327+
}
4328+
4329+
Expr *getBase() const { return cast<Expr>(BaseAndUpdaterExprs[0]); }
4330+
void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; }
4331+
4332+
InitListExpr *getUpdater() const {
4333+
return cast<InitListExpr>(BaseAndUpdaterExprs[1]);
4334+
}
4335+
void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; }
4336+
4337+
// Iterators
4338+
// children = the base and the updater
4339+
child_range children() {
4340+
return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
4341+
}
4342+
};
4343+
42704344
/// \brief Represents an implicitly-generated value initialization of
42714345
/// an object of a given type.
42724346
///

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,9 +2234,11 @@ DEF_TRAVERSE_STMT(CXXThisExpr, {})
22342234
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
22352235
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
22362236
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
2237+
DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
22372238
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
22382239
DEF_TRAVERSE_STMT(GNUNullExpr, {})
22392240
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
2241+
DEF_TRAVERSE_STMT(NoInitExpr, {})
22402242
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
22412243
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
22422244
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())

clang/include/clang/Basic/StmtNodes.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def CompoundLiteralExpr : DStmt<Expr>;
7777
def ExtVectorElementExpr : DStmt<Expr>;
7878
def InitListExpr : DStmt<Expr>;
7979
def DesignatedInitExpr : DStmt<Expr>;
80+
def DesignatedInitUpdateExpr : DStmt<Expr>;
8081
def ImplicitValueInitExpr : DStmt<Expr>;
82+
def NoInitExpr : DStmt<Expr>;
8183
def ParenListExpr : DStmt<Expr>;
8284
def VAArgExpr : DStmt<Expr>;
8385
def GenericSelectionExpr : DStmt<Expr>;

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,8 +1211,12 @@ namespace clang {
12111211
EXPR_INIT_LIST,
12121212
/// \brief A DesignatedInitExpr record.
12131213
EXPR_DESIGNATED_INIT,
1214+
/// \brief A DesignatedInitUpdateExpr record.
1215+
EXPR_DESIGNATED_INIT_UPDATE,
12141216
/// \brief An ImplicitValueInitExpr record.
12151217
EXPR_IMPLICIT_VALUE_INIT,
1218+
/// \brief An NoInitExpr record.
1219+
EXPR_NO_INIT,
12161220
/// \brief A VAArgExpr record.
12171221
EXPR_VA_ARG,
12181222
/// \brief An AddrLabelExpr record.

clang/lib/AST/Expr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
27722772
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
27732773
return Exp->isConstantInitializer(Ctx, false, Culprit);
27742774
}
2775+
case DesignatedInitUpdateExprClass: {
2776+
const DesignatedInitUpdateExpr *DIUE = cast<DesignatedInitUpdateExpr>(this);
2777+
return DIUE->getBase()->isConstantInitializer(Ctx, false, Culprit) &&
2778+
DIUE->getUpdater()->isConstantInitializer(Ctx, false, Culprit);
2779+
}
27752780
case InitListExprClass: {
27762781
const InitListExpr *ILE = cast<InitListExpr>(this);
27772782
if (ILE->getType()->isArrayType()) {
@@ -2818,6 +2823,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
28182823
break;
28192824
}
28202825
case ImplicitValueInitExprClass:
2826+
case NoInitExprClass:
28212827
return true;
28222828
case ParenExprClass:
28232829
return cast<ParenExpr>(this)->getSubExpr()
@@ -2925,6 +2931,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
29252931
case UnaryExprOrTypeTraitExprClass:
29262932
case AddrLabelExprClass:
29272933
case GNUNullExprClass:
2934+
case NoInitExprClass:
29282935
case CXXBoolLiteralExprClass:
29292936
case CXXNullPtrLiteralExprClass:
29302937
case CXXThisExprClass:
@@ -2983,6 +2990,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
29832990
case CompoundLiteralExprClass:
29842991
case ExtVectorElementExprClass:
29852992
case DesignatedInitExprClass:
2993+
case DesignatedInitUpdateExprClass:
29862994
case ParenListExprClass:
29872995
case CXXPseudoDestructorExprClass:
29882996
case CXXStdInitializerListExprClass:
@@ -3989,6 +3997,25 @@ void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
39893997
NumDesignators = NumDesignators - 1 + NumNewDesignators;
39903998
}
39913999

4000+
DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
4001+
SourceLocation lBraceLoc, Expr *baseExpr, SourceLocation rBraceLoc)
4002+
: Expr(DesignatedInitUpdateExprClass, baseExpr->getType(), VK_RValue,
4003+
OK_Ordinary, false, false, false, false) {
4004+
BaseAndUpdaterExprs[0] = baseExpr;
4005+
4006+
InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc);
4007+
ILE->setType(baseExpr->getType());
4008+
BaseAndUpdaterExprs[1] = ILE;
4009+
}
4010+
4011+
SourceLocation DesignatedInitUpdateExpr::getLocStart() const {
4012+
return getBase()->getLocStart();
4013+
}
4014+
4015+
SourceLocation DesignatedInitUpdateExpr::getLocEnd() const {
4016+
return getBase()->getLocEnd();
4017+
}
4018+
39924019
ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
39934020
ArrayRef<Expr*> exprs,
39944021
SourceLocation rparenloc)

clang/lib/AST/ExprClassification.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
183183
case Expr::ObjCIndirectCopyRestoreExprClass:
184184
case Expr::AtomicExprClass:
185185
case Expr::CXXFoldExprClass:
186+
case Expr::NoInitExprClass:
187+
case Expr::DesignatedInitUpdateExprClass:
186188
return Cl::CL_PRValue;
187189

188190
// Next come the complicated cases.

clang/lib/AST/ExprConstant.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8675,6 +8675,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
86758675
case Expr::CompoundLiteralExprClass:
86768676
case Expr::ExtVectorElementExprClass:
86778677
case Expr::DesignatedInitExprClass:
8678+
case Expr::NoInitExprClass:
8679+
case Expr::DesignatedInitUpdateExprClass:
86788680
case Expr::ImplicitValueInitExprClass:
86798681
case Expr::ParenListExprClass:
86808682
case Expr::VAArgExprClass:

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,7 +2680,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
26802680
// These all can only appear in local or variable-initialization
26812681
// contexts and so should never appear in a mangling.
26822682
case Expr::AddrLabelExprClass:
2683+
case Expr::DesignatedInitUpdateExprClass:
26832684
case Expr::ImplicitValueInitExprClass:
2685+
case Expr::NoInitExprClass:
26842686
case Expr::ParenListExprClass:
26852687
case Expr::LambdaExprClass:
26862688
case Expr::MSPropertyRefExprClass:

clang/lib/AST/StmtPrinter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,22 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
14301430
PrintExpr(Node->getInit());
14311431
}
14321432

1433+
void StmtPrinter::VisitDesignatedInitUpdateExpr(
1434+
DesignatedInitUpdateExpr *Node) {
1435+
OS << "{";
1436+
OS << "/*base*/";
1437+
PrintExpr(Node->getBase());
1438+
OS << ", ";
1439+
1440+
OS << "/*updater*/";
1441+
PrintExpr(Node->getUpdater());
1442+
OS << "}";
1443+
}
1444+
1445+
void StmtPrinter::VisitNoInitExpr(NoInitExpr *Node) {
1446+
OS << "/*no init*/";
1447+
}
1448+
14331449
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
14341450
if (Policy.LangOpts.CPlusPlus) {
14351451
OS << "/*implicit*/";

clang/lib/AST/StmtProfile.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,18 @@ void StmtProfiler::VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
744744
}
745745
}
746746

747+
// Seems that if VisitInitListExpr() only works on the syntactic form of an
748+
// InitListExpr, then a DesignatedInitUpdateExpr is not encountered.
749+
void StmtProfiler::VisitDesignatedInitUpdateExpr(
750+
const DesignatedInitUpdateExpr *S) {
751+
llvm_unreachable("Unexpected DesignatedInitUpdateExpr in syntactic form of "
752+
"initializer");
753+
}
754+
755+
void StmtProfiler::VisitNoInitExpr(const NoInitExpr *S) {
756+
llvm_unreachable("Unexpected NoInitExpr in syntactic form of initializer");
757+
}
758+
747759
void StmtProfiler::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *S) {
748760
VisitExpr(S);
749761
}

clang/lib/CodeGen/CGExprAgg.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,12 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
160160
EmitAggLoadOfLValue(E);
161161
}
162162

163+
void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E);
163164
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
164165
void VisitChooseExpr(const ChooseExpr *CE);
165166
void VisitInitListExpr(InitListExpr *E);
166167
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
168+
void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
167169
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
168170
Visit(DAE->getExpr());
169171
}
@@ -1056,6 +1058,9 @@ AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
10561058
return;
10571059
} else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
10581060
return EmitNullInitializationToLValue(LV);
1061+
} else if (isa<NoInitExpr>(E)) {
1062+
// Do nothing.
1063+
return;
10591064
} else if (type->isReferenceType()) {
10601065
RValue RV = CGF.EmitReferenceBindingToExpr(E);
10611066
return CGF.EmitStoreThroughLValue(RV, LV);
@@ -1276,6 +1281,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
12761281
cleanupDominator->eraseFromParent();
12771282
}
12781283

1284+
void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
1285+
AggValueSlot Dest = EnsureSlot(E->getType());
1286+
1287+
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
1288+
Dest.getAlignment());
1289+
EmitInitializationToLValue(E->getBase(), DestLV);
1290+
VisitInitListExpr(E->getUpdater());
1291+
}
1292+
12791293
//===----------------------------------------------------------------------===//
12801294
// Entry Points into this File
12811295
//===----------------------------------------------------------------------===//

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,25 @@ void CodeGenFunction::EmitNewArrayInitializer(
958958
if (ILE->getNumInits() == 0 && TryMemsetInitialization())
959959
return;
960960

961+
// If we have a struct whose every field is value-initialized, we can
962+
// usually use memset.
963+
if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
964+
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
965+
if (RType->getDecl()->isStruct()) {
966+
unsigned NumFields = 0;
967+
for (auto *Field : RType->getDecl()->fields())
968+
if (!Field->isUnnamedBitfield())
969+
++NumFields;
970+
if (ILE->getNumInits() == NumFields)
971+
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
972+
if (!isa<ImplicitValueInitExpr>(ILE->getInit(i)))
973+
--NumFields;
974+
if (ILE->getNumInits() == NumFields && TryMemsetInitialization())
975+
return;
976+
}
977+
}
978+
}
979+
961980
// Create the loop blocks.
962981
llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
963982
llvm::BasicBlock *LoopBB = createBasicBlock("new.loop");

0 commit comments

Comments
 (0)