Submitted by:
Reviewed by:
Implement type checking. First round of changes are:
- Added predicates to Type.
- Added predicates to BinExpr.
- Added Check hooks that model the categories for Binary ops.
- Added TypeRef to Expr. Will lazily eval subclasses...
- Misc bug fixes/cleanups.

llvm-svn: 39360
This commit is contained in:
Steve Naroff 2007-03-21 21:08:52 +00:00
parent bb73acd560
commit 26c8ea5fab
9 changed files with 255 additions and 49 deletions

View File

@ -24,6 +24,7 @@ namespace clang {
class ASTContext;
class Preprocessor;
class Decl;
class Expr;
class VarDecl;
class TypedefDecl;
class FunctionDecl;
@ -65,7 +66,7 @@ public:
virtual TypeResult ParseTypeName(Scope *S, Declarator &D);
virtual TypeResult ParseParamDeclaratorType(Scope *S, Declarator &D);
private:
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
@ -98,6 +99,9 @@ private:
TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
/// AddTopLevelDecl - called after the decl has been fully processed.
/// Allows for bookkeeping and post-processing of each declaration.
void AddTopLevelDecl(Decl *current, Decl *last);
/// More parsing and symbol table subroutines...
VarDecl *ParseParamDeclarator(DeclaratorChunk &FI, unsigned ArgNo,
@ -215,6 +219,15 @@ public:
/// ParseCXXBoolLiteral - Parse {true,false} literals.
virtual ExprResult ParseCXXBoolLiteral(SourceLocation OpLoc,
tok::TokenKind Kind);
private:
/// type checking binary operators (subroutines of ParseBinOp).
void CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
void CheckAdditiveOperands(Expr *op1, Expr *op2); // C99 6.5.6
void CheckShiftOperands(Expr *op1, Expr *op2); // C99 6.5.7
void CheckRelationalOperands(Expr *op1, Expr *op2); // C99 6.5.8
void CheckEqualityOperands(Expr *op1, Expr *op2); // C99 6.5.9
void CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
void CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
};

View File

@ -288,10 +288,8 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
S->AddDecl(New);
}
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
// remember this in the LastInGroupList list.
if (LastInGroup && S->getParent() == 0)
LastInGroupList.push_back((Decl*)LastInGroup);
if (S->getParent() == 0)
AddTopLevelDecl(New, (Decl *)LastInGroup);
return New;
}
@ -714,3 +712,12 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
Enum->defineElements(&Values[0], Values.size());
}
void Sema::AddTopLevelDecl(Decl *current, Decl *last) {
if (!current) return;
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
// remember this in the LastInGroupList list.
if (last) {
LastInGroupList.push_back((Decl*)last);
}
}

View File

@ -188,7 +188,7 @@ ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
if (isa<FunctionType>(ArgTy) && isSizeof) {
// alignof(function) is allowed.
Diag(OpLoc, diag::ext_sizeof_function_type);
return new IntegerLiteral(/*1*/);
return new IntegerLiteral(1, Context.IntTy);
} else if (ArgTy->isVoidType()) {
Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
} else if (ArgTy->isIncompleteType()) {
@ -196,7 +196,7 @@ ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
ArgTy->getAsString(TypeName);
Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type :
diag::err_alignof_incomplete_type, TypeName);
return new IntegerLiteral(/*0*/);
return new IntegerLiteral(0, Context.IntTy);
}
return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy);
@ -289,6 +289,21 @@ Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
case tok::comma: Opc = BinaryOperator::Comma; break;
}
if (BinaryOperator::isMultiplicativeOp(Opc))
CheckMultiplicativeOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isAdditiveOp(Opc))
CheckAdditiveOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isShiftOp(Opc))
CheckShiftOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isRelationalOp(Opc))
CheckRelationalOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isEqualityOp(Opc))
CheckEqualityOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isBitwiseOp(Opc))
CheckBitwiseOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isLogicalOp(Opc))
CheckLogicalOperands((Expr*)LHS, (Expr*)RHS);
return new BinaryOperator((Expr*)LHS, (Expr*)RHS, Opc);
}
@ -301,3 +316,24 @@ Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS);
}
void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
}

View File

