aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r--lib/Sema/SemaInit.cpp391
1 files changed, 358 insertions, 33 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index f9c91ecaab..163dac94b9 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/Diagnostic.h"
#include <algorithm> // for std::count_if
#include <functional> // for std::mem_fun
-namespace clang {
+using namespace clang;
InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
hadError = false;
@@ -131,7 +132,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
QualType &DeclType,
unsigned &Index) {
if (DeclType->isScalarType()) {
- CheckScalarType(IList, DeclType, Index);
+ CheckScalarType(IList, DeclType, 0, Index);
} else if (DeclType->isVectorType()) {
CheckVectorType(IList, DeclType, Index);
} else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
@@ -156,8 +157,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
void InitListChecker::CheckSubElementType(InitListExpr *IList,
QualType ElemType,
+ Expr *expr,
unsigned &Index) {
- Expr* expr = IList->getInit(Index);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
CheckExplicitInitList(SubInitList, ElemType, newIndex);
@@ -167,7 +168,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
SemaRef->CheckStringLiteralInit(lit, ElemType);
Index++;
} else if (ElemType->isScalarType()) {
- CheckScalarType(IList, ElemType, Index);
+ CheckScalarType(IList, ElemType, expr, Index);
} else if (expr->getType()->getAsRecordType() &&
SemaRef->Context.typesAreCompatible(
expr->getType().getUnqualifiedType(),
@@ -180,10 +181,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
}
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
- unsigned &Index) {
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
+ Expr *expr, unsigned &Index) {
if (Index < IList->getNumInits()) {
- Expr* expr = IList->getInit(Index);
+ if (!expr)
+ expr = IList->getInit(Index);
if (isa<InitListExpr>(expr)) {
SemaRef->Diag(IList->getLocStart(),
diag::err_many_braces_around_scalar_init)
@@ -191,13 +193,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
hadError = true;
++Index;
return;
+ } else if (isa<DesignatedInitExpr>(expr)) {
+ SemaRef->Diag(expr->getSourceRange().getBegin(),
+ diag::err_designator_for_scalar_init)
+ << DeclType << expr->getSourceRange();
+ hadError = true;
+ ++Index;
+ return;
}
+
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
hadError = true; // types weren't compatible.
- else if (savExpr != expr)
+ else if (savExpr != expr) {
// The type was promoted, update initializer list.
- IList->setInit(Index, expr);
+ if (DesignatedInitExpr *DIE
+ = dyn_cast<DesignatedInitExpr>(IList->getInit(Index)))
+ DIE->setInit(expr);
+ else
+ IList->setInit(Index, expr);
+ }
++Index;
} else {
SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
@@ -218,7 +233,7 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
- CheckSubElementType(IList, elementType, Index);
+ CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
}
}
}
@@ -246,29 +261,63 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
return;
}
- int maxElements = numArrayElements(DeclType);
+ // FIXME: Will 32 bits always be enough? I hope so.
+ const unsigned ArraySizeBits = 32;
+ llvm::APSInt elementIndex(ArraySizeBits, 0);
+
+ // We might know the maximum number of elements in advance.
+ llvm::APSInt maxElements(ArraySizeBits, 0);
+ bool maxElementsKnown = false;
+ if (const ConstantArrayType *CAT =
+ SemaRef->Context.getAsConstantArrayType(DeclType)) {
+ maxElements = CAT->getSize();
+ maxElementsKnown = true;
+ }
+
QualType elementType = SemaRef->Context.getAsArrayType(DeclType)
->getElementType();
- int numElements = 0;
- for (int i = 0; i < maxElements; ++i, ++numElements) {
- // Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // C99 6.7.8p17:
+ // [...] In contrast, a designation causes the following
+ // initializer to begin initialization of the subobject
+ // described by the designator.
+ FieldDecl *DesignatedField = 0;
+ if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField,
+ elementIndex, Index))
+ hadError = true;
+
+ ++elementIndex;
+ 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)
break;
- CheckSubElementType(IList, elementType, Index);
+
+ // 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;
}
if (DeclType->isIncompleteArrayType()) {
// If this is an incomplete array type, the actual type needs to
// be calculated here.
- if (numElements == 0) {
+ llvm::APInt Zero(ArraySizeBits, 0);
+ if (maxElements == Zero) {
// Sizing an array implicitly to zero is not allowed by ISO C,
// but is supported by GNU.
SemaRef->Diag(IList->getLocStart(),
diag::ext_typecheck_zero_array_size);
}
- llvm::APSInt ConstVal(32);
- ConstVal = numElements;
- DeclType = SemaRef->Context.getConstantArrayType(elementType, ConstVal,
+ DeclType = SemaRef->Context.getConstantArrayType(elementType, maxElements,
ArrayType::Normal, 0);
}
}
@@ -284,34 +333,310 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
hadError = true;
return;
}
- // If structDecl is a forward declaration, this loop won't do anything;
- // That's okay, because an error should get printed out elsewhere. It
- // might be worthwhile to skip over the rest of the initializer, though.
+ // 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.
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- // If we've hit the flexible array member at the end, we're done.
- if (Field->getType()->isIncompleteArrayType())
+ RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // C99 6.7.8p17:
+ // [...] In contrast, a designation causes the following
+ // initializer to begin initialization of the subobject
+ // described by the designator. Initialization then continues
+ // forward in order, beginning with the next subobject after
+ // that described by the designator.
+ FieldDecl *DesignatedField = 0;
+ llvm::APSInt LastElement;
+ if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField,
+ LastElement, Index)) {
+ hadError = true;
+ continue;
+ }
+
+ Field = RecordDecl::field_iterator(
+ DeclContext::decl_iterator(DesignatedField),
+ DeclType->getAsRecordType()->getDecl()->decls_end());
+ ++Field;
+ continue;
+ }
+
+ if (Field == FieldEnd) {
+ // We've run out of fields. We're done.
break;
+ }
- // Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
+ // If we've hit the flexible array member at the end, we're done.
+ if (Field->getType()->isIncompleteArrayType())
break;
if (!Field->getIdentifier()) {
// Don't initialize unnamed fields, e.g. "int : 20;"
+ ++Field;
continue;
}
- CheckSubElementType(IList, Field->getType(), Index);
- if (DeclType->isUnionType())
+ CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+ if (DeclType->isUnionType()) // FIXME: designated initializers?
break;
+
+ ++Field;
}
// FIXME: Implement flexible array initialization GCC extension (it's a
// really messy extension to implement, unfortunately...the necessary
// information isn't actually even here!)
}
-} // end namespace clang
+/// @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.
+///
+/// @param DesignatedField If 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.
+///
+/// @param DesignatedIndex If 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.
+///
+/// @param Index Index into @p IList where the designated initializer
+/// @p DIE occurs.
+///
+/// @returns true if there was an error, false otherwise.
+bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+ DesignatedInitExpr *DIE,
+ QualType DeclType,
+ FieldDecl *&DesignatedField,
+ llvm::APSInt &DesignatedIndex,
+ unsigned &Index) {
+ // DeclType is always the type of the "current object" (C99 6.7.8p17).
+
+ for (DesignatedInitExpr::designators_iterator D = DIE->designators_begin(),
+ DEnd = DIE->designators_end();
+ D != DEnd; ++D) {
+ 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 = DeclType->getAsRecordType();
+ if (!RT) {
+ SemaRef->Diag(DIE->getSourceRange().getBegin(),
+ diag::err_field_designator_non_aggr)
+ << SemaRef->getLangOptions().CPlusPlus << DeclType;
+ ++Index;
+ return true;
+ }
+
+ IdentifierInfo *FieldName = D->getFieldName();
+ DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ FieldDecl *ThisField = 0;
+ if (Lookup.first == Lookup.second) {
+ // Lookup did not find anything with this name.
+ SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+ << FieldName << DeclType;
+ } else if (isa<FieldDecl>(*Lookup.first)) {
+ // Name lookup found a field.
+ ThisField = 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 (!ThisField) {
+ ++Index;
+ return true;
+ }
+
+ // Update the designator with the field declaration.
+ D->setField(ThisField);
+
+ if (D == DIE->designators_begin())
+ DesignatedField = ThisField;
+
+ // The current object is now the type of this field.
+ DeclType = ThisField->getType();
+ } else {
+ // 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.
+ const ArrayType *AT = SemaRef->Context.getAsArrayType(DeclType);
+ if (!AT) {
+ SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
+ << DeclType;
+ ++Index;
+ return true;
+ }
+
+ Expr *IndexExpr = 0;
+ llvm::APSInt ThisIndex;
+ if (D->isArrayDesignator())
+ IndexExpr = DIE->getArrayIndex(*D);
+ else {
+ assert(D->isArrayRangeDesignator() && "Need array-range designator");
+ IndexExpr = DIE->getArrayRangeEnd(*D);
+ }
+
+ bool ConstExpr
+ = IndexExpr->isIntegerConstantExpr(ThisIndex, SemaRef->Context);
+ assert(ConstExpr && "Expression must be constant"); (void)ConstExpr;
+
+ if (isa<ConstantArrayType>(AT)) {
+ llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
+ if (ThisIndex >= MaxElements) {
+ SemaRef->Diag(IndexExpr->getSourceRange().getBegin(),
+ diag::err_array_designator_too_large)
+ << ThisIndex.toString(10) << MaxElements.toString(10);
+ ++Index;
+ return true;
+ }
+ }
+
+ if (D == DIE->designators_begin())
+ DesignatedIndex = ThisIndex;
+
+ // The current object is now the element type of this array.
+ DeclType = AT->getElementType();
+ }
+ }
+
+ // Check the actual initialization for the designated object type.
+ bool prevHadError = hadError;
+ CheckSubElementType(IList, DeclType, DIE->getInit(), Index);
+ return hadError && !prevHadError;
+}
+
+/// 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.
+ llvm::APSInt Zero(llvm::APSInt::getNullValue(Value.getBitWidth()), false);
+ 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);
+}