[cfe-commits] r39369 - in /cfe/cfe/trunk: AST/Sema.cpp AST/Sema.h AST/SemaExpr.cpp AST/Type.cpp Sema/Sema.cpp Sema/Sema.h Sema/SemaExpr.cpp include/clang/AST/Expr.h include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:43:41 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:43:41 2007
New Revision: 39369
URL: http://llvm.org/viewvc/llvm-project?rev=39369&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Implement ++/-- typechecking for pre/post unary expressions. This includes:
- added isLvalue, isModifiableLvalue (on TypeRef, Type, and RecordType).
- added isRealType, isRealFloatingType, isComplexType.
- hacked Diag to take a TypeRef (I was sick of writing the 2 line "setup":-)
In addition, this will likely lead to less bugs...I already had written code
that was doing a getAsString on "Type" (which is wrong...since it doesn't include
any qualifiers).
- Changed UnaryOperator to take a TypeRef...pass it the right stuff.
- Removed redundant ternary expressions in several predicates.
- A couple diagnostics.
Modified:
cfe/cfe/trunk/AST/Sema.cpp
cfe/cfe/trunk/AST/Sema.h
cfe/cfe/trunk/AST/SemaExpr.cpp
cfe/cfe/trunk/AST/Type.cpp
cfe/cfe/trunk/Sema/Sema.cpp
cfe/cfe/trunk/Sema/Sema.h
cfe/cfe/trunk/Sema/SemaExpr.cpp
cfe/cfe/trunk/include/clang/AST/Expr.h
cfe/cfe/trunk/include/clang/AST/Type.h
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
Modified: cfe/cfe/trunk/AST/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.cpp?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.cpp (original)
+++ cfe/cfe/trunk/AST/Sema.cpp Wed Jul 11 11:43:41 2007
@@ -31,6 +31,13 @@
return true;
}
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, TypeRef t) {
+ std::string Name;
+ t.getAsString(Name);
+ PP.Diag(Loc, DiagID, Name);
+ return true;
+}
+
bool Sema::Diag(const LexerToken &Tok, unsigned DiagID, const std::string &M) {
Diag(Tok.getLocation(), DiagID, M);
return true;
Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:43:41 2007
@@ -58,6 +58,7 @@
const std::string &Msg = std::string());
bool Diag(const LexerToken &Tok, unsigned DiagID,
const std::string &M = std::string());
+ bool Diag(SourceLocation Loc, unsigned DiagID, TypeRef t);
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:43:41 2007
@@ -173,8 +173,22 @@
//Opc = UnaryOperator::Extension;
//break;
}
+ TypeRef type = ((Expr *)Input)->getTypeRef();
- return new UnaryOperator((Expr*)Input, Opc);
+ assert(!type.isNull() && "no type for prefix unary expression");
+
+ if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec) {
+ // C99 6.5.3.1: isRealType excludes complex (GCC allows complex).
+ if (!type->isRealType() && !type->isPointerType())
+ return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);
+
+ // At this point, we know we have a real or pointer type. As a result, the
+ // following predicate is overkill (i.e. it will check for types we know we
+ // don't have in this context). Nevertheless, we model the C99 spec closely.
+ if (!type.isModifiableLvalue())
+ return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+ }
+ return new UnaryOperator((Expr*)Input, Opc, type);
}
Action::ExprResult Sema::
@@ -214,8 +228,21 @@
case tok::plusplus: Opc = UnaryOperator::PostInc; break;
case tok::minusminus: Opc = UnaryOperator::PostDec; break;
}
+ TypeRef type = ((Expr *)Input)->getTypeRef();
+
+ assert(!type.isNull() && "no type for postfix unary expression");
- return new UnaryOperator((Expr*)Input, Opc);
+ // C99 6.5.2.4: isRealType excludes complex (GCC allows complex).
+ if (!type->isRealType() && !type->isPointerType())
+ return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);
+
+ // At this point, we know we have a real or pointer type. As a result, the
+ // following predicate is overkill (i.e. it will check for types we know we
+ // don't have in this context). Nevertheless, we model the C99 spec closely.
+ if (!type.isModifiableLvalue())
+ return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+
+ return new UnaryOperator((Expr*)Input, Opc, type);
}
Action::ExprResult Sema::
@@ -253,11 +280,8 @@
resultType = ary->getPointeeType();
// in practice, the following check catches trying to index a pointer
// to a function (e.g. void (*)(int)). Functions are not objects in c99.
- if (!resultType->isObjectType()) {
- std::string Name;
- baseType->getAsString(Name);
- Diag(LLoc, diag::err_typecheck_subscript_not_object, Name);
- }
+ if (!resultType->isObjectType())
+ return Diag(LLoc, diag::err_typecheck_subscript_not_object, baseType);
}
return new ArraySubscriptExpr((Expr*)Base, (Expr*)Idx, resultType);
}
Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:43:41 2007
@@ -44,15 +44,15 @@
}
bool Type::isFunctionType() const {
- return isa<FunctionType>(CanonicalType) ? true : false;
+ return isa<FunctionType>(CanonicalType);
}
bool Type::isPointerType() const {
- return isa<PointerType>(CanonicalType) ? true : false;
+ return isa<PointerType>(CanonicalType);
}
bool Type::isArrayType() const {
- return isa<ArrayType>(CanonicalType) ? true : false;
+ return isa<ArrayType>(CanonicalType);
}
bool Type::isStructureType() const {
@@ -96,6 +96,42 @@
}
}
+bool Type::isRealFloatingType() const {
+ switch (CanonicalType->getTypeClass()) {
+ default: return false;
+ case Builtin:
+ const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ }
+}
+
+bool Type::isRealType() const {
+ // this is equivalent to (isIntegralType() || isRealFloatingType()).
+ switch (CanonicalType->getTypeClass()) { // inlined for performance
+ default: return false;
+ case Builtin:
+ const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ case Tagged:
+ const TagType *TT = static_cast<TagType*>(CanonicalType);
+ if (TT->getDecl()->getKind() == Decl::Enum)
+ return true;
+ return false;
+ }
+}
+
+bool Type::isComplexType() const {
+ switch (CanonicalType->getTypeClass()) {
+ default: return false;
+ case Builtin:
+ const BuiltinType *BT = static_cast<BuiltinType*>(CanonicalType);
+ return BT->getKind() >= BuiltinType::FloatComplex &&
+ BT->getKind() <= BuiltinType::LongDoubleComplex;
+ }
+}
+
bool Type::isArithmeticType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
@@ -152,6 +188,42 @@
}
}
+/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or
+/// an incomplete type other than void.
+bool Type::isLvalue() const {
+ if (isObjectType())
+ return true;
+ else if (isIncompleteType())
+ return isVoidType() ? false : true;
+ else
+ return false;
+}
+
+/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
+/// does not have an incomplete type, does not have a const-qualified type, and
+/// if it is a structure or union, does not have any member (including,
+/// recursively, any member or element of all contained aggregates or unions)
+/// with a const-qualified type.
+
+bool TypeRef::isModifiableLvalue() const {
+ if (isConstQualified())
+ return false;
+ else
+ return getTypePtr()->isModifiableLvalue();
+}
+
+bool Type::isModifiableLvalue() const {
+ if (!isLvalue())
+ return false;
+
+ if (isArrayType())
+ return false;
+ if (isIncompleteType())
+ return false;
+ if (const RecordType *r = dyn_cast<RecordType>(this))
+ return r->isModifiableLvalue();
+ return true;
+}
const char *BuiltinType::getName() const {
switch (getKind()) {
Modified: cfe/cfe/trunk/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.cpp?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.cpp (original)
+++ cfe/cfe/trunk/Sema/Sema.cpp Wed Jul 11 11:43:41 2007
@@ -31,6 +31,13 @@
return true;
}
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, TypeRef t) {
+ std::string Name;
+ t.getAsString(Name);
+ PP.Diag(Loc, DiagID, Name);
+ return true;
+}
+
bool Sema::Diag(const LexerToken &Tok, unsigned DiagID, const std::string &M) {
Diag(Tok.getLocation(), DiagID, M);
return true;
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:43:41 2007
@@ -58,6 +58,7 @@
const std::string &Msg = std::string());
bool Diag(const LexerToken &Tok, unsigned DiagID,
const std::string &M = std::string());
+ bool Diag(SourceLocation Loc, unsigned DiagID, TypeRef t);
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:43:41 2007
@@ -173,8 +173,22 @@
//Opc = UnaryOperator::Extension;
//break;
}
+ TypeRef type = ((Expr *)Input)->getTypeRef();
- return new UnaryOperator((Expr*)Input, Opc);
+ assert(!type.isNull() && "no type for prefix unary expression");
+
+ if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec) {
+ // C99 6.5.3.1: isRealType excludes complex (GCC allows complex).
+ if (!type->isRealType() && !type->isPointerType())
+ return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);
+
+ // At this point, we know we have a real or pointer type. As a result, the
+ // following predicate is overkill (i.e. it will check for types we know we
+ // don't have in this context). Nevertheless, we model the C99 spec closely.
+ if (!type.isModifiableLvalue())
+ return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+ }
+ return new UnaryOperator((Expr*)Input, Opc, type);
}
Action::ExprResult Sema::
@@ -214,8 +228,21 @@
case tok::plusplus: Opc = UnaryOperator::PostInc; break;
case tok::minusminus: Opc = UnaryOperator::PostDec; break;
}
+ TypeRef type = ((Expr *)Input)->getTypeRef();
+
+ assert(!type.isNull() && "no type for postfix unary expression");
- return new UnaryOperator((Expr*)Input, Opc);
+ // C99 6.5.2.4: isRealType excludes complex (GCC allows complex).
+ if (!type->isRealType() && !type->isPointerType())
+ return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);
+
+ // At this point, we know we have a real or pointer type. As a result, the
+ // following predicate is overkill (i.e. it will check for types we know we
+ // don't have in this context). Nevertheless, we model the C99 spec closely.
+ if (!type.isModifiableLvalue())
+ return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+
+ return new UnaryOperator((Expr*)Input, Opc, type);
}
Action::ExprResult Sema::
@@ -253,11 +280,8 @@
resultType = ary->getPointeeType();
// in practice, the following check catches trying to index a pointer
// to a function (e.g. void (*)(int)). Functions are not objects in c99.
- if (!resultType->isObjectType()) {
- std::string Name;
- baseType->getAsString(Name);
- Diag(LLoc, diag::err_typecheck_subscript_not_object, Name);
- }
+ if (!resultType->isObjectType())
+ return Diag(LLoc, diag::err_typecheck_subscript_not_object, baseType);
}
return new ArraySubscriptExpr((Expr*)Base, (Expr*)Idx, resultType);
}
Modified: cfe/cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Expr.h?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:43:41 2007
@@ -149,8 +149,8 @@
Extension // __extension__ marker.
};
- UnaryOperator(Expr *input, Opcode opc)
- : Expr(UnaryOperatorClass), Val(input), Opc(opc) {}
+ UnaryOperator(Expr *input, Opcode opc, TypeRef type)
+ : Expr(UnaryOperatorClass, type), Val(input), Opc(opc) {}
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++"
Modified: cfe/cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Type.h?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:43:41 2007
@@ -116,7 +116,9 @@
/// getCanonicalType - Return the canonical version of this type, with the
/// appropriate type qualifiers on it.
inline TypeRef getCanonicalType() const;
-
+
+ bool isModifiableLvalue() const;
+
void getAsString(std::string &S) const;
void dump() const;
};
@@ -201,10 +203,13 @@
/// Helper methods to distinguish type categories. All type predicates
/// operate on the canonical type, ignoring typedefs.
- bool isIntegralType() const; // C99 6.2.5p17 (int, char, bool, enum)
- bool isFloatingType() const; // C99 6.2.5p11 (float, double, long double)
- bool isArithmeticType() const; // C99 6.2.5p18 (integral + floating)
- bool isVoidType() const; // C99 6.2.5p19
+ bool isIntegralType() const; // C99 6.2.5p17 (int, char, bool, enum)
+ bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
+ bool isComplexType() const; // C99 6.2.5p11 (complex)
+ bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
+ bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
+ bool isArithmeticType() const; // C99 6.2.5p18 (integral + floating)
+ bool isVoidType() const; // C99 6.2.5p19
/// Derived types (C99 6.2.5p20). isFunctionType() is also a derived type.
bool isDerivedType() const;
@@ -215,7 +220,14 @@
bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
bool isAggregateType() const; // C99 6.2.5p21 (arrays, structures)
-
+
+ bool isLvalue() const; // C99 6.3.2.1
+private:
+ // this forces clients to use isModifiableLvalue on TypeRef, the class that
+ // knows if the type is const. This predicate is a helper to TypeRef.
+ bool isModifiableLvalue() const; // C99 6.3.2.1
+ friend class TypeRef;
+public:
virtual void getAsString(std::string &InnerString) const = 0;
static bool classof(const Type *) { return true; }
@@ -459,6 +471,7 @@
RecordDecl *getDecl() const {
return reinterpret_cast<RecordDecl*>(TagType::getDecl());
}
+ bool isModifiableLvalue() const { return true; } // FIXME
static bool classof(const Type *T);
static bool classof(const RecordType *) { return true; }
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39369&r1=39368&r2=39369&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:43:41 2007
@@ -498,6 +498,10 @@
"incomplete definition of type '%s'")
DIAG(err_typecheck_no_member, ERROR,
"no member named '%s'")
+DIAG(err_typecheck_illegal_increment_decrement, ERROR,
+ "cannot modify value of type '%s'")
+DIAG(err_typecheck_not_modifiable, ERROR,
+ "cannot modify read-only value of type '%s'")
// Statements.
DIAG(err_continue_not_in_loop, ERROR,
More information about the cfe-commits
mailing list