[cfe-commits] r63525 - in /cfe/trunk: include/clang/AST/Expr.h lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaInit.cpp test/SemaCXX/dcl_init_aggr.cpp
Douglas Gregor
dgregor at apple.com
Mon Feb 2 09:43:22 PST 2009
Author: dgregor
Date: Mon Feb 2 11:43:21 2009
New Revision: 63525
URL: http://llvm.org/viewvc/llvm-project?rev=63525&view=rev
Log:
Check value-initializations that occur when an initializer list
provides too few elements.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=63525&r1=63524&r2=63525&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Feb 2 11:43:21 2009
@@ -1725,6 +1725,8 @@
return LBraceLoc.isValid() && RBraceLoc.isValid();
}
+ void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
+
/// @brief Retrieve the initializer list that describes the
/// syntactic form of the initializer.
///
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63525&r1=63524&r2=63525&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb 2 11:43:21 2009
@@ -1715,6 +1715,7 @@
StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType);
bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT);
+ bool CheckValueInitialization(QualType Type, SourceLocation Loc);
// type checking C++ declaration initializers (C++ [dcl.init]).
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=63525&r1=63524&r2=63525&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Feb 2 11:43:21 2009
@@ -1592,13 +1592,20 @@
return cast<CXXConstructorDecl>(Best->Function);
case OR_No_Viable_Function:
- Diag(Loc, diag::err_ovl_no_viable_function_in_init)
- << InitEntity << (unsigned)CandidateSet.size() << Range;
+ if (InitEntity)
+ Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+ << InitEntity << (unsigned)CandidateSet.size() << Range;
+ else
+ Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+ << ClassType << (unsigned)CandidateSet.size() << Range;
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
return 0;
case OR_Ambiguous:
- Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
+ if (InitEntity)
+ Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
+ else
+ Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return 0;
}
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=63525&r1=63524&r2=63525&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Feb 2 11:43:21 2009
@@ -127,6 +127,10 @@
void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
assert((ILE->getType() != SemaRef->Context.VoidTy) &&
"Should not have void type");
+ SourceLocation Loc = ILE->getSourceRange().getBegin();
+ if (ILE->getSyntacticForm())
+ Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
+
if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
unsigned Init = 0, NumInits = ILE->getNumInits();
for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
@@ -135,24 +139,32 @@
if (Field->isUnnamedBitfield())
continue;
- if (Init >= NumInits) {
+ if (Init >= NumInits || !ILE->getInit(Init)) {
if (Field->getType()->isReferenceType()) {
// C++ [dcl.init.aggr]p9:
// If an incomplete or empty initializer-list leaves a
// member of reference type uninitialized, the program is
// ill-formed.
- SemaRef->Diag(ILE->getSyntacticForm()->getLocStart(),
- diag::err_init_reference_member_uninitialized)
+ SemaRef->Diag(Loc, diag::err_init_reference_member_uninitialized)
<< Field->getType()
<< ILE->getSyntacticForm()->getSourceRange();
SemaRef->Diag(Field->getLocation(),
diag::note_uninit_reference_member);
hadError = true;
+ return;
+ } else if (SemaRef->CheckValueInitialization(Field->getType(), Loc)) {
+ hadError = true;
+ return;
}
- } else if (!ILE->getInit(Init))
- ILE->setInit(Init,
- new (SemaRef->Context) ImplicitValueInitExpr(Field->getType()));
- else if (InitListExpr *InnerILE
+
+ // FIXME: If value-initialization involves calling a
+ // constructor, should we make that call explicit in the
+ // representation (even when it means extending the
+ // initializer list)?
+ if (Init < NumInits && !hadError)
+ ILE->setInit(Init,
+ new (SemaRef->Context) ImplicitValueInitExpr(Field->getType()));
+ } else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
++Init;
@@ -167,18 +179,33 @@
QualType ElementType;
- if (const ArrayType *AType = SemaRef->Context.getAsArrayType(ILE->getType()))
+ unsigned NumInits = ILE->getNumInits();
+ unsigned NumElements = NumInits;
+ if (const ArrayType *AType = SemaRef->Context.getAsArrayType(ILE->getType())) {
ElementType = AType->getElementType();
- else if (const VectorType *VType = ILE->getType()->getAsVectorType())
+ if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
+ NumElements = CAType->getSize().getZExtValue();
+ } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) {
ElementType = VType->getElementType();
- else
+ NumElements = VType->getNumElements();
+ } else
ElementType = ILE->getType();
- for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits;
- ++Init) {
- if (!ILE->getInit(Init))
- ILE->setInit(Init,
- new (SemaRef->Context) ImplicitValueInitExpr(ElementType));
+ for (unsigned Init = 0; Init != NumElements; ++Init) {
+ if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (SemaRef->CheckValueInitialization(ElementType, Loc)) {
+ hadError = true;
+ return;
+ }
+
+ // FIXME: If value-initialization involves calling a
+ // constructor, should we make that call explicit in the
+ // representation (even when it means extending the
+ // initializer list)?
+ if (Init < NumInits && !hadError)
+ ILE->setInit(Init,
+ new (SemaRef->Context) ImplicitValueInitExpr(ElementType));
+ }
else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
}
@@ -254,9 +281,19 @@
unsigned StructuredSubobjectInitIndex = 0;
// Check the element types and build the structural subobject.
+ unsigned StartIndex = Index;
CheckListElementTypes(ParentIList, T, false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
+ unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
+
+ // Update the structured sub-object initialize so that it's ending
+ // range corresponds with the end of the last initializer it used.
+ if (EndIndex < ParentIList->getNumInits()) {
+ SourceLocation EndLoc
+ = ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
+ StructuredSubobjectInitList->setRBraceLoc(EndLoc);
+ }
}
void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
@@ -1102,9 +1139,12 @@
<< ExistingInit->getSourceRange();
}
+ SourceLocation StartLoc;
+ if (Index < IList->getNumInits())
+ StartLoc = IList->getInit(Index)->getSourceRange().getBegin();
InitListExpr *Result
- = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0,
- SourceLocation());
+ = new (SemaRef->Context) InitListExpr(StartLoc, 0, 0,
+ IList->getSourceRange().getEnd());
Result->setType(CurrentObjectType);
// Link this new initializer list into the structured initializer
@@ -1257,3 +1297,52 @@
return CheckInitList.HadError();
}
+
+/// \brief Diagnose any semantic errors with value-initialization of
+/// the given type.
+///
+/// Value-initialization effectively zero-initializes any types
+/// without user-declared constructors, and calls the default
+/// constructor for a for any type that has a user-declared
+/// constructor (C++ [dcl.init]p5). Value-initialization can fail when
+/// a type with a user-declared constructor does not have an
+/// accessible, non-deleted default constructor. In C, everything can
+/// be value-initialized, which corresponds to C's notion of
+/// initializing objects with static storage duration when no
+/// initializer is provided for that object.
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
+ // C++ [dcl.init]p5:
+ //
+ // To value-initialize an object of type T means:
+
+ // -- if T is an array type, then each element is value-initialized;
+ if (const ArrayType *AT = Context.getAsArrayType(Type))
+ return CheckValueInitialization(AT->getElementType(), Loc);
+
+ if (const RecordType *RT = Type->getAsRecordType()) {
+ if (const CXXRecordType *CXXRec = dyn_cast<CXXRecordType>(RT)) {
+ // -- if T is a class type (clause 9) with a user-declared
+ // constructor (12.1), then the default constructor for T is
+ // called (and the initialization is ill-formed if T has no
+ // accessible default constructor);
+ if (CXXRec->getDecl()->hasUserDeclaredConstructor())
+ // FIXME: Eventually, we'll need to put the constructor decl
+ // into the AST.
+ return PerformInitializationByConstructor(Type, 0, 0, Loc,
+ SourceRange(Loc),
+ DeclarationName(),
+ IK_Direct);
+ }
+ }
+
+ if (Type->isReferenceType()) {
+ // C++ [dcl.init]p5:
+ // [...] A program that calls for default-initialization or
+ // value-initialization of an entity of reference type is
+ // ill-formed. [...]
+ }
+
+ return false;
+}
Modified: cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp?rev=63525&r1=63524&r2=63525&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp (original)
+++ cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp Mon Feb 2 11:43:21 2009
@@ -40,6 +40,21 @@
struct TooFew { int a; char* b; int c; };
TooFew too_few = { 1, "asdf" }; // okay
+struct NoDefaultConstructor { // expected-note{{candidate function}}
+ NoDefaultConstructor(int); // expected-note{{candidate function}}
+};
+struct TooFewError {
+ int a;
+ NoDefaultConstructor nodef;
+};
+TooFewError too_few_okay = { 1, 1 };
+TooFewError too_few_error = { 1 }; // expected-error{{no matching constructor}}
+
+TooFewError too_few_okay2[2] = { 1, 1 };
+TooFewError too_few_error2[2] = { 1 }; // expected-error{{no matching constructor}}
+
+NoDefaultConstructor too_few_error3[3] = { }; // expected-error{{no matching constructor}}
+
// C++ [dcl.init.aggr]p8
struct Empty { };
struct EmptyTest {
More information about the cfe-commits
mailing list