[cfe-commits] r39427 - in /cfe/cfe/trunk: AST/SemaExpr.cpp AST/Type.cpp 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:44:15 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:44:15 2007
New Revision: 39427
URL: http://llvm.org/viewvc/llvm-project?rev=39427&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Implement CheckAssignmentOperands(). This includes...
- Adding 6 static member predicates to Type.
- Adding 2 error diagnostics and 3 GCC extensions.
- Adding a "getValue" accessor to IntegerLiteral.
Still more work to do (including implement compound assignments).
Modified:
cfe/cfe/trunk/AST/SemaExpr.cpp
cfe/cfe/trunk/AST/Type.cpp
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/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:15 2007
@@ -601,13 +601,79 @@
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
}
-Action::ExprResult Sema::CheckAssignmentOperands( // C99 6.5.16
+/// CheckAssignmentOperands (C99 6.5.16) - This routine currently
+/// has code to accommodate several GCC extensions when type checking
+/// pointers. Here are some objectionable examples that GCC considers warnings:
+///
+/// int a, *pint;
+/// short *pshort;
+/// struct foo *pfoo;
+///
+/// pint = pshort; // warning: assignment from incompatible pointer type
+/// a = pint; // warning: assignment makes integer from pointer without a cast
+/// pint = a; // warning: assignment makes pointer from integer without a cast
+/// pint = pfoo; // warning: assignment from incompatible pointer type
+///
+/// As a result, the code for dealing with pointers is more complex than the
+/// C99 spec dictates.
+/// Note: the warning above turn into errors when -pedantic-errors is enabled.
+///
+Action::ExprResult Sema::CheckAssignmentOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
{
QualType lhsType = lex->getType();
QualType rhsType = rex->getType();
- // FIXME: add type checking and fix result type
+ if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
+ if (lhsType.isConstQualified())
+ return Diag(loc, diag::err_typecheck_assign_const);
+
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) {
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isPointerType()) {
+ if (rhsType->isIntegerType()) {
+ // check for null pointer constant (C99 6.3.2.3p3)
+ const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
+ if (!constant || constant->getValue() != 0)
+ Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ // FIXME: make sure the qualifier are matching
+ if (rhsType->isPointerType()) {
+ if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ } else if (rhsType->isPointerType()) {
+ if (lhsType->isIntegerType()) {
+ Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ // FIXME: make sure the qualifier are matching
+ if (lhsType->isPointerType()) {
+ if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ } else if (lhsType->isArrayType() && rhsType->isArrayType()) {
+ /// int aryInt[3], aryInt2[3];
+ /// aryInt = aryInt2; // gcc considers this an error (FIXME?)
+ if (Type::arrayTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isStructureType() && rhsType->isStructureType()) {
+ if (Type::structureTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isUnionType() && rhsType->isUnionType()) {
+ if (Type::unionTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isFunctionType() && rhsType->isFunctionType()) {
+ if (Type::functionTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ return Diag(loc, diag::err_typecheck_assign_incompatible);
+ }
+
+ // FIXME: type check compound assignments...
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
}
Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:44:15 2007
@@ -71,6 +71,76 @@
return false;
}
+// C99 6.2.7p1: If both are complete types, then the following additional
+// requirements apply...FIXME (handle compatibility across source files).
+bool Type::structureTypesAreCompatible(QualType lhs, QualType rhs) {
+ TagDecl *ldecl = cast<TagType>(lhs.getCanonicalType())->getDecl();
+ TagDecl *rdecl = cast<TagType>(rhs.getCanonicalType())->getDecl();
+
+ if (ldecl->getKind() == Decl::Struct && rdecl->getKind() == Decl::Struct) {
+ if (ldecl->getIdentifier() == rdecl->getIdentifier())
+ return true;
+ }
+ return false;
+}
+
+bool Type::unionTypesAreCompatible(QualType lhs, QualType rhs) {
+ TagDecl *ldecl = cast<TagType>(lhs.getCanonicalType())->getDecl();
+ TagDecl *rdecl = cast<TagType>(rhs.getCanonicalType())->getDecl();
+
+ if (ldecl->getKind() == Decl::Union && rdecl->getKind() == Decl::Union) {
+ if (ldecl->getIdentifier() == rdecl->getIdentifier())
+ return true;
+ }
+ return false;
+}
+
+bool Type::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
+ QualType ltype = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+ QualType rtype = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+ // handle void first (not sure this is the best place to check for this).
+ if (ltype->isVoidType() || rtype->isVoidType())
+ return true;
+ return typesAreCompatible(ltype, rtype);
+}
+
+bool Type::functionTypesAreCompatible(QualType lhs, QualType rhs) {
+ return true; // FIXME: add more checking
+}
+
+bool Type::arrayTypesAreCompatible(QualType lhs, QualType rhs) {
+ QualType ltype = cast<ArrayType>(lhs.getCanonicalType())->getElementType();
+ QualType rtype = cast<ArrayType>(rhs.getCanonicalType())->getElementType();
+
+ if (!typesAreCompatible(ltype, rtype))
+ return false;
+
+ // FIXME: If both types specify constant sizes, then the sizes must also be
+ // the same. Even if the sizes are the same, GCC produces an error.
+ return true;
+}
+
+bool Type::typesAreCompatible(QualType lcanon, QualType rcanon) {
+ // If two types are identical, they are are compatible
+ if (lcanon == rcanon)
+ return true;
+
+ if (lcanon->isStructureType() && rcanon->isStructureType())
+ return structureTypesAreCompatible(lcanon, rcanon);
+
+ if (lcanon->isPointerType() && rcanon->isPointerType())
+ return pointerTypesAreCompatible(lcanon, rcanon);
+
+ if (lcanon->isArrayType() && rcanon->isArrayType())
+ return arrayTypesAreCompatible(lcanon, rcanon);
+
+ if (lcanon->isFunctionType() && rcanon->isFunctionType())
+ return functionTypesAreCompatible(lcanon, rcanon);
+
+ return false;
+}
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:15 2007
@@ -601,13 +601,79 @@
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
}
-Action::ExprResult Sema::CheckAssignmentOperands( // C99 6.5.16
+/// CheckAssignmentOperands (C99 6.5.16) - This routine currently
+/// has code to accommodate several GCC extensions when type checking
+/// pointers. Here are some objectionable examples that GCC considers warnings:
+///
+/// int a, *pint;
+/// short *pshort;
+/// struct foo *pfoo;
+///
+/// pint = pshort; // warning: assignment from incompatible pointer type
+/// a = pint; // warning: assignment makes integer from pointer without a cast
+/// pint = a; // warning: assignment makes pointer from integer without a cast
+/// pint = pfoo; // warning: assignment from incompatible pointer type
+///
+/// As a result, the code for dealing with pointers is more complex than the
+/// C99 spec dictates.
+/// Note: the warning above turn into errors when -pedantic-errors is enabled.
+///
+Action::ExprResult Sema::CheckAssignmentOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
{
QualType lhsType = lex->getType();
QualType rhsType = rex->getType();
- // FIXME: add type checking and fix result type
+ if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
+ if (lhsType.isConstQualified())
+ return Diag(loc, diag::err_typecheck_assign_const);
+
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) {
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isPointerType()) {
+ if (rhsType->isIntegerType()) {
+ // check for null pointer constant (C99 6.3.2.3p3)
+ const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
+ if (!constant || constant->getValue() != 0)
+ Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ // FIXME: make sure the qualifier are matching
+ if (rhsType->isPointerType()) {
+ if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ } else if (rhsType->isPointerType()) {
+ if (lhsType->isIntegerType()) {
+ Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ // FIXME: make sure the qualifier are matching
+ if (lhsType->isPointerType()) {
+ if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ } else if (lhsType->isArrayType() && rhsType->isArrayType()) {
+ /// int aryInt[3], aryInt2[3];
+ /// aryInt = aryInt2; // gcc considers this an error (FIXME?)
+ if (Type::arrayTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isStructureType() && rhsType->isStructureType()) {
+ if (Type::structureTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isUnionType() && rhsType->isUnionType()) {
+ if (Type::unionTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ } else if (lhsType->isFunctionType() && rhsType->isFunctionType()) {
+ if (Type::functionTypesAreCompatible(lhsType, rhsType))
+ return new BinaryOperator(lex, rex, (BOP)code, lhsType);
+ }
+ return Diag(loc, diag::err_typecheck_assign_incompatible);
+ }
+
+ // FIXME: type check compound assignments...
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
}
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=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:15 2007
@@ -83,7 +83,8 @@
: Expr(IntegerLiteralClass, type), Value(value) {
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
}
-
+ intmax_t getValue() const { return Value; }
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == IntegerLiteralClass;
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=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:44:15 2007
@@ -233,6 +233,14 @@
bool isPromotableIntegerType() const; // C99 6.3.1.1p2
bool isSignedIntegerType() const; // C99 6.2.5p4
bool isUnsignedIntegerType() const; // C99 6.2.5p6
+
+ /// Compatibility predicates used to check assignment expressions.
+ static bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ static bool structureTypesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ static bool unionTypesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ static bool pointerTypesAreCompatible(QualType, QualType); // C99 6.7.5.1p2
+ static bool functionTypesAreCompatible(QualType, QualType); // C99 6.7.5.3p15
+ static bool arrayTypesAreCompatible(QualType, QualType); // C99 6.7.5.2p6
private:
// this forces clients to use isModifiableLvalue on QualType, the class that
// knows if the type is const. This predicate is a helper to QualType.
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=39427&r1=39426&r2=39427&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:15 2007
@@ -539,6 +539,16 @@
"invalid operands to binary expression")
DIAG(ext_typecheck_comparison_of_pointer_integer, EXTENSION,
"comparison between pointer and integer")
+DIAG(err_typecheck_assign_const, ERROR,
+ "assignment of read-only variable")
+DIAG(err_typecheck_assign_incompatible, ERROR,
+ "incompatible types in assignment")
+DIAG(ext_typecheck_assign_int_from_pointer, EXTENSION,
+ "assignment makes integer from pointer without a cast")
+DIAG(ext_typecheck_assign_pointer_from_int, EXTENSION,
+ "assignment makes pointer from integer without a cast")
+DIAG(ext_typecheck_assign_incompatible_pointer, EXTENSION,
+ "assignment from incompatible pointer type")
// Statements.
DIAG(err_continue_not_in_loop, ERROR,
More information about the cfe-commits
mailing list