2008-05-02 06:18:59 +08:00
|
|
|
//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for initializers.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
2009-01-22 08:58:24 +08:00
|
|
|
#include "clang/Parse/Designator.h"
|
2008-05-02 06:18:59 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Expr.h"
|
2008-08-11 11:27:53 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2008-12-12 00:49:14 +08:00
|
|
|
#include <algorithm> // for std::count_if
|
|
|
|
#include <functional> // for std::mem_fun
|
2008-05-02 06:18:59 +08:00
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
using namespace clang;
|
2008-05-02 06:18:59 +08:00
|
|
|
|
|
|
|
InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
|
|
|
|
hadError = false;
|
|
|
|
SemaRef = S;
|
2008-05-20 04:00:43 +08:00
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
unsigned newIndex = 0;
|
2008-05-20 04:00:43 +08:00
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
CheckExplicitInitList(IL, T, newIndex);
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int InitListChecker::numArrayElements(QualType DeclType) {
|
2008-05-25 21:22:35 +08:00
|
|
|
// FIXME: use a proper constant
|
|
|
|
int maxElements = 0x7FFFFFFF;
|
2008-08-04 15:31:14 +08:00
|
|
|
if (const ConstantArrayType *CAT =
|
|
|
|
SemaRef->Context.getAsConstantArrayType(DeclType)) {
|
2008-05-02 06:18:59 +08:00
|
|
|
maxElements = static_cast<int>(CAT->getSize().getZExtValue());
|
|
|
|
}
|
|
|
|
return maxElements;
|
|
|
|
}
|
|
|
|
|
|
|
|
int InitListChecker::numStructUnionElements(QualType DeclType) {
|
|
|
|
RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
|
2008-12-12 04:41:00 +08:00
|
|
|
const int InitializableMembers
|
2008-12-12 00:49:14 +08:00
|
|
|
= std::count_if(structDecl->field_begin(), structDecl->field_end(),
|
|
|
|
std::mem_fun(&FieldDecl::getDeclName));
|
2008-06-10 07:19:58 +08:00
|
|
|
if (structDecl->isUnion())
|
2008-05-25 22:03:31 +08:00
|
|
|
return std::min(InitializableMembers, 1);
|
|
|
|
return InitializableMembers - structDecl->hasFlexibleArrayMember();
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
|
|
|
|
QualType T, unsigned &Index) {
|
|
|
|
llvm::SmallVector<Expr*, 4> InitExprs;
|
|
|
|
int maxElements = 0;
|
|
|
|
|
|
|
|
if (T->isArrayType())
|
|
|
|
maxElements = numArrayElements(T);
|
|
|
|
else if (T->isStructureType() || T->isUnionType())
|
|
|
|
maxElements = numStructUnionElements(T);
|
2008-05-20 03:16:24 +08:00
|
|
|
else if (T->isVectorType())
|
|
|
|
maxElements = T->getAsVectorType()->getNumElements();
|
2008-05-02 06:18:59 +08:00
|
|
|
else
|
|
|
|
assert(0 && "CheckImplicitInitList(): Illegal type");
|
2008-05-20 03:16:24 +08:00
|
|
|
|
2008-05-25 21:49:22 +08:00
|
|
|
if (maxElements == 0) {
|
|
|
|
SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(),
|
|
|
|
diag::err_implicit_empty_initializer);
|
|
|
|
hadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
// Check the element types *before* we create the implicit init list;
|
|
|
|
// otherwise, we might end up taking the wrong number of elements
|
|
|
|
unsigned NewIndex = Index;
|
2009-01-23 07:26:18 +08:00
|
|
|
CheckListElementTypes(ParentIList, T, false, NewIndex);
|
2008-05-20 03:16:24 +08:00
|
|
|
|
2008-05-02 06:18:59 +08:00
|
|
|
for (int i = 0; i < maxElements; ++i) {
|
|
|
|
// Don't attempt to go past the end of the init list
|
|
|
|
if (Index >= ParentIList->getNumInits())
|
|
|
|
break;
|
|
|
|
Expr* expr = ParentIList->getInit(Index);
|
|
|
|
|
|
|
|
// Add the expr to the new implicit init list and remove if from the old.
|
|
|
|
InitExprs.push_back(expr);
|
|
|
|
ParentIList->removeInit(Index);
|
|
|
|
}
|
|
|
|
// Synthesize an "implicit" InitListExpr (marked by the invalid source locs).
|
|
|
|
InitListExpr *ILE = new InitListExpr(SourceLocation(),
|
|
|
|
&InitExprs[0], InitExprs.size(),
|
2008-10-27 07:43:26 +08:00
|
|
|
SourceLocation(),
|
|
|
|
ParentIList->hadDesignators());
|
2008-05-02 06:18:59 +08:00
|
|
|
ILE->setType(T);
|
2008-05-20 04:00:43 +08:00
|
|
|
|
2008-05-02 06:18:59 +08:00
|
|
|
// Modify the parent InitListExpr to point to the implicit InitListExpr.
|
|
|
|
ParentIList->addInit(Index, ILE);
|
|
|
|
}
|
|
|
|
|
2008-05-06 08:23:44 +08:00
|
|
|
void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
|
2008-05-02 06:18:59 +08:00
|
|
|
unsigned &Index) {
|
2008-05-20 04:00:43 +08:00
|
|
|
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
|
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
CheckListElementTypes(IList, T, true, Index);
|
2008-05-06 08:23:44 +08:00
|
|
|
IList->setType(T);
|
2008-05-25 21:22:35 +08:00
|
|
|
if (hadError)
|
|
|
|
return;
|
2008-05-20 04:00:43 +08:00
|
|
|
|
2008-05-25 21:22:35 +08:00
|
|
|
if (Index < IList->getNumInits()) {
|
2008-05-20 04:00:43 +08:00
|
|
|
// We have leftover initializers
|
|
|
|
if (IList->getNumInits() > 0 &&
|
|
|
|
SemaRef->IsStringLiteralInit(IList->getInit(Index), T)) {
|
2008-05-20 04:12:18 +08:00
|
|
|
// Special-case
|
2008-05-20 04:00:43 +08:00
|
|
|
SemaRef->Diag(IList->getInit(Index)->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::err_excess_initializers_in_char_array_initializer)
|
|
|
|
<< IList->getInit(Index)->getSourceRange();
|
2008-05-20 04:00:43 +08:00
|
|
|
hadError = true;
|
2008-05-20 13:25:56 +08:00
|
|
|
} else if (!T->isIncompleteType()) {
|
|
|
|
// Don't warn for incomplete types, since we'll get an error elsewhere
|
2008-05-20 04:00:43 +08:00
|
|
|
SemaRef->Diag(IList->getInit(Index)->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::warn_excess_initializers)
|
|
|
|
<< IList->getInit(Index)->getSourceRange();
|
2008-05-20 04:00:43 +08:00
|
|
|
}
|
|
|
|
}
|
2008-05-20 04:20:43 +08:00
|
|
|
|
2008-05-25 21:22:35 +08:00
|
|
|
if (T->isScalarType())
|
2008-11-19 13:27:50 +08:00
|
|
|
SemaRef->Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
|
|
|
|
<< IList->getSourceRange();
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
|
|
|
|
QualType &DeclType,
|
2009-01-23 07:26:18 +08:00
|
|
|
bool SubobjectIsDesignatorContext,
|
2008-05-20 03:16:24 +08:00
|
|
|
unsigned &Index) {
|
2008-05-20 04:00:43 +08:00
|
|
|
if (DeclType->isScalarType()) {
|
2009-01-22 08:58:24 +08:00
|
|
|
CheckScalarType(IList, DeclType, 0, Index);
|
2008-05-20 04:00:43 +08:00
|
|
|
} else if (DeclType->isVectorType()) {
|
2008-05-02 06:18:59 +08:00
|
|
|
CheckVectorType(IList, DeclType, Index);
|
2008-05-20 04:00:43 +08:00
|
|
|
} else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
|
2009-01-23 07:26:18 +08:00
|
|
|
if (DeclType->isStructureType() || DeclType->isUnionType()) {
|
|
|
|
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
|
|
|
|
CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
|
|
|
|
SubobjectIsDesignatorContext, Index);
|
|
|
|
} else if (DeclType->isArrayType()) {
|
2009-01-24 00:54:12 +08:00
|
|
|
llvm::APSInt Zero(
|
|
|
|
SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
|
|
|
|
false);
|
2009-01-23 07:26:18 +08:00
|
|
|
CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index);
|
|
|
|
}
|
2008-05-02 06:18:59 +08:00
|
|
|
else
|
|
|
|
assert(0 && "Aggregate that isn't a function or array?!");
|
2008-08-11 00:05:48 +08:00
|
|
|
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
|
|
|
|
// This type is invalid, issue a diagnostic.
|
2008-05-20 13:25:56 +08:00
|
|
|
Index++;
|
2008-11-20 14:38:18 +08:00
|
|
|
SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< DeclType;
|
2008-05-20 13:25:56 +08:00
|
|
|
hadError = true;
|
2008-05-02 06:18:59 +08:00
|
|
|
} else {
|
|
|
|
// In C, all types are either scalars or aggregates, but
|
|
|
|
// additional handling is needed here for C++ (and possibly others?).
|
|
|
|
assert(0 && "Unsupported initializer type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
void InitListChecker::CheckSubElementType(InitListExpr *IList,
|
|
|
|
QualType ElemType,
|
2009-01-22 08:58:24 +08:00
|
|
|
Expr *expr,
|
2008-05-20 03:16:24 +08:00
|
|
|
unsigned &Index) {
|
2008-05-20 04:00:43 +08:00
|
|
|
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
|
|
|
|
unsigned newIndex = 0;
|
|
|
|
CheckExplicitInitList(SubInitList, ElemType, newIndex);
|
|
|
|
Index++;
|
2008-05-20 03:16:24 +08:00
|
|
|
} else if (StringLiteral *lit =
|
|
|
|
SemaRef->IsStringLiteralInit(expr, ElemType)) {
|
|
|
|
SemaRef->CheckStringLiteralInit(lit, ElemType);
|
|
|
|
Index++;
|
2008-05-20 04:00:43 +08:00
|
|
|
} else if (ElemType->isScalarType()) {
|
2009-01-22 08:58:24 +08:00
|
|
|
CheckScalarType(IList, ElemType, expr, Index);
|
2008-05-20 03:16:24 +08:00
|
|
|
} else if (expr->getType()->getAsRecordType() &&
|
2008-06-09 11:52:40 +08:00
|
|
|
SemaRef->Context.typesAreCompatible(
|
|
|
|
expr->getType().getUnqualifiedType(),
|
|
|
|
ElemType.getUnqualifiedType())) {
|
2008-05-20 03:16:24 +08:00
|
|
|
Index++;
|
|
|
|
// FIXME: Add checking
|
|
|
|
} else {
|
|
|
|
CheckImplicitInitList(IList, ElemType, Index);
|
|
|
|
Index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
|
|
|
|
Expr *expr, unsigned &Index) {
|
2008-05-02 06:18:59 +08:00
|
|
|
if (Index < IList->getNumInits()) {
|
2009-01-22 08:58:24 +08:00
|
|
|
if (!expr)
|
|
|
|
expr = IList->getInit(Index);
|
2008-05-20 04:00:43 +08:00
|
|
|
if (isa<InitListExpr>(expr)) {
|
2008-05-20 04:12:18 +08:00
|
|
|
SemaRef->Diag(IList->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::err_many_braces_around_scalar_init)
|
|
|
|
<< IList->getSourceRange();
|
2008-05-20 04:12:18 +08:00
|
|
|
hadError = true;
|
|
|
|
++Index;
|
|
|
|
return;
|
2009-01-22 08:58:24 +08:00
|
|
|
} else if (isa<DesignatedInitExpr>(expr)) {
|
|
|
|
SemaRef->Diag(expr->getSourceRange().getBegin(),
|
|
|
|
diag::err_designator_for_scalar_init)
|
|
|
|
<< DeclType << expr->getSourceRange();
|
|
|
|
hadError = true;
|
|
|
|
++Index;
|
|
|
|
return;
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2008-05-20 04:00:43 +08:00
|
|
|
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
|
2009-01-14 23:45:31 +08:00
|
|
|
if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
|
2008-05-20 04:12:18 +08:00
|
|
|
hadError = true; // types weren't compatible.
|
2009-01-22 08:58:24 +08:00
|
|
|
else if (savExpr != expr) {
|
2008-05-20 04:00:43 +08:00
|
|
|
// The type was promoted, update initializer list.
|
2009-01-22 08:58:24 +08:00
|
|
|
if (DesignatedInitExpr *DIE
|
|
|
|
= dyn_cast<DesignatedInitExpr>(IList->getInit(Index)))
|
|
|
|
DIE->setInit(expr);
|
|
|
|
else
|
|
|
|
IList->setInit(Index, expr);
|
|
|
|
}
|
2008-05-02 06:18:59 +08:00
|
|
|
++Index;
|
2008-05-20 04:12:18 +08:00
|
|
|
} else {
|
2008-11-19 13:27:50 +08:00
|
|
|
SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
|
|
|
|
<< IList->getSourceRange();
|
2008-05-20 04:12:18 +08:00
|
|
|
hadError = true;
|
|
|
|
return;
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
|
|
|
|
unsigned &Index) {
|
|
|
|
if (Index < IList->getNumInits()) {
|
|
|
|
const VectorType *VT = DeclType->getAsVectorType();
|
|
|
|
int maxElements = VT->getNumElements();
|
|
|
|
QualType elementType = VT->getElementType();
|
|
|
|
|
|
|
|
for (int i = 0; i < maxElements; ++i) {
|
|
|
|
// Don't attempt to go past the end of the init list
|
|
|
|
if (Index >= IList->getNumInits())
|
|
|
|
break;
|
2009-01-22 08:58:24 +08:00
|
|
|
CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
|
2009-01-23 07:26:18 +08:00
|
|
|
llvm::APSInt elementIndex,
|
|
|
|
bool SubobjectIsDesignatorContext,
|
2008-05-02 06:18:59 +08:00
|
|
|
unsigned &Index) {
|
|
|
|
// Check for the special-case of initializing an array with a string.
|
|
|
|
if (Index < IList->getNumInits()) {
|
|
|
|
if (StringLiteral *lit =
|
|
|
|
SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) {
|
|
|
|
SemaRef->CheckStringLiteralInit(lit, DeclType);
|
|
|
|
++Index;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-08-04 15:31:14 +08:00
|
|
|
if (const VariableArrayType *VAT =
|
|
|
|
SemaRef->Context.getAsVariableArrayType(DeclType)) {
|
2008-05-25 21:22:35 +08:00
|
|
|
// Check for VLAs; in standard C it would be possible to check this
|
|
|
|
// earlier, but I don't know where clang accepts VLAs (gcc accepts
|
|
|
|
// them in all sorts of strange places).
|
|
|
|
SemaRef->Diag(VAT->getSizeExpr()->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::err_variable_object_no_init)
|
|
|
|
<< VAT->getSizeExpr()->getSourceRange();
|
2008-05-25 21:22:35 +08:00
|
|
|
hadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
// We might know the maximum number of elements in advance.
|
2009-01-24 02:58:42 +08:00
|
|
|
llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned());
|
2009-01-22 08:58:24 +08:00
|
|
|
bool maxElementsKnown = false;
|
|
|
|
if (const ConstantArrayType *CAT =
|
|
|
|
SemaRef->Context.getAsConstantArrayType(DeclType)) {
|
|
|
|
maxElements = CAT->getSize();
|
2009-01-24 00:54:12 +08:00
|
|
|
elementIndex.extOrTrunc(maxElements.getBitWidth());
|
2009-01-24 02:58:42 +08:00
|
|
|
elementIndex.setIsUnsigned(maxElements.isUnsigned());
|
2009-01-22 08:58:24 +08:00
|
|
|
maxElementsKnown = true;
|
|
|
|
}
|
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
QualType elementType = SemaRef->Context.getAsArrayType(DeclType)
|
|
|
|
->getElementType();
|
2009-01-22 08:58:24 +08:00
|
|
|
while (Index < IList->getNumInits()) {
|
|
|
|
Expr *Init = IList->getInit(Index);
|
|
|
|
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
|
2009-01-23 07:26:18 +08:00
|
|
|
// If we're not the subobject that matches up with the '{' for
|
|
|
|
// the designator, we shouldn't be handling the
|
|
|
|
// designator. Return immediately.
|
|
|
|
if (!SubobjectIsDesignatorContext)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Handle this designated initializer. elementIndex will be
|
|
|
|
// updated to be the next array element we'll initialize.
|
|
|
|
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
|
|
|
|
DeclType, 0, &elementIndex, Index)) {
|
2009-01-22 08:58:24 +08:00
|
|
|
hadError = true;
|
2009-01-23 07:26:18 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-01-24 00:54:12 +08:00
|
|
|
if (elementIndex.getBitWidth() > maxElements.getBitWidth())
|
|
|
|
maxElements.extend(elementIndex.getBitWidth());
|
|
|
|
else if (elementIndex.getBitWidth() < maxElements.getBitWidth())
|
|
|
|
elementIndex.extend(maxElements.getBitWidth());
|
2009-01-24 02:58:42 +08:00
|
|
|
elementIndex.setIsUnsigned(maxElements.isUnsigned());
|
2009-01-24 00:54:12 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// If the array is of incomplete type, keep track of the number of
|
|
|
|
// elements in the initializer.
|
|
|
|
if (!maxElementsKnown && elementIndex > maxElements)
|
|
|
|
maxElements = elementIndex;
|
2009-01-22 08:58:24 +08:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we know the maximum number of elements, and we've already
|
|
|
|
// hit it, stop consuming elements in the initializer list.
|
|
|
|
if (maxElementsKnown && elementIndex == maxElements)
|
2008-05-02 06:18:59 +08:00
|
|
|
break;
|
2009-01-22 08:58:24 +08:00
|
|
|
|
|
|
|
// Check this element.
|
|
|
|
CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
|
|
|
|
++elementIndex;
|
|
|
|
|
|
|
|
// If the array is of incomplete type, keep track of the number of
|
|
|
|
// elements in the initializer.
|
|
|
|
if (!maxElementsKnown && elementIndex > maxElements)
|
|
|
|
maxElements = elementIndex;
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
if (DeclType->isIncompleteArrayType()) {
|
|
|
|
// If this is an incomplete array type, the actual type needs to
|
2008-08-19 04:28:46 +08:00
|
|
|
// be calculated here.
|
2009-01-24 02:58:42 +08:00
|
|
|
llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned());
|
2009-01-22 08:58:24 +08:00
|
|
|
if (maxElements == Zero) {
|
2008-08-19 04:28:46 +08:00
|
|
|
// Sizing an array implicitly to zero is not allowed by ISO C,
|
|
|
|
// but is supported by GNU.
|
2008-05-02 06:18:59 +08:00
|
|
|
SemaRef->Diag(IList->getLocStart(),
|
2008-08-19 04:28:46 +08:00
|
|
|
diag::ext_typecheck_zero_array_size);
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
2008-08-19 04:28:46 +08:00
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
DeclType = SemaRef->Context.getConstantArrayType(elementType, maxElements,
|
2008-08-19 04:28:46 +08:00
|
|
|
ArrayType::Normal, 0);
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
|
|
|
|
QualType DeclType,
|
2009-01-23 07:26:18 +08:00
|
|
|
RecordDecl::field_iterator Field,
|
|
|
|
bool SubobjectIsDesignatorContext,
|
2008-05-20 03:16:24 +08:00
|
|
|
unsigned &Index) {
|
|
|
|
RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
|
2008-05-02 06:18:59 +08:00
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
// If the record is invalid, some of it's members are invalid. To avoid
|
|
|
|
// confusion, we forgo checking the intializer for the entire record.
|
|
|
|
if (structDecl->isInvalidDecl()) {
|
|
|
|
hadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
// If structDecl is a forward declaration, this loop won't do
|
|
|
|
// anything except look at designated initializers; That's okay,
|
|
|
|
// because an error should get printed out elsewhere. It might be
|
|
|
|
// worthwhile to skip over the rest of the initializer, though.
|
2008-12-12 00:49:14 +08:00
|
|
|
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
|
2009-01-23 07:26:18 +08:00
|
|
|
RecordDecl::field_iterator FieldEnd = RD->field_end();
|
2009-01-22 08:58:24 +08:00
|
|
|
while (Index < IList->getNumInits()) {
|
|
|
|
Expr *Init = IList->getInit(Index);
|
|
|
|
|
|
|
|
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
|
2009-01-23 07:26:18 +08:00
|
|
|
// If we're not the subobject that matches up with the '{' for
|
|
|
|
// the designator, we shouldn't be handling the
|
|
|
|
// designator. Return immediately.
|
|
|
|
if (!SubobjectIsDesignatorContext)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Handle this designated initializer. Field will be updated to
|
|
|
|
// the next field that we'll be initializing.
|
|
|
|
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
|
|
|
|
DeclType, &Field, 0, Index))
|
2009-01-22 08:58:24 +08:00
|
|
|
hadError = true;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Field == FieldEnd) {
|
|
|
|
// We've run out of fields. We're done.
|
2008-12-12 00:49:14 +08:00
|
|
|
break;
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
// If we've hit the flexible array member at the end, we're done.
|
|
|
|
if (Field->getType()->isIncompleteArrayType())
|
2008-05-20 03:16:24 +08:00
|
|
|
break;
|
2008-12-12 00:49:14 +08:00
|
|
|
|
|
|
|
if (!Field->getIdentifier()) {
|
2008-05-20 03:16:24 +08:00
|
|
|
// Don't initialize unnamed fields, e.g. "int : 20;"
|
2009-01-22 08:58:24 +08:00
|
|
|
++Field;
|
2008-05-20 03:16:24 +08:00
|
|
|
continue;
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
|
|
|
|
if (DeclType->isUnionType()) // FIXME: designated initializers?
|
2008-05-20 03:16:24 +08:00
|
|
|
break;
|
2009-01-22 08:58:24 +08:00
|
|
|
|
|
|
|
++Field;
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2008-05-20 03:16:24 +08:00
|
|
|
// FIXME: Implement flexible array initialization GCC extension (it's a
|
|
|
|
// really messy extension to implement, unfortunately...the necessary
|
|
|
|
// information isn't actually even here!)
|
2008-05-02 06:18:59 +08:00
|
|
|
}
|
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
/// @brief Check the well-formedness of a C99 designated initializer.
|
|
|
|
///
|
|
|
|
/// Determines whether the designated initializer @p DIE, which
|
|
|
|
/// resides at the given @p Index within the initializer list @p
|
|
|
|
/// IList, is well-formed for a current object of type @p DeclType
|
|
|
|
/// (C99 6.7.8). The actual subobject that this designator refers to
|
|
|
|
/// within the current subobject is returned in either
|
|
|
|
/// @p DesignatedField or @p DesignatedIndex (whichever is
|
|
|
|
/// appropriate).
|
|
|
|
///
|
|
|
|
/// @param IList The initializer list in which this designated
|
|
|
|
/// initializer occurs.
|
|
|
|
///
|
|
|
|
/// @param DIE The designated initializer and its initialization
|
|
|
|
/// expression.
|
|
|
|
///
|
|
|
|
/// @param DeclType The type of the "current object" (C99 6.7.8p17),
|
|
|
|
/// into which the designation in @p DIE should refer.
|
|
|
|
///
|
2009-01-23 07:26:18 +08:00
|
|
|
/// @param NextField If non-NULL and the first designator in @p DIE is
|
|
|
|
/// a field, this will be set to the field declaration corresponding
|
|
|
|
/// to the field named by the designator.
|
2009-01-22 08:58:24 +08:00
|
|
|
///
|
2009-01-23 07:26:18 +08:00
|
|
|
/// @param NextElementIndex If non-NULL and the first designator in @p
|
|
|
|
/// DIE is an array designator or GNU array-range designator, this
|
|
|
|
/// will be set to the last index initialized by this designator.
|
2009-01-22 08:58:24 +08:00
|
|
|
///
|
|
|
|
/// @param Index Index into @p IList where the designated initializer
|
|
|
|
/// @p DIE occurs.
|
|
|
|
///
|
|
|
|
/// @returns true if there was an error, false otherwise.
|
2009-01-23 07:26:18 +08:00
|
|
|
bool
|
|
|
|
InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
|
|
|
|
DesignatedInitExpr *DIE,
|
|
|
|
DesignatedInitExpr::designators_iterator D,
|
|
|
|
QualType &CurrentObjectType,
|
|
|
|
RecordDecl::field_iterator *NextField,
|
|
|
|
llvm::APSInt *NextElementIndex,
|
|
|
|
unsigned &Index) {
|
|
|
|
bool IsFirstDesignator = (D == DIE->designators_begin());
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
if (D == DIE->designators_end()) {
|
|
|
|
// Check the actual initialization for the designated object type.
|
|
|
|
bool prevHadError = hadError;
|
|
|
|
CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index);
|
|
|
|
return hadError && !prevHadError;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
if (D->isFieldDesignator()) {
|
|
|
|
// C99 6.7.8p7:
|
|
|
|
//
|
|
|
|
// If a designator has the form
|
|
|
|
//
|
|
|
|
// . identifier
|
|
|
|
//
|
|
|
|
// then the current object (defined below) shall have
|
|
|
|
// structure or union type and the identifier shall be the
|
|
|
|
// name of a member of that type.
|
|
|
|
const RecordType *RT = CurrentObjectType->getAsRecordType();
|
|
|
|
if (!RT) {
|
|
|
|
SourceLocation Loc = D->getDotLoc();
|
|
|
|
if (Loc.isInvalid())
|
|
|
|
Loc = D->getFieldLoc();
|
|
|
|
SemaRef->Diag(Loc, diag::err_field_designator_non_aggr)
|
|
|
|
<< SemaRef->getLangOptions().CPlusPlus << CurrentObjectType;
|
|
|
|
++Index;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *FieldName = D->getFieldName();
|
|
|
|
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
|
|
|
|
FieldDecl *DesignatedField = 0;
|
|
|
|
if (Lookup.first == Lookup.second) {
|
|
|
|
// Lookup did not find anything with this name.
|
|
|
|
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
|
|
|
|
<< FieldName << CurrentObjectType;
|
|
|
|
} else if (isa<FieldDecl>(*Lookup.first)) {
|
|
|
|
// Name lookup found a field.
|
|
|
|
DesignatedField = cast<FieldDecl>(*Lookup.first);
|
|
|
|
// FIXME: Make sure this isn't a field in an anonymous
|
|
|
|
// struct/union.
|
|
|
|
} else {
|
|
|
|
// Name lookup found something, but it wasn't a field.
|
|
|
|
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
|
|
|
|
<< FieldName;
|
|
|
|
SemaRef->Diag((*Lookup.first)->getLocation(),
|
|
|
|
diag::note_field_designator_found);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DesignatedField) {
|
|
|
|
++Index;
|
|
|
|
return true;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// Update the designator with the field declaration.
|
|
|
|
D->setField(DesignatedField);
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// Recurse to check later designated subobjects.
|
|
|
|
QualType FieldType = DesignatedField->getType();
|
|
|
|
if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Find the position of the next field to be initialized in this
|
|
|
|
// subobject.
|
|
|
|
RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField),
|
|
|
|
RT->getDecl()->decls_end());
|
|
|
|
++Field;
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// If this the first designator, our caller will continue checking
|
|
|
|
// the rest of this struct/class/union subobject.
|
|
|
|
if (IsFirstDesignator) {
|
|
|
|
if (NextField)
|
|
|
|
*NextField = Field;
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// Check the remaining fields within this class/struct/union subobject.
|
|
|
|
bool prevHadError = hadError;
|
|
|
|
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index);
|
|
|
|
return hadError && !prevHadError;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
// C99 6.7.8p6:
|
|
|
|
//
|
|
|
|
// If a designator has the form
|
|
|
|
//
|
|
|
|
// [ constant-expression ]
|
|
|
|
//
|
|
|
|
// then the current object (defined below) shall have array
|
|
|
|
// type and the expression shall be an integer constant
|
|
|
|
// expression. If the array is of unknown size, any
|
|
|
|
// nonnegative value is valid.
|
|
|
|
//
|
|
|
|
// Additionally, cope with the GNU extension that permits
|
|
|
|
// designators of the form
|
|
|
|
//
|
|
|
|
// [ constant-expression ... constant-expression ]
|
|
|
|
const ArrayType *AT = SemaRef->Context.getAsArrayType(CurrentObjectType);
|
|
|
|
if (!AT) {
|
|
|
|
SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
|
|
|
|
<< CurrentObjectType;
|
|
|
|
++Index;
|
|
|
|
return true;
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
Expr *IndexExpr = 0;
|
|
|
|
llvm::APSInt DesignatedIndex;
|
|
|
|
if (D->isArrayDesignator())
|
|
|
|
IndexExpr = DIE->getArrayIndex(*D);
|
|
|
|
else {
|
|
|
|
assert(D->isArrayRangeDesignator() && "Need array-range designator");
|
|
|
|
IndexExpr = DIE->getArrayRangeEnd(*D);
|
|
|
|
}
|
2009-01-22 08:58:24 +08:00
|
|
|
|
2009-01-23 07:26:18 +08:00
|
|
|
bool ConstExpr
|
|
|
|
= IndexExpr->isIntegerConstantExpr(DesignatedIndex, SemaRef->Context);
|
|
|
|
assert(ConstExpr && "Expression must be constant"); (void)ConstExpr;
|
|
|
|
|
|
|
|
if (isa<ConstantArrayType>(AT)) {
|
|
|
|
llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
|
2009-01-24 00:54:12 +08:00
|
|
|
DesignatedIndex.extOrTrunc(MaxElements.getBitWidth());
|
2009-01-24 02:58:42 +08:00
|
|
|
DesignatedIndex.setIsUnsigned(MaxElements.isUnsigned());
|
2009-01-23 07:26:18 +08:00
|
|
|
if (DesignatedIndex >= MaxElements) {
|
|
|
|
SemaRef->Diag(IndexExpr->getSourceRange().getBegin(),
|
|
|
|
diag::err_array_designator_too_large)
|
|
|
|
<< DesignatedIndex.toString(10) << MaxElements.toString(10)
|
|
|
|
<< IndexExpr->getSourceRange();
|
|
|
|
++Index;
|
|
|
|
return true;
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
}
|
2009-01-23 07:26:18 +08:00
|
|
|
|
|
|
|
// Recurse to check later designated subobjects.
|
|
|
|
QualType ElementType = AT->getElementType();
|
|
|
|
if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Move to the next index in the array that we'll be initializing.
|
|
|
|
++DesignatedIndex;
|
|
|
|
|
|
|
|
// If this the first designator, our caller will continue checking
|
|
|
|
// the rest of this array subobject.
|
|
|
|
if (IsFirstDesignator) {
|
|
|
|
if (NextElementIndex)
|
|
|
|
*NextElementIndex = DesignatedIndex;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the remaining elements within this array subobject.
|
2009-01-22 08:58:24 +08:00
|
|
|
bool prevHadError = hadError;
|
2009-01-23 07:26:18 +08:00
|
|
|
CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index);
|
|
|
|
return hadError && !prevHadError;
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that the given Index expression is a valid array designator
|
|
|
|
/// value. This is essentailly just a wrapper around
|
|
|
|
/// Expr::isIntegerConstantExpr that also checks for negative values
|
|
|
|
/// and produces a reasonable diagnostic if there is a
|
|
|
|
/// failure. Returns true if there was an error, false otherwise. If
|
|
|
|
/// everything went okay, Value will receive the value of the constant
|
|
|
|
/// expression.
|
|
|
|
static bool
|
|
|
|
CheckArrayDesignatorExpr(Sema &Self, Expr *Index, llvm::APSInt &Value) {
|
|
|
|
SourceLocation Loc = Index->getSourceRange().getBegin();
|
|
|
|
|
|
|
|
// Make sure this is an integer constant expression.
|
|
|
|
if (!Index->isIntegerConstantExpr(Value, Self.Context, &Loc))
|
|
|
|
return Self.Diag(Loc, diag::err_array_designator_nonconstant)
|
|
|
|
<< Index->getSourceRange();
|
|
|
|
|
|
|
|
// Make sure this constant expression is non-negative.
|
2009-01-24 02:58:42 +08:00
|
|
|
llvm::APSInt Zero(llvm::APSInt::getNullValue(Value.getBitWidth()),
|
|
|
|
Value.isUnsigned());
|
2009-01-22 08:58:24 +08:00
|
|
|
if (Value < Zero)
|
|
|
|
return Self.Diag(Loc, diag::err_array_designator_negative)
|
|
|
|
<< Value.toString(10) << Index->getSourceRange();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
|
|
|
|
SourceLocation Loc,
|
|
|
|
bool UsedColonSyntax,
|
|
|
|
OwningExprResult Init) {
|
|
|
|
typedef DesignatedInitExpr::Designator ASTDesignator;
|
|
|
|
|
|
|
|
bool Invalid = false;
|
|
|
|
llvm::SmallVector<ASTDesignator, 32> Designators;
|
|
|
|
llvm::SmallVector<Expr *, 32> InitExpressions;
|
|
|
|
|
|
|
|
// Build designators and check array designator expressions.
|
|
|
|
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
|
|
|
|
const Designator &D = Desig.getDesignator(Idx);
|
|
|
|
switch (D.getKind()) {
|
|
|
|
case Designator::FieldDesignator:
|
|
|
|
Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
|
|
|
|
D.getFieldLoc()));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Designator::ArrayDesignator: {
|
|
|
|
Expr *Index = static_cast<Expr *>(D.getArrayIndex());
|
|
|
|
llvm::APSInt IndexValue;
|
|
|
|
if (CheckArrayDesignatorExpr(*this, Index, IndexValue))
|
|
|
|
Invalid = true;
|
|
|
|
else {
|
|
|
|
Designators.push_back(ASTDesignator(InitExpressions.size(),
|
|
|
|
D.getLBracketLoc(),
|
|
|
|
D.getRBracketLoc()));
|
|
|
|
InitExpressions.push_back(Index);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Designator::ArrayRangeDesignator: {
|
|
|
|
Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
|
|
|
|
Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
|
|
|
|
llvm::APSInt StartValue;
|
|
|
|
llvm::APSInt EndValue;
|
|
|
|
if (CheckArrayDesignatorExpr(*this, StartIndex, StartValue) ||
|
|
|
|
CheckArrayDesignatorExpr(*this, EndIndex, EndValue))
|
|
|
|
Invalid = true;
|
|
|
|
else if (EndValue < StartValue) {
|
|
|
|
Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
|
|
|
|
<< StartValue.toString(10) << EndValue.toString(10)
|
|
|
|
<< StartIndex->getSourceRange() << EndIndex->getSourceRange();
|
|
|
|
Invalid = true;
|
|
|
|
} else {
|
|
|
|
Designators.push_back(ASTDesignator(InitExpressions.size(),
|
|
|
|
D.getLBracketLoc(),
|
|
|
|
D.getEllipsisLoc(),
|
|
|
|
D.getRBracketLoc()));
|
|
|
|
InitExpressions.push_back(StartIndex);
|
|
|
|
InitExpressions.push_back(EndIndex);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Invalid || Init.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
// Clear out the expressions within the designation.
|
|
|
|
Desig.ClearExprs(*this);
|
|
|
|
|
|
|
|
DesignatedInitExpr *DIE
|
|
|
|
= DesignatedInitExpr::Create(Context, &Designators[0], Designators.size(),
|
|
|
|
&InitExpressions[0], InitExpressions.size(),
|
|
|
|
Loc, UsedColonSyntax,
|
|
|
|
static_cast<Expr *>(Init.release()));
|
|
|
|
return Owned(DIE);
|
|
|
|
}
|