diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/AST/ASTContext.h | 10 | ||||
| -rw-r--r-- | clang/include/clang/AST/Expr.h | 80 | ||||
| -rw-r--r-- | clang/include/clang/AST/Type.h | 158 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 48 | ||||
| -rw-r--r-- | clang/lib/AST/CFG.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 30 | ||||
| -rw-r--r-- | clang/lib/AST/StmtIterator.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 37 | ||||
| -rw-r--r-- | clang/lib/AST/TypeSerialization.cpp | 20 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 78 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 30 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 5 | ||||
| -rw-r--r-- | clang/test/SemaCXX/dependent-types.cpp | 10 | ||||
| -rw-r--r-- | clang/test/SemaCXX/type-dependent-exprs.cpp | 14 | 
18 files changed, 469 insertions, 66 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0d3568b1276..2a8b1c8a5b8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -60,6 +60,7 @@ class ASTContext {    llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;    llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;    std::vector<VariableArrayType*> VariableArrayTypes; +  std::vector<DependentSizedArrayType*> DependentSizedArrayTypes;    llvm::FoldingSet<VectorType> VectorTypes;    llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;    llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos; @@ -142,6 +143,7 @@ public:    QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;    QualType VoidPtrTy;    QualType OverloadTy; +  QualType DependentTy;    ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,               IdentifierTable &idents, SelectorTable &sels, @@ -183,6 +185,14 @@ public:    QualType getVariableArrayType(QualType EltTy, Expr *NumElts,                                  ArrayType::ArraySizeModifier ASM,                                  unsigned EltTypeQuals); +   +  /// getDependentSizedArrayType - Returns a non-unique reference to +  /// the type for a dependently-sized array of the specified element +  /// type. FIXME: We will need these to be uniqued, or at least +  /// comparable, at some point. +  QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, +				      ArrayType::ArraySizeModifier ASM, +				      unsigned EltTypeQuals);    /// getIncompleteArrayType - Returns a unique reference to the type for a    /// incomplete array of the specified element type. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 02e581dce4b..57c9763f7d2 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -38,8 +38,27 @@ namespace clang {  ///  class Expr : public Stmt {    QualType TR; + +  /// TypeDependent - Whether this expression is type-dependent  +  /// (C++ [temp.dep.expr]). +  bool TypeDependent : 1; + +  /// ValueDependent - Whether this expression is value-dependent  +  /// (C++ [temp.dep.constexpr]). +  bool ValueDependent : 1; +  protected: -  Expr(StmtClass SC, QualType T) : Stmt(SC) { setType(T); } +  // FIXME: Eventually, this constructor should go away and we should +  // require every subclass to provide type/value-dependence +  // information. +  Expr(StmtClass SC, QualType T)  +    : Stmt(SC), TypeDependent(false), ValueDependent(false) { setType(T); } + +  Expr(StmtClass SC, QualType T, bool TD, bool VD) +    : Stmt(SC), TypeDependent(TD), ValueDependent(VD) { +    setType(T); +  } +  public:      QualType getType() const { return TR; }    void setType(QualType t) {  @@ -56,6 +75,28 @@ public:      TR = t;     } +  /// isValueDependent - Determines whether this expression is +  /// value-dependent (C++ [temp.dep.constexpr]). For example, the +  /// array bound of "Chars" in the following example is +  /// value-dependent.  +  /// @code +  /// template<int Size, char (&Chars)[Size]> struct meta_string; +  /// @endcode +  bool isValueDependent() const { return ValueDependent; } + +  /// isTypeDependent - Determines whether this expression is +  /// type-dependent (C++ [temp.dep.expr]), which means that its type +  /// could change from one template instantiation to the next. For +  /// example, the expressions "x" and "x + y" are type-dependent in +  /// the following code, but "y" is not type-dependent: +  /// @code +  /// template<typename T>  +  /// void add(T x, int y) { +  ///   x + y; +  /// } +  /// @endcode +  bool isTypeDependent() const { return TypeDependent; } +    /// SourceLocation tokens are not useful in isolation - they are low level    /// value objects created/interpreted by SourceManager. We assume AST    /// clients will have a pointer to the respective SourceManager. @@ -204,7 +245,10 @@ public:    const Expr *IgnoreParenCasts() const {      return const_cast<Expr*>(this)->IgnoreParenCasts();    } -   + +  static bool hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs); +  static bool hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs); +    static bool classof(const Stmt *T) {       return T->getStmtClass() >= firstExprConstant &&             T->getStmtClass() <= lastExprConstant;  @@ -232,8 +276,13 @@ protected:      Expr(SC, t), D(d), Loc(l) {}  public: +  // FIXME: Eventually, this constructor will go away and all clients +  // will have to provide the type- and value-dependent flags.    DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) :       Expr(DeclRefExprClass, t), D(d), Loc(l) {} + +  DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) :  +    Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {}    NamedDecl *getDecl() { return D; }    const NamedDecl *getDecl() const { return D; } @@ -450,7 +499,9 @@ class ParenExpr : public Expr {    Stmt *Val;  public:    ParenExpr(SourceLocation l, SourceLocation r, Expr *val) -    : Expr(ParenExprClass, val->getType()), L(l), R(r), Val(val) {} +    : Expr(ParenExprClass, val->getType(), +           val->isTypeDependent(), val->isValueDependent()),  +      L(l), R(r), Val(val) {}    const Expr *getSubExpr() const { return cast<Expr>(Val); }    Expr *getSubExpr() { return cast<Expr>(Val); } @@ -863,7 +914,14 @@ class CastExpr : public Expr {    Stmt *Op;  protected:    CastExpr(StmtClass SC, QualType ty, Expr *op) :  -    Expr(SC, ty), Op(op) {} +    Expr(SC, ty, +         // Cast expressions are type-dependent if the type is +         // dependent (C++ [temp.dep.expr]p3). +         ty->isDependentType(), +         // Cast expressions are value-dependent if the type is +         // dependent or if the subexpression is value-dependent. +         ty->isDependentType() || (op && op->isValueDependent())),  +    Op(op) {}  public:    Expr *getSubExpr() { return cast<Expr>(Op); } @@ -1030,7 +1088,10 @@ public:    BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,                   SourceLocation opLoc) -    : Expr(BinaryOperatorClass, ResTy), Opc(opc), OpLoc(opLoc) { +    : Expr(BinaryOperatorClass, ResTy, +           lhs->isTypeDependent() || rhs->isTypeDependent(), +           lhs->isValueDependent() || rhs->isValueDependent()),  +      Opc(opc), OpLoc(opLoc) {      SubExprs[LHS] = lhs;      SubExprs[RHS] = rhs;      assert(!isCompoundAssignmentOp() &&  @@ -1128,7 +1189,14 @@ class ConditionalOperator : public Expr {    Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.  public:    ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t) -    : Expr(ConditionalOperatorClass, t) { +    : Expr(ConditionalOperatorClass, t, +           // FIXME: the type of the conditional operator doesn't +           // depend on the type of the conditional, but the standard +           // seems to imply that it could. File a bug! +           ((lhs && lhs->isTypeDependent()) || (rhs && rhs->isTypeDependent())), +           (cond->isValueDependent() ||  +            (lhs && lhs->isValueDependent()) || +            (rhs && rhs->isValueDependent()))) {      SubExprs[COND] = cond;      SubExprs[LHS] = lhs;      SubExprs[RHS] = rhs; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 411d35a5b13..ffcc9f6457b 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -51,6 +51,7 @@ namespace clang {    class ConstantArrayType;    class VariableArrayType;    class IncompleteArrayType; +  class DependentSizedArrayType;    class RecordType;    class EnumType;    class ComplexType; @@ -236,7 +237,7 @@ class Type {  public:    enum TypeClass {      Builtin, Complex, Pointer, Reference,  -    ConstantArray, VariableArray, IncompleteArray, +    ConstantArray, VariableArray, IncompleteArray, DependentSizedArray,      Vector, ExtVector,      FunctionNoProto, FunctionProto,      TypeName, Tagged, ASQual, @@ -249,17 +250,21 @@ public:  private:    QualType CanonicalType; +  /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). +  bool Dependent : 1; +    /// TypeClass bitfield - Enum that specifies what subclass this belongs to.    /// Note that this should stay at the end of the ivars for Type so that    /// subclasses can pack their bitfields into the same word.    unsigned TC : 5; +  protected:    // silence VC++ warning C4355: 'this' : used in base member initializer list    Type *this_() { return this; } -  Type(TypeClass tc, QualType Canonical) +  Type(TypeClass tc, QualType Canonical, bool dependent)      : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical), -      TC(tc) {} -  virtual ~Type() {}; +      Dependent(dependent), TC(tc) {} +  virtual ~Type() {}    virtual void Destroy(ASTContext& C);    friend class ASTContext; @@ -332,6 +337,7 @@ public:    bool isConstantArrayType() const;    bool isIncompleteArrayType() const;    bool isVariableArrayType() const; +  bool isDependentSizedArrayType() const;    bool isRecordType() const;    bool isClassType() const;       bool isStructureType() const;    @@ -343,6 +349,11 @@ public:    bool isObjCQualifiedInterfaceType() const;    // NSString<foo>    bool isObjCQualifiedIdType() const;           // id<foo>    bool isTemplateTypeParmType() const;          // C++ template type parameter + +  /// isDependentType - Whether this type is a dependent type, meaning +  /// that its definition somehow depends on a template parameter  +  /// (C++ [temp.dep.type]). +  bool isDependentType() const { return Dependent; }    bool isOverloadType() const;                  // C++ overloaded function    // Type Checking Functions: Check to see if this type is structurally the @@ -357,7 +368,7 @@ public:    const ReferenceType *getAsReferenceType() const;    const RecordType *getAsRecordType() const;    const RecordType *getAsStructureType() const; -  /// NOTE: getAsArrayType* are methods on ASTContext. +  /// NOTE: getAs*ArrayType are methods on ASTContext.    const TypedefType *getAsTypedefType() const;    const RecordType *getAsUnionType() const;    const EnumType *getAsEnumType() const; @@ -440,7 +451,8 @@ class ASQualType : public Type, public llvm::FoldingSetNode {    /// Address Space ID - The address space ID this type is qualified with.    unsigned AddressSpace;    ASQualType(Type *Base, QualType CanonicalPtr, unsigned AddrSpace) : -    Type(ASQual, CanonicalPtr), BaseType(Base), AddressSpace(AddrSpace) { +    Type(ASQual, CanonicalPtr, Base->isDependentType()), BaseType(Base),  +    AddressSpace(AddrSpace) {    }    friend class ASTContext;  // ASTContext creates these.  public: @@ -493,12 +505,15 @@ public:      Float, Double, LongDouble, -    Overload  // This represents the type of an overloaded function declaration. +    Overload,  // This represents the type of an overloaded function declaration. +    Dependent  // This represents the type of a type-dependent expression.    };  private:    Kind TypeKind;  public: -  BuiltinType(Kind K) : Type(Builtin, QualType()), TypeKind(K) {} +  BuiltinType(Kind K)  +    : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),  +      TypeKind(K) {}    Kind getKind() const { return TypeKind; }    const char *getName() const; @@ -515,7 +530,8 @@ public:  class ComplexType : public Type, public llvm::FoldingSetNode {    QualType ElementType;    ComplexType(QualType Element, QualType CanonicalPtr) : -    Type(Complex, CanonicalPtr), ElementType(Element) { +    Type(Complex, CanonicalPtr, Element->isDependentType()),  +    ElementType(Element) {    }    friend class ASTContext;  // ASTContext creates these.  public: @@ -548,7 +564,7 @@ class PointerLikeType : public Type {    QualType PointeeType;  protected:    PointerLikeType(TypeClass K, QualType Pointee, QualType CanonicalPtr) : -    Type(K, CanonicalPtr), PointeeType(Pointee) { +    Type(K, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) {    }  public: @@ -597,7 +613,8 @@ protected:  class BlockPointerType : public Type, public llvm::FoldingSetNode {    QualType PointeeType;  // Block is some kind of pointer type    BlockPointerType(QualType Pointee, QualType CanonicalCls) : -    Type(BlockPointer, CanonicalCls), PointeeType(Pointee) { +    Type(BlockPointer, CanonicalCls, Pointee->isDependentType()),  +    PointeeType(Pointee) {    }    friend class ASTContext;  // ASTContext creates these.  public: @@ -651,8 +668,9 @@ public:  class ArrayType : public Type, public llvm::FoldingSetNode {  public:    /// ArraySizeModifier - Capture whether this is a normal array (e.g. int X[4]) -  /// an array with a static size (e.g. int X[static 4]), or with a star size -  /// (e.g. int X[*]). 'static' is only allowed on function parameters. +  /// an array with a static size (e.g. int X[static 4]), or an array +  /// with a star size (e.g. int X[*]). +  /// 'static' is only allowed on function parameters.    enum ArraySizeModifier {      Normal, Static, Star    }; @@ -669,9 +687,16 @@ private:    unsigned IndexTypeQuals : 3;  protected: +  // C++ [temp.dep.type]p1: +  //   A type is dependent if it is... +  //     - an array type constructed from any dependent type or whose +  //       size is specified by a constant expression that is +  //       value-dependent,    ArrayType(TypeClass tc, QualType et, QualType can,              ArraySizeModifier sm, unsigned tq) -    : Type(tc, can), ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {} +    : Type(tc, can, et->isDependentType() || tc == DependentSizedArray), +      ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {} +    friend class ASTContext;  // ASTContext creates these.  public:    QualType getElementType() const { return ElementType; } @@ -683,7 +708,8 @@ public:    static bool classof(const Type *T) {      return T->getTypeClass() == ConstantArray ||             T->getTypeClass() == VariableArray || -           T->getTypeClass() == IncompleteArray; +           T->getTypeClass() == IncompleteArray || +           T->getTypeClass() == DependentSizedArray;    }    static bool classof(const ArrayType *) { return true; }  }; @@ -806,6 +832,54 @@ protected:    friend class Type;  }; +/// DependentSizedArrayType - This type represents an array type in +/// C++ whose size is a value-dependent expression. For example: +/// @code +/// template<typename T, int Size>  +/// class array { +///   T data[Size]; +/// }; +/// @endcode +/// For these types, we won't actually know what the array bound is +/// until template instantiation occurs, at which point this will +/// become either a ConstantArrayType or a VariableArrayType. +class DependentSizedArrayType : public ArrayType { +  /// SizeExpr - An assignment expression that will instantiate to the +  /// size of the array. +  Stmt *SizeExpr; +   +  DependentSizedArrayType(QualType et, QualType can, Expr *e, +			  ArraySizeModifier sm, unsigned tq) +    : ArrayType(DependentSizedArray, et, can, sm, tq), SizeExpr((Stmt*) e) {} +  friend class ASTContext;  // ASTContext creates these. +  virtual void Destroy(ASTContext& C); + +public: +  Expr *getSizeExpr() const {  +    // We use C-style casts instead of cast<> here because we do not wish +    // to have a dependency of Type.h on Stmt.h/Expr.h. +    return (Expr*) SizeExpr; +  } +   +  virtual void getAsStringInternal(std::string &InnerString) const; +   +  static bool classof(const Type *T) {  +    return T->getTypeClass() == DependentSizedArray;  +  } +  static bool classof(const DependentSizedArrayType *) { return true; } +   +  friend class StmtIteratorBase; +   +  void Profile(llvm::FoldingSetNodeID &ID) { +    assert (0 && "Cannnot unique DependentSizedArrayTypes."); +  } +   +protected:   +  virtual void EmitImpl(llvm::Serializer& S) const; +  static Type* CreateImpl(ASTContext& Context,llvm::Deserializer& D); +  friend class Type; +}; +  /// VectorType - GCC generic vector type. This type is created using  /// __attribute__((vector_size(n)), where "n" specifies the vector size in   /// bytes. Since the constructor takes the number of vector elements, the  @@ -819,10 +893,12 @@ protected:    unsigned NumElements;    VectorType(QualType vecType, unsigned nElements, QualType canonType) : -    Type(Vector, canonType), ElementType(vecType), NumElements(nElements) {}  +    Type(Vector, canonType, vecType->isDependentType()),  +    ElementType(vecType), NumElements(nElements) {}     VectorType(TypeClass tc, QualType vecType, unsigned nElements,  -    QualType canonType) : Type(tc, canonType), ElementType(vecType),  -    NumElements(nElements) {}  +	     QualType canonType)  +    : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),  +      NumElements(nElements) {}     friend class ASTContext;  // ASTContext creates these.  public: @@ -924,8 +1000,8 @@ class FunctionType : public Type {    QualType ResultType;  protected:    FunctionType(TypeClass tc, QualType res, bool SubclassInfo, -               unsigned typeQuals, QualType Canonical) -    : Type(tc, Canonical), +               unsigned typeQuals, QualType Canonical, bool Dependent) +    : Type(tc, Canonical, Dependent),        SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}    bool getSubClassData() const { return SubClassData; }    unsigned getTypeQuals() const { return TypeQuals; } @@ -945,7 +1021,8 @@ public:  /// no information available about its arguments.  class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {    FunctionTypeNoProto(QualType Result, QualType Canonical) -    : FunctionType(FunctionNoProto, Result, false, 0, Canonical) {} +    : FunctionType(FunctionNoProto, Result, false, 0, Canonical,  +		   /*Dependent=*/false) {}    friend class ASTContext;  // ASTContext creates these.  public:    // No additional state past what FunctionType provides. @@ -974,9 +1051,21 @@ protected:  /// 'int foo(int)' or 'int foo(void)'.  'void' is represented as having no  /// arguments, not as having a single void argument.  class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode { +  /// hasAnyDependentType - Determine whether there are any dependent +  /// types within the arguments passed in. +  static bool hasAnyDependentType(const QualType *ArgArray, unsigned numArgs) { +    for (unsigned Idx = 0; Idx < numArgs; ++Idx) +      if (ArgArray[Idx]->isDependentType()) +	return true; + +    return false; +  } +    FunctionTypeProto(QualType Result, const QualType *ArgArray, unsigned numArgs,                      bool isVariadic, unsigned typeQuals, QualType Canonical) -    : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical), +    : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, +		   (Result->isDependentType() ||  +		    hasAnyDependentType(ArgArray, numArgs))),        NumArgs(numArgs) {      // Fill in the trailing argument array.      QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);; @@ -1032,7 +1121,7 @@ class TypedefType : public Type {    TypedefDecl *Decl;  protected:    TypedefType(TypeClass tc, TypedefDecl *D, QualType can)  -    : Type(tc, can), Decl(D) { +    : Type(tc, can, can->isDependentType()), Decl(D) {      assert(!isa<TypedefType>(can) && "Invalid canonical type");    }    friend class ASTContext;  // ASTContext creates these. @@ -1062,9 +1151,7 @@ protected:  /// TypeOfExpr (GCC extension).  class TypeOfExpr : public Type {    Expr *TOExpr; -  TypeOfExpr(Expr *E, QualType can) : Type(TypeOfExp, can), TOExpr(E) { -    assert(!isa<TypedefType>(can) && "Invalid canonical type"); -  } +  TypeOfExpr(Expr *E, QualType can);    friend class ASTContext;  // ASTContext creates these.  public:    Expr *getUnderlyingExpr() const { return TOExpr; } @@ -1078,7 +1165,8 @@ public:  /// TypeOfType (GCC extension).  class TypeOfType : public Type {    QualType TOType; -  TypeOfType(QualType T, QualType can) : Type(TypeOfTyp, can), TOType(T) { +  TypeOfType(QualType T, QualType can)  +    : Type(TypeOfTyp, can, T->isDependentType()), TOType(T) {      assert(!isa<TypedefType>(can) && "Invalid canonical type");    }    friend class ASTContext;  // ASTContext creates these. @@ -1096,7 +1184,11 @@ class TagType : public Type {    friend class ASTContext;  protected: -  TagType(TagDecl *D, QualType can) : Type(Tagged, can), decl(D) {} +  // FIXME: We'll need the user to pass in information about whether +  // this type is dependent or not, because we don't have enough +  // information to compute it here. +  TagType(TagDecl *D, QualType can)  +    : Type(Tagged, can, /*Dependent=*/false), decl(D) {}  public:       TagDecl *getDecl() const { return decl; } @@ -1184,7 +1276,7 @@ class TemplateTypeParmType : public Type {  protected:    TemplateTypeParmType(TemplateTypeParmDecl *D) -    : Type(TemplateTypeParm, QualType(this, 0)), Decl(D) { } +    : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true), Decl(D) { }    friend class ASTContext; // ASTContext creates these @@ -1214,7 +1306,7 @@ class ObjCInterfaceType : public Type {    ObjCInterfaceDecl *Decl;  protected:    ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) :  -    Type(tc, QualType()), Decl(D) { } +    Type(tc, QualType(), /*Dependent=*/false), Decl(D) { }    friend class ASTContext;  // ASTContext creates these.  public: @@ -1327,7 +1419,8 @@ class ObjCQualifiedIdType : public Type,    llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;    ObjCQualifiedIdType(ObjCProtocolDecl **Protos, unsigned NumP) -    : Type(ObjCQualifiedId, QualType()/*these are always canonical*/),  +    : Type(ObjCQualifiedId, QualType()/*these are always canonical*/, +	   /*Dependent=*/false),     Protocols(Protos, Protos+NumP) { }    friend class ASTContext;  // ASTContext creates these.  public: @@ -1469,6 +1562,9 @@ inline bool Type::isIncompleteArrayType() const {  inline bool Type::isVariableArrayType() const {    return isa<VariableArrayType>(CanonicalType.getUnqualifiedType());  } +inline bool Type::isDependentSizedArrayType() const { +  return isa<DependentSizedArrayType>(CanonicalType.getUnqualifiedType()); +}  inline bool Type::isRecordType() const {    return isa<RecordType>(CanonicalType.getUnqualifiedType());  } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 7c8b4b1b413..35647cf02aa 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -183,7 +183,14 @@ void ASTContext::InitBuiltinTypes() {    InitBuiltinType(WCharTy,             BuiltinType::WChar);    // Placeholder type for functions. -  InitBuiltinType(OverloadTy,         BuiltinType::Overload); +  InitBuiltinType(OverloadTy,          BuiltinType::Overload); + +  // Placeholder type for type-dependent expressions whose type is +  // completely unknown. No code should ever check a type against +  // DependentTy and users should never see it; however, it is here to +  // help diagnose failures to properly check for type-dependent +  // expressions. +  InitBuiltinType(DependentTy,         BuiltinType::Dependent);    // C99 6.2.5p11.    FloatComplexTy      = getComplexType(FloatTy); @@ -235,6 +242,8 @@ ASTContext::getTypeInfo(const Type *T) {      assert(0 && "Incomplete types have no size!");    case Type::VariableArray:      assert(0 && "VLAs not implemented yet!"); +  case Type::DependentSizedArray: +    assert(0 && "Dependently-sized arrays don't have a known size");    case Type::ConstantArray: {      const ConstantArrayType *CAT = cast<ConstantArrayType>(T); @@ -759,6 +768,28 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,    return QualType(New, 0);  } +/// getDependentSizedArrayType - Returns a non-unique reference to +/// the type for a dependently-sized array of the specified element +/// type. FIXME: We will need these to be uniqued, or at least +/// comparable, at some point. +QualType ASTContext::getDependentSizedArrayType(QualType EltTy, Expr *NumElts, +                                                ArrayType::ArraySizeModifier ASM, +                                                unsigned EltTypeQuals) { +  assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&  +         "Size must be type- or value-dependent!"); + +  // Since we don't unique expressions, it isn't possible to unique +  // dependently-sized array types. + +  DependentSizedArrayType *New  +    = new DependentSizedArrayType(EltTy, QualType(), NumElts,  +                                  ASM, EltTypeQuals); + +  DependentSizedArrayTypes.push_back(New); +  Types.push_back(New); +  return QualType(New, 0); +} +  QualType ASTContext::getIncompleteArrayType(QualType EltTy,                                              ArrayType::ArraySizeModifier ASM,                                              unsigned EltTypeQuals) { @@ -1174,6 +1205,11 @@ QualType ASTContext::getCanonicalType(QualType T) {      return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),                                    IAT->getIndexTypeQualifier()); +  if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT)) +    return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), +                                      DSAT->getSizeModifier(), +                                      DSAT->getIndexTypeQualifier());     +    // FIXME: What is the ownership of size expressions in VLAs?    VariableArrayType *VAT = cast<VariableArrayType>(AT);    return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), @@ -1246,6 +1282,16 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) {      return cast<ArrayType>(getIncompleteArrayType(NewEltTy,                                                    IAT->getSizeModifier(),                                                   IAT->getIndexTypeQualifier())); + +  // FIXME: What is the ownership of size expressions in +  // dependent-sized array types? +  if (const DependentSizedArrayType *DSAT  +        = dyn_cast<DependentSizedArrayType>(ATy)) +    return cast<ArrayType>( +                     getDependentSizedArrayType(NewEltTy,  +                                                DSAT->getSizeExpr(), +                                                DSAT->getSizeModifier(), +                                                DSAT->getIndexTypeQualifier()));    // FIXME: What is the ownership of size expressions in VLAs?    const VariableArrayType *VAT = cast<VariableArrayType>(ATy); diff --git a/clang/lib/AST/CFG.cpp b/clang/lib/AST/CFG.cpp index 82336a44e08..69e82f2b832 100644 --- a/clang/lib/AST/CFG.cpp +++ b/clang/lib/AST/CFG.cpp @@ -154,6 +154,8 @@ private:    bool badCFG;  }; +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template?  static VariableArrayType* FindVA(Type* t) {    while (ArrayType* vt = dyn_cast<ArrayType>(t)) {      if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt)) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a3264b010b7..14db18c1345 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -103,7 +103,10 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {  CallExpr::CallExpr(StmtClass SC, Expr *fn, Expr **args, unsigned numargs,                      QualType t, SourceLocation rparenloc) -  : Expr(SC, t), NumArgs(numargs) { +  : Expr(SC, t,  +         fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), +         fn->isValueDependent() || hasAnyValueDependentArguments(args, numargs)), +    NumArgs(numargs) {    SubExprs = new Stmt*[numargs+1];    SubExprs[FN] = fn;    for (unsigned i = 0; i != numargs; ++i) @@ -113,7 +116,10 @@ CallExpr::CallExpr(StmtClass SC, Expr *fn, Expr **args, unsigned numargs,  CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,                     SourceLocation rparenloc) -  : Expr(CallExprClass, t), NumArgs(numargs) { +  : Expr(CallExprClass, t, +         fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), +         fn->isValueDependent() || hasAnyValueDependentArguments(args, numargs)), +    NumArgs(numargs) {    SubExprs = new Stmt*[numargs+1];    SubExprs[FN] = fn;    for (unsigned i = 0; i != numargs; ++i) @@ -631,6 +637,26 @@ Expr *Expr::IgnoreParenCasts() {    }  } +/// hasAnyTypeDependentArguments - Determines if any of the expressions +/// in Exprs is type-dependent. +bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) { +  for (unsigned I = 0; I < NumExprs; ++I) +    if (Exprs[I]->isTypeDependent()) +      return true; + +  return false; +} + +/// hasAnyValueDependentArguments - Determines if any of the expressions +/// in Exprs is value-dependent. +bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) { +  for (unsigned I = 0; I < NumExprs; ++I) +    if (Exprs[I]->isValueDependent()) +      return true; + +  return false; +} +  bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {    switch (getStmtClass()) {    default: diff --git a/clang/lib/AST/StmtIterator.cpp b/clang/lib/AST/StmtIterator.cpp index 46882422e1c..48003450191 100644 --- a/clang/lib/AST/StmtIterator.cpp +++ b/clang/lib/AST/StmtIterator.cpp @@ -16,6 +16,8 @@  using namespace clang; +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template?  static inline VariableArrayType* FindVA(Type* t) {    while (ArrayType* vt = dyn_cast<ArrayType>(t)) {      if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt)) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 303fc7e7ca5..5909c976aa6 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -43,6 +43,10 @@ void VariableArrayType::Destroy(ASTContext& C) {    delete this;    } +void DependentSizedArrayType::Destroy(ASTContext& C) { +  SizeExpr->Destroy(C); +  delete this; +}  /// getArrayElementTypeNoTypeQual - If this is an array type, return the  /// element type of the array, potentially with type qualifiers missing. @@ -634,11 +638,12 @@ bool Type::isAggregateType() const {  /// isConstantSizeType - Return true if this is not a variable sized type,  /// according to the rules of C99 6.7.5p3.  It is not legal to call this on -/// incomplete types. +/// incomplete types or dependent types.  bool Type::isConstantSizeType() const {    if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType))      return ASQT->getBaseType()->isConstantSizeType();    assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); +  assert(!isDependentType() && "This doesn't make sense for dependent types");    // The VAT must have a size, as it is known to be complete.    return !isa<VariableArrayType>(CanonicalType);  } @@ -706,6 +711,7 @@ const char *BuiltinType::getName() const {    case LongDouble:        return "long double";    case WChar:             return "wchar_t";    case Overload:          return "<overloaded function type>"; +  case Dependent:         return "<dependent type>";    }  } @@ -780,6 +786,11 @@ QualType TypedefType::LookThroughTypedefs() const {    }  } +TypeOfExpr::TypeOfExpr(Expr *E, QualType can) +  : Type(TypeOfExp, can, E->isTypeDependent()), TOExpr(E) { +  assert(!isa<TypedefType>(can) && "Invalid canonical type"); +} +  bool RecordType::classof(const TagType *TT) {    return isa<RecordDecl>(TT->getDecl());  } @@ -932,6 +943,30 @@ void VariableArrayType::getAsStringInternal(std::string &S) const {    getElementType().getAsStringInternal(S);  } +void DependentSizedArrayType::getAsStringInternal(std::string &S) const { +  S += '['; +   +  if (getIndexTypeQualifier()) { +    AppendTypeQualList(S, getIndexTypeQualifier()); +    S += ' '; +  } +   +  if (getSizeModifier() == Static) +    S += "static"; +  else if (getSizeModifier() == Star) +    S += '*'; +   +  if (getSizeExpr()) { +    std::string SStr; +    llvm::raw_string_ostream s(SStr); +    getSizeExpr()->printPretty(s); +    S += s.str(); +  } +  S += ']'; +   +  getElementType().getAsStringInternal(S); +} +  void VectorType::getAsStringInternal(std::string &S) const {    // FIXME: We prefer to print the size directly here, but have no way    // to get the size of the type. diff --git a/clang/lib/AST/TypeSerialization.cpp b/clang/lib/AST/TypeSerialization.cpp index 3bdc946de7e..8e35f187a3e 100644 --- a/clang/lib/AST/TypeSerialization.cpp +++ b/clang/lib/AST/TypeSerialization.cpp @@ -315,6 +315,26 @@ Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) {  }  //===----------------------------------------------------------------------===// +// DependentSizedArrayType +//===----------------------------------------------------------------------===// + +void DependentSizedArrayType::EmitImpl(Serializer& S) const { +  S.Emit(getElementType()); +  S.EmitInt(getSizeModifier()); +  S.EmitInt(getIndexTypeQualifier()); +  S.EmitOwnedPtr(SizeExpr); +} + +Type* DependentSizedArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { +  QualType ElTy = QualType::ReadVal(D); +  ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt()); +  unsigned ITQ = D.ReadInt();   +  Expr* SizeExpr = D.ReadOwnedPtr<Expr>(Context); +   +  return Context.getDependentSizedArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr(); +} + +//===----------------------------------------------------------------------===//  // IncompleteArrayType  //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index fbf11204070..85b10399a41 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -191,6 +191,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {    switch (Ty.getTypeClass()) {    case Type::TypeName:        // typedef isn't canonical.    case Type::TemplateTypeParm:// template type parameters never generated +  case Type::DependentSizedArray: // dependent types are never generated    case Type::TypeOfExp:       // typeof isn't canonical.    case Type::TypeOfTyp:       // typeof isn't canonical.      assert(0 && "Non-canonical type, shouldn't happen"); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c893d275978..e581b100dcc 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -870,9 +870,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {    if (PrevDecl && isTemplateParameterDecl(PrevDecl)) {      // Maybe we will complain about the shadowed template parameter. -    InvalidDecl  -      = InvalidDecl || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),  -						       PrevDecl); +    InvalidDecl = InvalidDecl  +      || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);      // Just pretend that we didn't see the previous declaration.      PrevDecl = 0;    } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ec86b9f2a6b..e4beb74fc5d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -490,7 +490,52 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,    }    // If this reference is not in a block or if the referenced variable is    // within the block, create a normal DeclRefExpr. -  return new DeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc); + +  // C++ [temp.dep.expr]p3: +  //   An id-expression is type-dependent if it contains:    +  bool TypeDependent = false; + +  //     - an identifier that was declared with a dependent type, +  if (VD->getType()->isDependentType()) +    TypeDependent = true; +  //     - FIXME: a template-id that is dependent, +  //     - a conversion-function-id that specifies a dependent type, +  else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && +           Name.getCXXNameType()->isDependentType()) +    TypeDependent = true; +  //     - a nested-name-specifier that contains a class-name that +  //       names a dependent type. +  else if (SS && !SS->isEmpty()) { +    for (DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());  +         DC; DC = DC->getParent()) { +      // FIXME: could stop early at namespace scope. +      if (DC->isCXXRecord()) { +        CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); +        if (Context.getTypeDeclType(Record)->isDependentType()) { +          TypeDependent = true; +          break; +        } +      } +    } +  } + +  // C++ [temp.dep.constexpr]p2: +  // +  //   An identifier is value-dependent if it is: +  bool ValueDependent = false; +   +  //     - a name declared with a dependent type, +  if (TypeDependent) +    ValueDependent = true; +  //     - the name of a non-type template parameter, +  else if (isa<NonTypeTemplateParmDecl>(VD)) +    ValueDependent = true; +  //    - a constant with integral or enumeration type and is +  //      initialized with an expression that is value-dependent +  //      (FIXME!). + +  return new DeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, +                         TypeDependent, ValueDependent);  }  Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, @@ -1279,6 +1324,11 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,    FunctionDecl *FDecl = NULL;    OverloadedFunctionDecl *Ovl = NULL; +  // FIXME: Will need to cache the results of name lookup (including +  // ADL) in Fn. +  if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) +    return new CallExpr(Fn, Args, NumArgs, Context.DependentTy, RParenLoc); +    // If we're directly calling a function or a set of overloaded    // functions, get the appropriate declaration.    { @@ -1318,6 +1368,7 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,    // of arguments and function on error.    llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,                                                   Context.BoolTy, RParenLoc)); +      const FunctionType *FuncT;    if (!Fn->getType()->isBlockPointerType()) {      // C99 6.5.2.2p1 - "The expression that denotes the called function shall @@ -1470,6 +1521,8 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {    // type needs to be scalar.    if (castType->isVoidType()) {      // Cast to void allows any expr type. +  } else if (castType->isDependentType() || castExpr->isTypeDependent()) { +    // We can't check any more until template instantiation time.    } else if (!castType->isScalarType() && !castType->isVectorType()) {      // GCC struct/union extension: allow cast to self.      if (Context.getCanonicalType(castType) != @@ -1541,13 +1594,17 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15    QualType rexT = rex->getType();    // first, check the condition. -  if (!condT->isScalarType()) { // C99 6.5.15p2 -    Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) << condT; -    return QualType(); +  if (!cond->isTypeDependent()) { +    if (!condT->isScalarType()) { // C99 6.5.15p2 +      Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) << condT; +      return QualType(); +    }    }    // Now check the two expressions. -   +  if ((lex && lex->isTypeDependent()) || (rex && rex->isTypeDependent())) +    return Context.DependentTy; +    // If both operands have arithmetic type, do the usual arithmetic conversions    // to find a common type: C99 6.5.15p3,5.    if (lexT->isArithmeticType() && rexT->isArithmeticType()) { @@ -2959,6 +3016,17 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,    assert((lhs != 0) && "ActOnBinOp(): missing left expression");    assert((rhs != 0) && "ActOnBinOp(): missing right expression"); +  // If either expression is type-dependent, just build the AST. +  // FIXME: We'll need to perform some caching of the result of name +  // lookup for operator+. +  if (lhs->isTypeDependent() || rhs->isTypeDependent()) { +    if (Opc > BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) +      return new CompoundAssignOperator(lhs, rhs, Opc, Context.DependentTy,  +                                        Context.DependentTy, TokLoc); +    else +      return new BinaryOperator(lhs, rhs, Opc, Context.DependentTy, TokLoc); +  } +    if (getLangOptions().CPlusPlus &&        (lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||         rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1e9b945a181..c4cab3316ba 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -163,9 +163,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,    //    if (Ty->isArrayType())      return Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange; -  if (Ty->isIncompleteType() && !Ty->isVoidType()) +  if (!Ty->isDependentType() && Ty->isIncompleteType() && !Ty->isVoidType())      return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use)  -      << Ty << FullRange; +             << Ty << FullRange;    return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc);  } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 0159f5f0a53..21f897f639b 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -782,21 +782,23 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {      return new ReturnStmt(ReturnLoc, (Expr*)0);    } -  // we have a non-void function with an expression, continue checking -  QualType RetValType = RetValExp->getType(); - -  // C99 6.8.6.4p3(136): The return statement is not an assignment. The  -  // overlap restriction of subclause 6.5.16.1 does not apply to the case of  -  // function return.   - -  // In C++ the return statement is handled via a copy initialization. -  // the C version of which boils down to -  // CheckSingleAssignmentConstraints. -  if (PerformCopyInitialization(RetValExp, FnRetType, "returning")) -    return true; -   -  if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); +  if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { +    // we have a non-void function with an expression, continue checking +    QualType RetValType = RetValExp->getType(); +     +    // C99 6.8.6.4p3(136): The return statement is not an assignment. The  +    // overlap restriction of subclause 6.5.16.1 does not apply to the case of  +    // function return.   +     +    // In C++ the return statement is handled via a copy initialization. +    // the C version of which boils down to +    // CheckSingleAssignmentConstraints. +    if (PerformCopyInitialization(RetValExp, FnRetType, "returning")) +      return true; +    if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); +  } +    return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);  } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 749d181baf0..092c9d2236a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -12,6 +12,7 @@  //+//===----------------------------------------------------------------------===/  #include "Sema.h" +#include "clang/AST/Expr.h"  #include "clang/Parse/DeclSpec.h"  #include "clang/Basic/LangOptions.h" diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4487c1e4160..2423e1271b8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -391,6 +391,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {        llvm::APSInt ConstVal(32);        if (!ArraySize) {          T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals); +      } else if (ArraySize->isValueDependent()) { +        T = Context.getDependentSizedArrayType(T, ArraySize, ASM, ATI.TypeQuals);        } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||                   !T->isConstantSizeType()) {          // Per C99, a variable array is an array with either a non-constant @@ -416,7 +418,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {        // If this is not C99, extwarn about VLA's and C99 array size modifiers.        if (!getLangOptions().C99 &&            (ASM != ArrayType::Normal || -           (ArraySize && !ArraySize->isIntegerConstantExpr(Context)))) +           (ArraySize && !ArraySize->isValueDependent() &&  +            !ArraySize->isIntegerConstantExpr(Context))))          Diag(D.getIdentifierLoc(), diag::ext_vla);        break;      } diff --git a/clang/test/SemaCXX/dependent-types.cpp b/clang/test/SemaCXX/dependent-types.cpp new file mode 100644 index 00000000000..a5d23ffaa48 --- /dev/null +++ b/clang/test/SemaCXX/dependent-types.cpp @@ -0,0 +1,10 @@ +// RUN: clang -fsyntax-only -pedantic -verify %s + +template<typename T, int Size> void f() { +  T x1; +  T* x2; +  T& x3; // expected-error{{declaration of reference variable 'x3' requires an initializer}} +  T x4[]; // expected-error{{variable has incomplete type 'T []'}} +  T x5[Size]; +  int x6[Size]; +} diff --git a/clang/test/SemaCXX/type-dependent-exprs.cpp b/clang/test/SemaCXX/type-dependent-exprs.cpp new file mode 100644 index 00000000000..d3fd8922ac2 --- /dev/null +++ b/clang/test/SemaCXX/type-dependent-exprs.cpp @@ -0,0 +1,14 @@ +// RUN: clang -fsyntax-only -verify %s + +void g(int); + +template<typename T> +T f(T x) { +  (void)(x + 0); +  (void)T(0); +  (void)(x += 0); +  (void)(x? x : x); +  return g(x); +  //  h(x); // h is a dependent name +  return 0; +}  | 