@ -14,7 +14,9 @@
#include "clang/Lex/IdentifierTable.h"
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include <iostream>
using namespace llvm;
using namespace clang;
@ -22,16 +24,105 @@ Type::~Type() {}
/// isVoidType - Helper method to determine if this is the 'void' type.
bool Type::isVoidType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(getCanonicalType()))
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::Void;
return false;
}
bool Type::isFunctionType() const {
return isa<FunctionType>(CanonicalType) ? true : false;
}
bool Type::isPointerType() const {
return isa<PointerType>(CanonicalType) ? true : false;
}
bool Type::isArrayType() const {
return isa<ArrayType>(CanonicalType) ? true : false;
}
bool Type::isStructureType() const {
if (const TaggedType *TT = dyn_cast<TaggedType>(CanonicalType)) {
if (TT->getDecl()->getKind() == Decl::Struct)
return true;
}
return false;
}
bool Type::isUnionType() const {
if (const TaggedType *TT = dyn_cast<TaggedType>(CanonicalType)) {
if (TT->getDecl()->getKind() == Decl::Union)
return true;
}
return false;
}
bool Type::isIntegralType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::ULongLong;
case Tagged:
const TaggedType *TT = static_cast<TaggedType*>(CanonicalType);
if (TT->getDecl()->getKind() == Decl::Enum)
return true;
return false;
}
}
bool Type::isFloatingType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
return BT->getKind() >= BuiltinType::Float &&
BT->getKind() <= BuiltinType::LongDoubleComplex;
}
}
bool Type::isArithmeticType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::LongDoubleComplex;
}
}
bool Type::isScalarType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::LongDoubleComplex;
case Pointer:
return true;
}
}
bool Type::isAggregateType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Array:
return true;
case Tagged:
const TaggedType *TT = static_cast<TaggedType*>(CanonicalType);
if (TT->getDecl()->getKind() == Decl::Struct)
return true;
return true;
}
}
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
/// - a type that can describe objects, but which lacks information needed to
/// determine its size.
bool Type::isIncompleteType() const {
switch (getTypeClass()) {
bool Type::isIncompleteType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
@ -40,17 +131,10 @@ bool Type::isIncompleteType() const {
case Tagged:
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
return !cast<TaggedType>(this)->getDecl()->isDefinition();
return !cast<TaggedType>(CanonicalType)->getDecl()->isDefinition();
case Array:
// An array of unknown size is an incomplete type (C99 6.2.5p22).
// In C99, an unknown size is permitted in 4 instances:
// - The array being declared is a formal parameter of a function.
// - The declarator is accompanied by an initializer from which the array
// can be deduced (char foo[] = "whatever").
// - Forward declarations (extern int matrix[][7]).
// - The last component of a structure (flexible array idiom).
// Clients of this routine will need to determine if the size is required.
return cast<ArrayType>(this)->getSize() == 0;
return cast<ArrayType>(CanonicalType)->getSize() == 0;
}
}

View File

@ -24,6 +24,7 @@ namespace clang {
class ASTContext;
class Preprocessor;
class Decl;
class Expr;
class VarDecl;
class TypedefDecl;
class FunctionDecl;
@ -65,7 +66,7 @@ public:
virtual TypeResult ParseTypeName(Scope *S, Declarator &D);
virtual TypeResult ParseParamDeclaratorType(Scope *S, Declarator &D);
private:
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
@ -98,6 +99,9 @@ private:
TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
/// AddTopLevelDecl - called after the decl has been fully processed.
/// Allows for bookkeeping and post-processing of each declaration.
void AddTopLevelDecl(Decl *current, Decl *last);
/// More parsing and symbol table subroutines...
VarDecl *ParseParamDeclarator(DeclaratorChunk &FI, unsigned ArgNo,
@ -215,6 +219,15 @@ public:
/// ParseCXXBoolLiteral - Parse {true,false} literals.
virtual ExprResult ParseCXXBoolLiteral(SourceLocation OpLoc,
tok::TokenKind Kind);
private:
/// type checking binary operators (subroutines of ParseBinOp).
void CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
void CheckAdditiveOperands(Expr *op1, Expr *op2); // C99 6.5.6
void CheckShiftOperands(Expr *op1, Expr *op2); // C99 6.5.7
void CheckRelationalOperands(Expr *op1, Expr *op2); // C99 6.5.8
void CheckEqualityOperands(Expr *op1, Expr *op2); // C99 6.5.9
void CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
void CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
};

View File

@ -288,10 +288,8 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
S->AddDecl(New);
}
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
// remember this in the LastInGroupList list.
if (LastInGroup && S->getParent() == 0)
LastInGroupList.push_back((Decl*)LastInGroup);
if (S->getParent() == 0)
AddTopLevelDecl(New, (Decl *)LastInGroup);
return New;
}
@ -714,3 +712,12 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
Enum->defineElements(&Values[0], Values.size());
}
void Sema::AddTopLevelDecl(Decl *current, Decl *last) {
if (!current) return;
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
// remember this in the LastInGroupList list.
if (last) {
LastInGroupList.push_back((Decl*)last);
}
}

View File

@ -188,7 +188,7 @@ ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
if (isa<FunctionType>(ArgTy) && isSizeof) {
// alignof(function) is allowed.
Diag(OpLoc, diag::ext_sizeof_function_type);
return new IntegerLiteral(/*1*/);
return new IntegerLiteral(1, Context.IntTy);
} else if (ArgTy->isVoidType()) {
Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
} else if (ArgTy->isIncompleteType()) {
@ -196,7 +196,7 @@ ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
ArgTy->getAsString(TypeName);
Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type :
diag::err_alignof_incomplete_type, TypeName);
return new IntegerLiteral(/*0*/);
return new IntegerLiteral(0, Context.IntTy);
}
return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy);
@ -289,6 +289,21 @@ Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
case tok::comma: Opc = BinaryOperator::Comma; break;
}
if (BinaryOperator::isMultiplicativeOp(Opc))
CheckMultiplicativeOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isAdditiveOp(Opc))
CheckAdditiveOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isShiftOp(Opc))
CheckShiftOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isRelationalOp(Opc))
CheckRelationalOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isEqualityOp(Opc))
CheckEqualityOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isBitwiseOp(Opc))
CheckBitwiseOperands((Expr*)LHS, (Expr*)RHS);
else if (BinaryOperator::isLogicalOp(Opc))
CheckLogicalOperands((Expr*)LHS, (Expr*)RHS);
return new BinaryOperator((Expr*)LHS, (Expr*)RHS, Opc);
}
@ -301,3 +316,24 @@ Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS);
}
void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
}
void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
}

