[cfe-commits] r60615 - in /cfe/trunk: 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 test/SemaCXX/type-dependent-exprs.cpp
Douglas Gregor
dgregor at apple.com
Fri Dec 5 15:32:11 PST 2008
Author: dgregor
Date: Fri Dec 5 17:32:09 2008
New Revision: 60615
URL: http://llvm.org/viewvc/llvm-project?rev=60615&view=rev
Log:
Introduce basic support for dependent types, type-dependent
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.
Added:
cfe/trunk/test/SemaCXX/dependent-types.cpp
cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/CFG.cpp
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/StmtIterator.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/AST/TypeSerialization.cpp
cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Dec 5 17:32:09 2008
@@ -60,6 +60,7 @@
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 @@
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 @@
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.
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Dec 5 17:32:09 2008
@@ -38,8 +38,27 @@
///
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Fri Dec 5 17:32:09 2008
@@ -51,6 +51,7 @@
class ConstantArrayType;
class VariableArrayType;
class IncompleteArrayType;
+ class DependentSizedArrayType;
class RecordType;
class EnumType;
class ComplexType;
@@ -236,7 +237,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/// 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 @@
/// '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 @@
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 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
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 @@
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::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());
}
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Dec 5 17:32:09 2008
@@ -183,7 +183,14 @@
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 @@
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 @@
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 @@
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 @@
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);
Modified: cfe/trunk/lib/AST/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CFG.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CFG.cpp (original)
+++ cfe/trunk/lib/AST/CFG.cpp Fri Dec 5 17:32:09 2008
@@ -154,6 +154,8 @@
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))
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Dec 5 17:32:09 2008
@@ -103,7 +103,10 @@
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(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 @@
}
}
+/// 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:
Modified: cfe/trunk/lib/AST/StmtIterator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtIterator.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtIterator.cpp (original)
+++ cfe/trunk/lib/AST/StmtIterator.cpp Fri Dec 5 17:32:09 2008
@@ -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))
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Fri Dec 5 17:32:09 2008
@@ -43,6 +43,10 @@
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 @@
/// 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 @@
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 @@
}
}
+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 @@
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.
Modified: cfe/trunk/lib/AST/TypeSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeSerialization.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeSerialization.cpp (original)
+++ cfe/trunk/lib/AST/TypeSerialization.cpp Fri Dec 5 17:32:09 2008
@@ -315,6 +315,26 @@
}
//===----------------------------------------------------------------------===//
+// 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
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Fri Dec 5 17:32:09 2008
@@ -191,6 +191,7 @@
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");
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Dec 5 17:32:09 2008
@@ -870,9 +870,8 @@
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;
}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Dec 5 17:32:09 2008
@@ -490,7 +490,52 @@
}
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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())) {
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Dec 5 17:32:09 2008
@@ -163,9 +163,9 @@
//
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);
}
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Dec 5 17:32:09 2008
@@ -782,21 +782,23 @@
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);
}
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Dec 5 17:32:09 2008
@@ -12,6 +12,7 @@
//+//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=60615&r1=60614&r2=60615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Dec 5 17:32:09 2008
@@ -391,6 +391,8 @@
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 @@
// 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;
}
Added: cfe/trunk/test/SemaCXX/dependent-types.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dependent-types.cpp?rev=60615&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/dependent-types.cpp (added)
+++ cfe/trunk/test/SemaCXX/dependent-types.cpp Fri Dec 5 17:32:09 2008
@@ -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];
+}
Added: cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp?rev=60615&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp (added)
+++ cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp Fri Dec 5 17:32:09 2008
@@ -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;
+}
More information about the cfe-commits
mailing list