From 9ea62768fca25d829d80199cf4f8cf0f4dd39251 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 21 May 2009 23:17:49 +0000 Subject: [PATCH] Template instantiation for C99 designated initializers, because we can. Also, delay semantic analysis of initialization for value-dependent as well as type-dependent expressions, since we can't always properly type-check a value-dependent expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72233 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 7 ++- lib/AST/Expr.cpp | 77 +++++++++++++++--------- lib/Sema/SemaInit.cpp | 21 +++++-- lib/Sema/SemaTemplateInstantiateExpr.cpp | 61 ++++++++++++++++++- test/SemaTemplate/fun-template-def.cpp | 4 +- test/SemaTemplate/instantiate-c99.cpp | 56 +++++++++++++++++ 6 files changed, 187 insertions(+), 39 deletions(-) create mode 100644 test/SemaTemplate/instantiate-c99.cpp diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 0a42be9f5c..79cd510f21 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -41,6 +41,7 @@ namespace clang { class Expr : public Stmt { QualType TR; +protected: /// TypeDependent - Whether this expression is type-dependent /// (C++ [temp.dep.expr]). bool TypeDependent : 1; @@ -49,7 +50,6 @@ class Expr : public Stmt { /// (C++ [temp.dep.constexpr]). bool ValueDependent : 1; -protected: // FIXME: Eventually, this constructor should go away and we should // require every subclass to provide type/value-dependence // information. @@ -2074,7 +2074,8 @@ private: DesignatedInitExpr(QualType Ty, unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, - unsigned NumSubExprs); + Expr **IndexExprs, unsigned NumIndexExprs, + Expr *Init); explicit DesignatedInitExpr(unsigned NumSubExprs) : Expr(DesignatedInitExprClass, EmptyShell()), @@ -2337,6 +2338,8 @@ public: return SourceRange(); } + ImplicitValueInitExpr *Clone(ASTContext &C) const; + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2df76a2904..81936efb08 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -385,7 +385,9 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) - : Expr(InitListExprClass, QualType()), + : Expr(InitListExprClass, QualType(), + hasAnyTypeDependentArguments(initExprs, numInits), + hasAnyValueDependentArguments(initExprs, numInits)), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { @@ -1632,13 +1634,48 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, - unsigned NumSubExprs) - : Expr(DesignatedInitExprClass, Ty), + Expr **IndexExprs, + unsigned NumIndexExprs, + Expr *Init) + : Expr(DesignatedInitExprClass, Ty, + Init->isTypeDependent(), Init->isValueDependent()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), - NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { this->Designators = new Designator[NumDesignators]; - for (unsigned I = 0; I != NumDesignators; ++I) + + // Record the initializer itself. + child_iterator Child = child_begin(); + *Child++ = Init; + + // Copy the designators and their subexpressions, computing + // value-dependence along the way. + unsigned IndexIdx = 0; + for (unsigned I = 0; I != NumDesignators; ++I) { this->Designators[I] = Designators[I]; + + if (this->Designators[I].isArrayDesignator()) { + // Compute type- and value-dependence. + Expr *Index = IndexExprs[IndexIdx]; + ValueDependent = ValueDependent || + Index->isTypeDependent() || Index->isValueDependent(); + + // Copy the index expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + } else if (this->Designators[I].isArrayRangeDesignator()) { + // Compute type- and value-dependence. + Expr *Start = IndexExprs[IndexIdx]; + Expr *End = IndexExprs[IndexIdx + 1]; + ValueDependent = ValueDependent || + Start->isTypeDependent() || Start->isValueDependent() || + End->isTypeDependent() || End->isValueDependent(); + + // Copy the start/end expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + *Child++ = IndexExprs[IndexIdx++]; + } + } + + assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions"); } DesignatedInitExpr * @@ -1649,29 +1686,9 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); - DesignatedInitExpr *DIE - = new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators, - ColonOrEqualLoc, UsesColonSyntax, - NumIndexExprs + 1); - - // Fill in the designators - unsigned ExpectedNumSubExprs = 0; - designators_iterator Desig = DIE->designators_begin(); - for (unsigned Idx = 0; Idx < NumDesignators; ++Idx, ++Desig) { - if (Designators[Idx].isArrayDesignator()) - ++ExpectedNumSubExprs; - else if (Designators[Idx].isArrayRangeDesignator()) - ExpectedNumSubExprs += 2; - } - assert(ExpectedNumSubExprs == NumIndexExprs && "Wrong number of indices!"); - - // Fill in the subexpressions, including the initializer expression. - child_iterator Child = DIE->child_begin(); - *Child++ = Init; - for (unsigned Idx = 0; Idx < NumIndexExprs; ++Idx, ++Child) - *Child = IndexExprs[Idx]; - - return DIE; + return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators, + ColonOrEqualLoc, UsesColonSyntax, + IndexExprs, NumIndexExprs, Init); } DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, @@ -1766,6 +1783,10 @@ void DesignatedInitExpr::Destroy(ASTContext &C) { Expr::Destroy(C); } +ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const { + return new (C) ImplicitValueInitExpr(getType()); +} + //===----------------------------------------------------------------------===// // ExprIterator. //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f3ad2a1b32..126b3869fe 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -117,7 +117,8 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, SourceLocation InitLoc, DeclarationName InitEntity, bool DirectInit) { - if (DeclType->isDependentType() || Init->isTypeDependent()) + if (DeclType->isDependentType() || + Init->isTypeDependent() || Init->isValueDependent()) return false; // C++ [dcl.init.ref]p1: @@ -1635,7 +1636,9 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, case Designator::ArrayDesignator: { Expr *Index = static_cast(D.getArrayIndex()); llvm::APSInt IndexValue; - if (CheckArrayDesignatorExpr(*this, Index, IndexValue)) + if (!Index->isTypeDependent() && + !Index->isValueDependent() && + CheckArrayDesignatorExpr(*this, Index, IndexValue)) Invalid = true; else { Designators.push_back(ASTDesignator(InitExpressions.size(), @@ -1651,12 +1654,20 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, Expr *EndIndex = static_cast(D.getArrayRangeEnd()); llvm::APSInt StartValue; llvm::APSInt EndValue; - if (CheckArrayDesignatorExpr(*this, StartIndex, StartValue) || - CheckArrayDesignatorExpr(*this, EndIndex, EndValue)) + bool StartDependent = StartIndex->isTypeDependent() || + StartIndex->isValueDependent(); + bool EndDependent = EndIndex->isTypeDependent() || + EndIndex->isValueDependent(); + if ((!StartDependent && + CheckArrayDesignatorExpr(*this, StartIndex, StartValue)) || + (!EndDependent && + CheckArrayDesignatorExpr(*this, EndIndex, EndValue))) Invalid = true; else { // Make sure we're comparing values with the same bit width. - if (StartValue.getBitWidth() > EndValue.getBitWidth()) + if (StartDependent || EndDependent) { + // Nothing to compute. + } else if (StartValue.getBitWidth() > EndValue.getBitWidth()) EndValue.extend(StartValue.getBitWidth()); else if (StartValue.getBitWidth() < EndValue.getBitWidth()) StartValue.extend(EndValue.getBitWidth()); diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 283b0d35a2..38f9245721 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Designator.h" #include "clang/Lex/Preprocessor.h" // for the identifier table #include "llvm/Support/Compiler.h" using namespace clang; @@ -61,8 +62,8 @@ namespace { OwningExprResult VisitChooseExpr(ChooseExpr *E); OwningExprResult VisitVAArgExpr(VAArgExpr *E); OwningExprResult VisitInitListExpr(InitListExpr *E); - // FIXME: DesignatedInitExpr - // FIXME: ImplicitValueInitExpr + OwningExprResult VisitDesignatedInitExpr(DesignatedInitExpr *E); + OwningExprResult VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); // FIXME: ExtVectorElementExpr // FIXME: BlockExpr // FIXME: BlockDeclRefExpr @@ -594,6 +595,62 @@ TemplateExprInstantiator::VisitInitListExpr(InitListExpr *E) { E->getRBraceLoc()); } +Sema::OwningExprResult +TemplateExprInstantiator::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + Designation Desig; + + // Instantiate the initializer value + OwningExprResult Init = Visit(E->getInit()); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + // Instantiate the designators. + ExprVector ArrayExprs(SemaRef); // Expresses used in array designators + for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), + DEnd = E->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + Desig.AddDesignator(Designator::getField(D->getFieldName(), + D->getDotLoc(), + D->getFieldLoc())); + continue; + } + + if (D->isArrayDesignator()) { + OwningExprResult Index = Visit(E->getArrayIndex(*D)); + if (Index.isInvalid()) + return SemaRef.ExprError(); + + Desig.AddDesignator(Designator::getArray(Index.get(), + D->getLBracketLoc())); + + ArrayExprs.push_back(Index.release()); + continue; + } + + assert(false && "No array range designators, yet"); + } + + OwningExprResult Result = + SemaRef.ActOnDesignatedInitializer(Desig, + E->getEqualOrColonLoc(), + E->usesGNUSyntax(), + move(Init)); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + ArrayExprs.take(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitImplicitValueInitExpr( + ImplicitValueInitExpr *E) { + assert(!E->isTypeDependent() && !E->isValueDependent() && + "ImplicitValueInitExprs are never dependent"); + return SemaRef.Clone(E); +} + Sema::OwningExprResult TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { bool isSizeOf = E->isSizeOf(); diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp index fdcf6ee92c..8833ef4ddc 100644 --- a/test/SemaTemplate/fun-template-def.cpp +++ b/test/SemaTemplate/fun-template-def.cpp @@ -34,9 +34,9 @@ T f(T t1, U u1, int i1) new (t1, u1) int; delete t1; - dummy d1 = sizeof(t1); // expected-error {{cannot initialize 'd1'}} + dummy d1 = sizeof(t1); // FIXME: delayed checking okay? dummy d2 = offsetof(T, foo); // expected-error {{cannot initialize 'd2'}} - dummy d3 = __alignof(u1); // expected-error {{cannot initialize 'd3'}} + dummy d3 = __alignof(u1); // FIXME: delayed checking okay? i1 = typeid(t1); // expected-error {{incompatible type assigning}} return u1; diff --git a/test/SemaTemplate/instantiate-c99.cpp b/test/SemaTemplate/instantiate-c99.cpp new file mode 100644 index 0000000000..a6d4dc994b --- /dev/null +++ b/test/SemaTemplate/instantiate-c99.cpp @@ -0,0 +1,56 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Test template instantiation for C99-specific features. + +// --------------------------------------------------------------------- +// Designated initializers +// --------------------------------------------------------------------- +template +struct DesigInit0 { + void f(XType x, YType y) { + T agg = { + .y = y, // expected-error{{does not refer}} + .x = x // expected-error{{does not refer}} + }; + } +}; + +struct Point2D { + float x, y; +}; + +template struct DesigInit0; + +struct Point3D { + float x, y, z; +}; + +template struct DesigInit0; + +struct Color { + unsigned char red, green, blue; +}; + +struct ColorPoint3D { + Color color; + float x, y, z; +}; + +template struct DesigInit0; +template struct DesigInit0; // expected-note{{instantiation}} + +template +struct DesigArrayInit0 { + void f(Val1 val1, Val2 val2) { + T array = { + [Subscript1] = val1, + [Subscript2] = val2 // expected-error{{exceeds array bounds}} + }; + + int array2[10] = { [5] = 3 }; + } +}; + +template struct DesigArrayInit0; +template struct DesigArrayInit0; // expected-note{{instantiation}}