View File

@ -27,9 +27,9 @@ namespace clang {
/// is required.
///
class Expr : public Stmt {
/// TODO: Type.
TypeRef Type;
public:
Expr(StmtClass SC) : Stmt(SC) {}
Expr(StmtClass SC, TypeRef T=0) : Stmt(SC), Type(T) {}
~Expr() {}
virtual void visit(StmtVisitor &Visitor);
@ -60,25 +60,14 @@ public:
static bool classof(const DeclRefExpr *) { return true; }
};
// FIXME: The "type" will eventually be moved to Stmt.
class IntegerLiteral : public Expr {
TypeRef Type; // IntTy, LongTy, LongLongTy
// UnsignedIntTy, UnsignedLongTy, UnsignedLongLongTy
intmax_t Value;
public:
// FIXME: To satisfy some of the current adhoc usage...
IntegerLiteral() : Expr(IntegerLiteralClass),
Type(0), Value(0) {
}
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
// or UnsignedLongLongTy
IntegerLiteral(intmax_t value, TypeRef type)
: Expr(IntegerLiteralClass), Type(type), Value(value) {
#if 0
std::cout << "Value=" << Value;
std::cout << " Type= ";
std::cout << static_cast<BuiltinType *>(type.getTypePtr())->getName();
std::cout << "\n";
#endif
: Expr(IntegerLiteralClass, type), Value(value) {
assert(type->isIntegralType() && "Illegal type in IntegerLiteral");
}
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
@ -89,7 +78,7 @@ public:
class FloatingLiteral : public Expr {
public:
FloatingLiteral() : Expr(FloatingLiteralClass) {}
FloatingLiteral() : Expr(FloatingLiteralClass) {}
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
@ -328,6 +317,15 @@ public:
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
static const char *getOpcodeStr(Opcode Op);
/// predicates to categorize the respective opcodes.
static bool isMultiplicativeOp(Opcode Op) { return Op >= Mul && Op <= Rem; }
static bool isAdditiveOp(Opcode Op) { return Op == Add || Op == Sub; }
static bool isShiftOp(Opcode Op) { return Op == Shl || Op == Shr; }
static bool isRelationalOp(Opcode Op) { return Op >= LT && Op <= GE; }
static bool isEqualityOp(Opcode Op) { return Op == EQ || Op == NE; }
static bool isBitwiseOp(Opcode Op) { return Op >= And && Op <= Or; }
static bool isLogicalOp(Opcode Op) { return Op == LAnd || Op == LOr; }
Opcode getOpcode() const { return Opc; }
Expr *getLHS() { return LHS; }
@ -338,7 +336,6 @@ public:
return T->getStmtClass() == BinaryOperatorClass;
}
static bool classof(const BinaryOperator *) { return true; }
private:
Expr *LHS, *RHS;
Opcode Opc;

View File

@ -182,13 +182,26 @@ public:
bool isCanonical() const { return CanonicalType == this; }
Type *getCanonicalType() const { return CanonicalType; }
/// Helper methods to distinguish type categories. All type predicates
/// operate on the canonical type, ignoring typedefs.
bool isIntegralType() const; // short/int/long, char, bool, enum { ... }
bool isFloatingType() const; // float, double, long double, complex
bool isArithmeticType() const; // integral + floating
bool isScalarType() const; // arithmetic + pointers
bool isAggregateType() const; // arrays, structures
/// isVoidType - Helper method to determine if this is the 'void' type.
bool isVoidType() const;
bool isVoidType() const;
bool isFunctionType() const;
bool isPointerType() const;
bool isArrayType() const;
bool isStructureType() const;
bool isUnionType() const;
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
/// - a type that can describe objects, but which lacks information needed to
/// determine its size (e.g. void, or a fwd declared struct).
/// determine its size (e.g. void, or a fwd declared struct). Clients of this
/// routine will need to determine if the size is actually required.
bool isIncompleteType() const;
virtual void getAsString(std::string &InnerString) const = 0;
@ -397,7 +410,7 @@ public:
class TypedefType : public Type {
TypedefDecl *Decl;
TypedefType(TypedefDecl *D, Type *can) : Type(TypeName, can), Decl(D) {
assert(!isa<TypedefType>(can) && "Invalid canonoical type");
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
friend class ASTContext; // ASTContext creates these.
public: