[cfe-commits] r39370 - in /cfe/cfe/trunk: AST/Sema.h AST/SemaExpr.cpp Sema/Sema.h Sema/SemaExpr.cpp include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:43:42 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:43:42 2007
New Revision: 39370
URL: http://llvm.org/viewvc/llvm-project?rev=39370&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Incorporate feedback from Chris (on the last check-in).
- added a shared hook for pre/post ++/-- CheckIncrementDecrementOperand().
- handle invalid arithmetic on incomplete types (void *, struct foo *, where the
body isn't in scope). Added a diagnostic for this case.
- added some comments and C99 annotations.
- Sema.h now includes Expr.h. I'd prefer not to, however it doesn't break
any layering.
Modified:
cfe/cfe/trunk/AST/Sema.h
cfe/cfe/trunk/AST/SemaExpr.cpp
cfe/cfe/trunk/Sema/Sema.h
cfe/cfe/trunk/Sema/SemaExpr.cpp
cfe/cfe/trunk/include/clang/AST/Type.h
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:43:42 2007
@@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_SEMA_H
#include "clang/Parse/Action.h"
+#include "clang/AST/Expr.h"
#include <vector>
#include <string>
@@ -24,7 +25,6 @@
class ASTContext;
class Preprocessor;
class Decl;
- class Expr;
class VarDecl;
class TypedefDecl;
class FunctionDecl;
@@ -225,13 +225,18 @@
Expr *ImplicitConversion(Expr *E); // C99 6.3
/// 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]
+ /// the following "Check" methods will either return a well formed AST node
+ /// or will return true if the expressions didn't type check properly.
+ ExprResult CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
+ ExprResult CheckAdditiveOperands(Expr *op1, Expr *op2); // C99 6.5.6
+ ExprResult CheckShiftOperands(Expr *op1, Expr *op2); // C99 6.5.7
+ ExprResult CheckRelationalOperands(Expr *op1, Expr *op2); // C99 6.5.8
+ ExprResult CheckEqualityOperands(Expr *op1, Expr *op2); // C99 6.5.9
+ ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
+ ExprResult CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
+
+ ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
+ UnaryOperator::Opcode Opc);
};
Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:43:42 2007
@@ -173,22 +173,11 @@
//Opc = UnaryOperator::Extension;
//break;
}
- TypeRef type = ((Expr *)Input)->getTypeRef();
-
- 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);
+ if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
+ return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+
+ // when all the check functions are written, this will go away...
+ return new UnaryOperator((Expr*)Input, Opc, 0);
}
Action::ExprResult Sema::
@@ -228,21 +217,7 @@
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");
-
- // 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);
+ return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
}
Action::ExprResult Sema::
@@ -273,6 +248,7 @@
if (!indexType->isIntegralType())
return Diag(LLoc, diag::err_typecheck_subscript);
+ // FIXME: need to deal with const...
TypeRef resultType;
if (ArrayType *ary = dyn_cast<ArrayType>(baseType)) {
resultType = ary->getElementType();
@@ -412,24 +388,54 @@
return E;
}
-void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+ return false;
+}
+
+Action::ExprResult Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult
+Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
+ UnaryOperator::Opcode OpCode) {
+ TypeRef type = op->getTypeRef();
+
+ assert(!type.isNull() && "no type for increment/decrement expression");
+
+ if (const PointerType *pt = dyn_cast<PointerType>(type)) {
+ if (!pt->getPointeeType()->isObjectType()) // C99 6.5.6p2
+ return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, type);
+ } else if (!type->isRealType()) // C99 6.5.2.4: isRealType excludes complex.
+ // FIXME: Allow Complex as a GCC extension.
+ 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(op, OpCode, type);
}
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:43:42 2007
@@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_SEMA_H
#include "clang/Parse/Action.h"
+#include "clang/AST/Expr.h"
#include <vector>
#include <string>
@@ -24,7 +25,6 @@
class ASTContext;
class Preprocessor;
class Decl;
- class Expr;
class VarDecl;
class TypedefDecl;
class FunctionDecl;
@@ -225,13 +225,18 @@
Expr *ImplicitConversion(Expr *E); // C99 6.3
/// 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]
+ /// the following "Check" methods will either return a well formed AST node
+ /// or will return true if the expressions didn't type check properly.
+ ExprResult CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
+ ExprResult CheckAdditiveOperands(Expr *op1, Expr *op2); // C99 6.5.6
+ ExprResult CheckShiftOperands(Expr *op1, Expr *op2); // C99 6.5.7
+ ExprResult CheckRelationalOperands(Expr *op1, Expr *op2); // C99 6.5.8
+ ExprResult CheckEqualityOperands(Expr *op1, Expr *op2); // C99 6.5.9
+ ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
+ ExprResult CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
+
+ ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
+ UnaryOperator::Opcode Opc);
};
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:43:42 2007
@@ -173,22 +173,11 @@
//Opc = UnaryOperator::Extension;
//break;
}
- TypeRef type = ((Expr *)Input)->getTypeRef();
-
- 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);
+ if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
+ return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+
+ // when all the check functions are written, this will go away...
+ return new UnaryOperator((Expr*)Input, Opc, 0);
}
Action::ExprResult Sema::
@@ -228,21 +217,7 @@
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");
-
- // 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);
+ return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
}
Action::ExprResult Sema::
@@ -273,6 +248,7 @@
if (!indexType->isIntegralType())
return Diag(LLoc, diag::err_typecheck_subscript);
+ // FIXME: need to deal with const...
TypeRef resultType;
if (ArrayType *ary = dyn_cast<ArrayType>(baseType)) {
resultType = ary->getElementType();
@@ -412,24 +388,54 @@
return E;
}
-void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+ return false;
+}
+
+Action::ExprResult Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+ return false;
}
-void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult
+Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
+ UnaryOperator::Opcode OpCode) {
+ TypeRef type = op->getTypeRef();
+
+ assert(!type.isNull() && "no type for increment/decrement expression");
+
+ if (const PointerType *pt = dyn_cast<PointerType>(type)) {
+ if (!pt->getPointeeType()->isObjectType()) // C99 6.5.6p2
+ return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, type);
+ } else if (!type->isRealType()) // C99 6.5.2.4: isRealType excludes complex.
+ // FIXME: Allow Complex as a GCC extension.
+ 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(op, OpCode, type);
}
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=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:43:42 2007
@@ -117,6 +117,11 @@
/// appropriate type qualifiers on it.
inline TypeRef getCanonicalType() const;
+ /// isModifiableLvalue - C99 6.3.2.1p1: returns true if the type is 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 struct/union, does not
+ /// have any member (including, recursively, any member or element of all
+ /// contained aggregates or unions) with a const-qualified type.
bool isModifiableLvalue() const;
void getAsString(std::string &S) const;
@@ -225,7 +230,7 @@
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
+ bool isModifiableLvalue() const; // C99 6.3.2.1p1
friend class TypeRef;
public:
virtual void getAsString(std::string &InnerString) const = 0;
@@ -471,7 +476,10 @@
RecordDecl *getDecl() const {
return reinterpret_cast<RecordDecl*>(TagType::getDecl());
}
- bool isModifiableLvalue() const { return true; } // FIXME
+ // FIXME: This predicate is a helper to TypeRef/Type. It needs to
+ // recursively check all fields for const-ness. If any field is declared
+ // const, it needs to return false.
+ bool isModifiableLvalue() const { return true; }
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=39370&r1=39369&r2=39370&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:43:42 2007
@@ -502,6 +502,8 @@
"cannot modify value of type '%s'")
DIAG(err_typecheck_not_modifiable, ERROR,
"cannot modify read-only value of type '%s'")
+DIAG(err_typecheck_arithmetic_incomplete_type, ERROR,
+ "arithmetic on pointer to incomplete type '%s'")
// Statements.
DIAG(err_continue_not_in_loop, ERROR,
More information about the cfe-commits
mailing list