[PATCH] C99 partial re-initialization behavior (DR-253)
Richard Smith
richard at metafoo.co.uk
Mon Apr 27 18:55:44 PDT 2015
This is looking really good. I'm not entirely sure that `NoInitExpr` is necessary -- we could define a null `Expr*` within the update list of a `DesignatedInitUpdateExpr` as meaning "perform no initialization" instead -- but we can look at removing it after this patch lands.
================
Comment at: include/clang/AST/Expr.h:4313
@@ +4312,3 @@
+ DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lbraceloc,
+ Expr* baseExprs, SourceLocation rbraceloc);
+
----------------
Put the `*` on the right, please, and capitalize as `lBraceLoc` / `rBraceLoc`.
================
Comment at: lib/AST/Expr.cpp:2779
@@ +2778,3 @@
+ return false;
+ assert(false && "DIUE->getBase() should not be a constant expression");
+ break;
----------------
I would think this should be:
return Base->isConstantInitializer(...) && Update->isConstantInitializer(...)
================
Comment at: lib/AST/Expr.cpp:4001
@@ +4000,3 @@
+
+ InitListExpr *ILE = new (C) InitListExpr(C, lbraceloc, None, rbraceloc);
+ ILE->setType(baseExpr->getType());
----------------
Given that we store the brace locations on the Updater, do we need to also store them inside `DesignatedInitUpdateExpr`?
================
Comment at: lib/AST/Expr.cpp:4006-4016
@@ +4005,13 @@
+
+SourceLocation DesignatedInitUpdateExpr::getLocStart() const {
+ if (LBraceLoc.isValid())
+ return LBraceLoc;
+ return getBase()->getLocStart();
+}
+
+SourceLocation DesignatedInitUpdateExpr::getLocEnd() const {
+ if (RBraceLoc.isValid())
+ return RBraceLoc;
+ return getUpdater()->getLocEnd();
+}
+
----------------
This will give a range of Base start to Updater end if there's no LBraceLoc / RBraceLoc, which is a source range that can contain things unrelated to the update. Updater's end loc is always the same as RBraceLoc anyway, so should this instead return `getBase()->getLocEnd()`?
================
Comment at: lib/AST/StmtProfile.cpp:716-724
@@ -715,1 +715,11 @@
+// FIXME: how to test these functions?
+void StmtProfiler::VisitDesignatedInitUpdateExpr(
+ const DesignatedInitUpdateExpr *S) {
+ llvm_unreachable("Not implemented");
+}
+
+void StmtProfiler::VisitNoInitExpr(const NoInitExpr *S) {
+ llvm_unreachable("Not implemented");
+}
+
----------------
To test these, put a `DesignatedInitUpdateExpr` in the signature of a function template, and declare it twice:
template<typename T> void f(decltype(T((char[4]){"foo", [2] = 'x'}))) {} // expected-note {{previous}}
template<typename T> void f(decltype(T((char[4]){"foo", [2] = 'r'}))) {} // ok
template<typename T> void f(decltype(T((char[4]){"boo", [2] = 'x'}))) {} // ok
template<typename T> void f(decltype(T((char[4]){"foo", [2] = 'x'}))) {} // expected-error {{redefinition}}
================
Comment at: lib/CodeGen/CGExprCXX.cpp:955-972
@@ -954,1 +954,20 @@
+ // If we have a struct whose every field is value-initialized, we can
+ // usually use memset.
+ if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
+ if (RType->getDecl()->isStruct()) {
+ unsigned NumFields = 0;
+ for (auto *Field : RType->getDecl()->fields())
+ if (!Field->isUnnamedBitfield())
+ ++NumFields;
+ if (ILE->getNumInits() == NumFields)
+ for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
+ if (!isa<ImplicitValueInitExpr>(ILE->getInit(i)))
+ --NumFields;
+ if (ILE->getNumInits() == NumFields && TryMemsetInitialization())
+ return;
+ }
+ }
+ }
+
----------------
This seems like a good idea, but not obviously related to this change. Can you split this out into a separate patch?
================
Comment at: lib/Sema/SemaInit.cpp:653-664
@@ -598,3 +652,5 @@
+ ILE->setInit(Init, ILE->getArrayFiller());
+ else if (!InitExpr && !ILE->hasArrayFiller()) {
ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(),
ElementEntity,
/*VerifyOnly*/false);
@@ -603,3 +659,7 @@
return;
}
+ Expr *Filler = FillWithNoInit ?
+ new (SemaRef.Context) NoInitExpr(ElementType) :
+ ElementInit.getAs<Expr>();
+
----------------
If we're using `NoInit` here, we shouldn't `PerformEmptyInit`, because that might fail and in any case will wastefully produce an AST node that we don't want.
================
Comment at: lib/Sema/SemaInit.cpp:2187-2204
@@ +2186,20 @@
+ StructuredList = Result;
+ else if (ExistingInit->isConstantInitializer(SemaRef.Context, false)) {
+ InitListExpr *Result = new (SemaRef.Context) InitListExpr(
+ SemaRef.Context, D->getLocStart(), None, DIE->getLocEnd());
+
+ QualType ResultType = CurrentObjectType;
+ if (!ResultType->isArrayType())
+ ResultType = ResultType.getNonLValueExprType(SemaRef.Context);
+ Result->setType(ResultType);
+
+ // If we decomposed an aggregate initializer into individual components,
+ // we do not issue diagnostics here; instead we wait till later and
+ // issue diagnostics on each individual component.
+ partialMergeFrom(SemaRef.Context, Result, ExistingInit);
+ ExistingInit = nullptr;
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ StructuredList = Result;
+ }
+ else {
+ if (DesignatedInitUpdateExpr *E =
----------------
I would prefer to see this case handled by teaching AST/ExprConstant to evaluate `DesignatedInitUpdateExpr` and always using the code below, rather than trying to convert an existing initializer into an `InitListExpr`.
================
Comment at: lib/Sema/SemaInit.cpp:2829-2831
@@ +2828,5 @@
+ else if (StructuredList->hasArrayFiller()) {
+ SemaRef.Diag(expr->getLocStart(),
+ diag::warn_initializer_overrides)
+ << expr->getSourceRange();
+ }
----------------
Is it useful to warn on overriding an array filler with an explicit value? This case seems unlikely to be a bug.
================
Comment at: test/CodeGen/partial-reinitialization2.c:2
@@ +1,3 @@
+// RUN: %clang_cc1 -isystem %S/Inputs %s -emit-llvm -o - \
+// RUN: | lli -force-interpreter | FileCheck %s
+
----------------
Executable/interpreted tests aren't acceptable here. Please check for specific IR being generated instead.
http://reviews.llvm.org/D5789
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
More information about the cfe-commits
mailing list