[cfe-commits] r39408 - in /cfe/cfe/trunk: AST/Expr.cpp AST/Sema.h AST/SemaExpr.cpp Sema/Sema.h Sema/SemaExpr.cpp clang.xcodeproj/project.pbxproj include/clang/AST/Decl.h include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticKinds.def
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:44:03 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:44:03 2007
New Revision: 39408
URL: http://llvm.org/viewvc/llvm-project?rev=39408&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Continue working on type checking for unary operators. Added:
- Two 3 private functions to Sema: CheckAddressOfOperand(), CheckIndirectionOperand(),
and getDecl().
- Added Expr::isLvalue() - it was needed for CheckAddressOfOperand(). It will
also be needed for ++/-- and the assignment operators.
- Added a couple diagnostics for invalid lvalues (for & of).
Modified:
cfe/cfe/trunk/AST/Expr.cpp
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/clang.xcodeproj/project.pbxproj
cfe/cfe/trunk/include/clang/AST/Decl.h
cfe/cfe/trunk/include/clang/AST/Expr.h
cfe/cfe/trunk/include/clang/AST/ExprCXX.h
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
Modified: cfe/cfe/trunk/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Expr.cpp?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:03 2007
@@ -117,3 +117,41 @@
case Comma: return ",";
}
}
+
+/// Expressions that can be lvalues:
+/// - name, where name must be a variable
+/// - e[i]
+/// - (e), where e must be an lvalue
+/// - e.name, where e must be an lvalue
+/// - e->name
+/// - *e
+/// - string-constant
+///
+bool Expr::isLvalue() {
+ switch (getStmtClass()) {
+ case StringLiteralClass:
+ return true;
+ case ArraySubscriptExprClass:
+ return true;
+ case DeclRefExprClass:
+ const DeclRefExpr *d = cast<DeclRefExpr>(this);
+ if (isa<VarDecl>(d->getDecl()))
+ return true;
+ return false;
+ case MemberExprClass:
+ const MemberExpr *m = cast<MemberExpr>(this);
+ if (m->isArrow())
+ return true;
+ return m->getBase()->isLvalue(); // make sure "." is an lvalue
+ case UnaryOperatorClass:
+ const UnaryOperator *u = cast<UnaryOperator>(this);
+ if (u->getOpcode() == UnaryOperator::Deref)
+ return true;
+ return false;
+ case ParenExprClass:
+ const ParenExpr *pref = cast<ParenExpr>(this);
+ return pref->getSubExpr()->isLvalue();
+ default:
+ return false;
+ }
+}
Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:03 2007
@@ -223,10 +223,11 @@
tok::TokenKind Kind);
private:
Expr *ImplicitConversion(Expr *E); // C99 6.3
-
- /// type checking binary operators (subroutines of ParseBinOp).
+
/// the following "Check" methods will either return a well formed AST node
/// or will return true if the expressions didn't type check properly.
+
+ /// type checking binary operators (subroutines of ParseBinOp).
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
@@ -235,6 +236,12 @@
ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
ExprResult CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
+ /// type checking unary operators (subroutines of ParseUnaryOp).
+ /// C99 6.5.3.2
+ ExprResult CheckAddressOfOperand(Expr *op, SourceLocation loc, unsigned c);
+ Decl *getDecl(Expr *e);
+ ExprResult CheckIndirectionOperand(Expr *op, SourceLocation loc, unsigned c);
+
ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
unsigned /*UnaryOperator::Opcode*/c);
};
Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:03 2007
@@ -176,6 +176,10 @@
}
if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+ else if (Opc == UnaryOperator::AddrOf)
+ return CheckAddressOfOperand((Expr *)Input, OpLoc, Opc);
+ else if (Opc == UnaryOperator::Deref)
+ return CheckIndirectionOperand((Expr *)Input, OpLoc, Opc);
// when all the check functions are written, this will go away...
return new UnaryOperator((Expr*)Input, Opc, QualType());
@@ -451,3 +455,64 @@
return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, qType);
}
+/// getDecl - This is currently a helper function for CheckAddressOfOperand().
+/// This routine allows us to typecheck complex/recursive expressions
+/// where the declaration is needed for type checking. Here are some
+/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+Decl *Sema::getDecl(Expr *e) {
+ switch (e->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(e)->getDecl();
+ case Stmt::MemberExprClass:
+ return getDecl(cast<MemberExpr>(e)->getBase());
+ case Stmt::ArraySubscriptExprClass:
+ return getDecl(cast<ArraySubscriptExpr>(e)->getBase());
+ case Stmt::CallExprClass:
+ return getDecl(cast<CallExpr>(e)->getCallee());
+ case Stmt::UnaryOperatorClass:
+ return getDecl(cast<UnaryOperator>(e)->getSubExpr());
+ case Stmt::ParenExprClass:
+ return getDecl(cast<ParenExpr>(e)->getSubExpr());
+ default:
+ return 0;
+ }
+}
+
+/// CheckAddressOfOperand - The operand of & must be either a function
+/// designator or an lvalue designating an object. If it is an lvalue, the
+/// object cannot be declared with storage class register or be a bit field.
+/// Note: The usual conversions are *not* applied to the operand of the &
+/// operator, and its result is never an lvalue.
+Action::ExprResult
+Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+ Decl *dcl = getDecl(op);
+
+ if (!op->isLvalue()) {
+ if (dcl && isa<FunctionDecl>(dcl))
+ ; // C99 6.5.3.2p1: Allow function designators.
+ else
+ return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
+ } else if (dcl) {
+ // We have an lvalue with a decl. Make sure the decl is not declared
+ // with the register storage-class specifier.
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
+ if (vd->getStorageClass() == VarDecl::Register)
+ return Diag(OpLoc, diag::err_typecheck_address_of_register);
+ }
+ // FIXME: add check for bitfields!
+ }
+ // If the operand has type "type", the result has type "pointer to type".
+ return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode,
+ Context.getPointerType(op->getType()));
+}
+
+Action::ExprResult
+Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+ QualType qType = op->getType();
+
+ assert(!qType.isNull() && "no type for * expression");
+
+ QualType canonType = qType.getCanonicalType();
+
+ return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, QualType());
+}
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:03 2007
@@ -223,10 +223,11 @@
tok::TokenKind Kind);
private:
Expr *ImplicitConversion(Expr *E); // C99 6.3
-
- /// type checking binary operators (subroutines of ParseBinOp).
+
/// the following "Check" methods will either return a well formed AST node
/// or will return true if the expressions didn't type check properly.
+
+ /// type checking binary operators (subroutines of ParseBinOp).
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
@@ -235,6 +236,12 @@
ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2); // C99 6.5.[10...12]
ExprResult CheckLogicalOperands(Expr *op1, Expr *op2); // C99 6.5.[13,14]
+ /// type checking unary operators (subroutines of ParseUnaryOp).
+ /// C99 6.5.3.2
+ ExprResult CheckAddressOfOperand(Expr *op, SourceLocation loc, unsigned c);
+ Decl *getDecl(Expr *e);
+ ExprResult CheckIndirectionOperand(Expr *op, SourceLocation loc, unsigned c);
+
ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
unsigned /*UnaryOperator::Opcode*/c);
};
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:03 2007
@@ -176,6 +176,10 @@
}
if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+ else if (Opc == UnaryOperator::AddrOf)
+ return CheckAddressOfOperand((Expr *)Input, OpLoc, Opc);
+ else if (Opc == UnaryOperator::Deref)
+ return CheckIndirectionOperand((Expr *)Input, OpLoc, Opc);
// when all the check functions are written, this will go away...
return new UnaryOperator((Expr*)Input, Opc, QualType());
@@ -451,3 +455,64 @@
return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, qType);
}
+/// getDecl - This is currently a helper function for CheckAddressOfOperand().
+/// This routine allows us to typecheck complex/recursive expressions
+/// where the declaration is needed for type checking. Here are some
+/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+Decl *Sema::getDecl(Expr *e) {
+ switch (e->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(e)->getDecl();
+ case Stmt::MemberExprClass:
+ return getDecl(cast<MemberExpr>(e)->getBase());
+ case Stmt::ArraySubscriptExprClass:
+ return getDecl(cast<ArraySubscriptExpr>(e)->getBase());
+ case Stmt::CallExprClass:
+ return getDecl(cast<CallExpr>(e)->getCallee());
+ case Stmt::UnaryOperatorClass:
+ return getDecl(cast<UnaryOperator>(e)->getSubExpr());
+ case Stmt::ParenExprClass:
+ return getDecl(cast<ParenExpr>(e)->getSubExpr());
+ default:
+ return 0;
+ }
+}
+
+/// CheckAddressOfOperand - The operand of & must be either a function
+/// designator or an lvalue designating an object. If it is an lvalue, the
+/// object cannot be declared with storage class register or be a bit field.
+/// Note: The usual conversions are *not* applied to the operand of the &
+/// operator, and its result is never an lvalue.
+Action::ExprResult
+Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+ Decl *dcl = getDecl(op);
+
+ if (!op->isLvalue()) {
+ if (dcl && isa<FunctionDecl>(dcl))
+ ; // C99 6.5.3.2p1: Allow function designators.
+ else
+ return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
+ } else if (dcl) {
+ // We have an lvalue with a decl. Make sure the decl is not declared
+ // with the register storage-class specifier.
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
+ if (vd->getStorageClass() == VarDecl::Register)
+ return Diag(OpLoc, diag::err_typecheck_address_of_register);
+ }
+ // FIXME: add check for bitfields!
+ }
+ // If the operand has type "type", the result has type "pointer to type".
+ return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode,
+ Context.getPointerType(op->getType()));
+}
+
+Action::ExprResult
+Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+ QualType qType = op->getType();
+
+ assert(!qType.isNull() && "no type for * expression");
+
+ QualType canonType = qType.getCanonicalType();
+
+ return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, QualType());
+}
Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:44:03 2007
@@ -483,10 +483,12 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+ compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";
projectRoot = "";
+ shouldCheckCompatibility = 1;
targets = (
8DD76F620486A84900D96B5E /* clang */,
);
Modified: cfe/cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Decl.h?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:44:03 2007
@@ -136,7 +136,7 @@
protected:
VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
StorageClass SC)
- : ValueDecl(DK, L, Id, T) {}
+ : ValueDecl(DK, L, Id, T) { SClass = SC; }
private:
StorageClass SClass;
// TODO: Initializer.
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=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:03 2007
@@ -35,6 +35,17 @@
public:
QualType getType() const { return TR; }
+ /// isLvalue - return true if the expression is one of the following:
+ /// - name, where name must be a variable
+ /// - e[i]
+ /// - (e), where e must be an lvalue
+ /// - e.name, where e must be an lvalue
+ /// - e->name
+ /// - *e
+ /// - string-constant
+ ///
+ bool isLvalue();
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
@@ -55,7 +66,7 @@
DeclRefExpr(Decl *d, QualType t) : Expr(DeclRefExprClass, t), D(d) {}
Decl *getDecl() const { return D; }
-
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
@@ -72,6 +83,7 @@
: Expr(IntegerLiteralClass, type), Value(value) {
assert(type->isIntegralType() && "Illegal type in IntegerLiteral");
}
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == IntegerLiteralClass;
@@ -84,6 +96,7 @@
public:
FloatingLiteral(float value, QualType type) :
Expr(FloatingLiteralClass, type), Value(value) {}
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
@@ -119,8 +132,8 @@
ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
: Expr(ParenExprClass, QualType()), L(l), R(r), Val(val) {}
- Expr *getSubExpr() { return Val; }
-
+ Expr *getSubExpr() const { return Val; }
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenExprClass;
@@ -156,12 +169,16 @@
/// isPostfix - Return true if this is a postfix operation, like x++.
static bool isPostfix(Opcode Op);
-
Opcode getOpcode() const { return Opc; }
- Expr *getSubExpr() { return Val; }
+ Expr *getSubExpr() const { return Val; }
bool isPostfix() const { return isPostfix(Opc); }
+ /// getDecl - a recursive routine that derives the base decl for an
+ /// expression. For example, it will return the declaration for "s" from
+ /// the following complex expression "s.zz[2].bb.vv".
+ static bool isAddressable(Expr *e);
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryOperatorClass;
@@ -205,7 +222,7 @@
Expr(ArraySubscriptExprClass, t),
Base(base), Idx(idx) {}
- Expr *getBase() { return Base; }
+ Expr *getBase() const { return Base; }
Expr *getIdx() { return Idx; }
virtual void visit(StmtVisitor &Visitor);
@@ -228,7 +245,7 @@
delete [] Args;
}
- Expr *getCallee() { return Fn; }
+ Expr *getCallee() const { return Fn; }
/// getNumArgs - Return the number of actual arguments to this call.
///
@@ -243,7 +260,7 @@
/// getNumCommas - Return the number of commas that must have been present in
/// this function call.
unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
-
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == CallExprClass;
@@ -262,8 +279,8 @@
: Expr(MemberExprClass, memberdecl->getType()),
Base(base), MemberDecl(memberdecl), IsArrow(isarrow) {}
- Expr *getBase() { return Base; }
- FieldDecl *getMemberDecl() { return MemberDecl; }
+ Expr *getBase() const { return Base; }
+ FieldDecl *getMemberDecl() const { return MemberDecl; }
bool isArrow() const { return IsArrow; }
virtual void visit(StmtVisitor &Visitor);
@@ -287,6 +304,7 @@
QualType getDestType() const { return Ty; }
Expr *getSubExpr() { return Op; }
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == CastExprClass;
Modified: cfe/cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/ExprCXX.h?rev=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/cfe/trunk/include/clang/AST/ExprCXX.h Wed Jul 11 11:44:03 2007
@@ -50,6 +50,9 @@
public:
CXXBoolLiteralExpr(bool val) :
Expr(CXXBoolLiteralExprClass, QualType()), Value(val) {}
+
+ virtual Expr *getPrimaryExpr() { return this; }
+
virtual void visit(StmtVisitor &Visitor);
};
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=39408&r1=39407&r2=39408&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:03 2007
@@ -529,6 +529,10 @@
"illegal storage class on file-scoped variable")
DIAG(err_typecheck_sclass_func, ERROR,
"illegal storage class on function")
+DIAG(err_typecheck_address_of_register, ERROR,
+ "address of register variable requested")
+DIAG(err_typecheck_invalid_lvalue_addrof, ERROR,
+ "invalid lvalue in address expression")
// Statements.
DIAG(err_continue_not_in_loop, ERROR,
More information about the cfe-commits
mailing list