]> granicus.if.org Git - clang/commitdiff
Introduce basic support for dependent types, type-dependent
authorDouglas Gregor <dgregor@apple.com>
Fri, 5 Dec 2008 23:32:09 +0000 (23:32 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 5 Dec 2008 23:32:09 +0000 (23:32 +0000)
expressions, and value-dependent expressions. This permits us to parse
some template definitions.

This is not a complete solution; we're missing type- and
value-dependent computations for most of the expression types, and
we're missing checks for dependent types and type-dependent
expressions throughout Sema.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60615 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Expr.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/CFG.cpp
lib/AST/Expr.cpp
lib/AST/StmtIterator.cpp
lib/AST/Type.cpp
lib/AST/TypeSerialization.cpp
lib/CodeGen/CodeGenTypes.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/dependent-types.cpp [new file with mode: 0644]
test/SemaCXX/type-dependent-exprs.cpp [new file with mode: 0644]

index 0d3568b1276275fedbfaf673fa9cba26de2ff4cf..2a8b1c8a5b8df2bc41a1e41462e2fecb1f8d7c3c 100644 (file)
@@ -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.
index 02e581dce4bf02fd19dab1597c8acdf1b464a7a0..57c9763f7d2bb00e0b8a219d81fdfbee595f0e7b 100644 (file)
@@ -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;
index 411d35a5b1325a5b1fefea8071be2cddf9dc22bc..ffcc9f6457b507e51d91a47e111bf9f570ccbe61 100644 (file)
@@ -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());
 }
index 7c8b4b1b41301ab0fb679d725d0cbae1e75c7b80..35647cf02aaaaaa68b421ffa21da8c2e6499267e 100644 (file)
@@ -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);
index 82336a44e08ebfad1538f3413860e0eb102d4ac0..69e82f2b832c86825fe23f7a832558cf3e9588a3 100644 (file)
@@ -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))
index a3264b010b7aca3990077add74d3bd91f1fdb0fd..14db18c1345d9cb0344edb305160b47a71ce0c30 100644 (file)
@@ -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:
index 46882422e1ccfdc1e9cb688ace609378bca4d56d..48003450191827d3a620c112a9e0e49d2108c764 100644 (file)
@@ -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))
index 303fc7e7ca540c0b29b61bbe7f1e7da42fd48135..5909c976aa6aaf0ca7bd016ff3ad66c8f95c9179 100644 (file)
@@ -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.
index 3bdc946de7ebcd8ed8de573c1bbb6c8f8f7f2759..8e35f187a3ee7d783428f8879063f554a1f05ec7 100644 (file)
@@ -314,6 +314,26 @@ Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) {
   return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr();
 }
 
+//===----------------------------------------------------------------------===//
+// 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
 //===----------------------------------------------------------------------===//
index fbf11204070b92641b0e19d7f92b9a6ec240758d..85b10399a410d052af2c63a12344591c6fd6e780 100644 (file)
@@ -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");
index c893d275978a804df220e9ba25a0caa30bb4c4e0..e581b100dcc884560555c8321d8f3362825a419f 100644 (file)
@@ -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;
   }
index ec86b9f2a6bfcbc41eeed12036a260b9ad91f513..e4beb74fc5dddf26110f53f5449a1f8d19ae4e38 100644 (file)
@@ -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())) {
index 1e9b945a181bf9854854a81513e319f6943bd9fd..c4cab3316ba6ea0f480962165dc89c219bc5ae28 100644 (file)
@@ -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);
 }
index 0159f5f0a5397f5e139e3f61b4b77f5e1f6649ac..21f897f639b4f9eed12852a7a4bdad1579478ac8 100644 (file)
@@ -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);
 }
 
index 749d181baf018ebe22406de71ae168853908a802..092c9d2236a5b881cf2369c680da4c1b6c934b8c 100644 (file)
@@ -12,6 +12,7 @@
 //+//===----------------------------------------------------------------------===/
 
 #include "Sema.h"
+#include "clang/AST/Expr.h"
 #include "clang/Parse/DeclSpec.h"
 #include "clang/Basic/LangOptions.h"
 
index 4487c1e4160bd52c5f68a041f44a1786fd61ce86..2423e1271b8367de1c72fe5d7758f8622abfc696 100644 (file)
@@ -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/test/SemaCXX/dependent-types.cpp b/test/SemaCXX/dependent-types.cpp
new file mode 100644 (file)
index 0000000..a5d23ff
--- /dev/null
@@ -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/test/SemaCXX/type-dependent-exprs.cpp b/test/SemaCXX/type-dependent-exprs.cpp
new file mode 100644 (file)
index 0000000..d3fd892
--- /dev/null
@@ -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;
+}