forked from OSchip/llvm-project
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:
parent
0733759b5a
commit
4619e439b6
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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())) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//+//===----------------------------------------------------------------------===/
|
||||
|
||||
#include "Sema.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue