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.

llvm-svn: 60615
This commit is contained in:
Douglas Gregor 2008-12-05 23:32:09 +00:00
parent 0733759b5a
commit 4619e439b6
18 changed files with 469 additions and 66 deletions

View 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.

View 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;

View 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());
}

View 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);

View 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))

View 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:

View 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))

View 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.

View 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
//===----------------------------------------------------------------------===//

View 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");

View 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;
}

View 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())) {

View 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);
}

View 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);
}

View File

@ -12,6 +12,7 @@
//+//===----------------------------------------------------------------------===/
#include "Sema.h"
#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"

View 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;
}

View File

@ -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];
}

View File

@ -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;
}