Submitted by:
Reviewed by:
This check-in should finally "nail" complex pointer assignments (involving
qualifiers, etc.).
- Replaced pointerTypeQualifiersAlign() with CheckPointerTypesForAssignment()
This also simplified UsualAssignmentConversions().
- Fixed Type::pointerTypesAreCompatible() and Type::typesAreCompatible()
to closely reflect the spec. They were (unfortunately) compensating for some of the
missing logic in the assignment checking code.

llvm-svn: 39440
This commit is contained in:
Steve Naroff 2007-05-11 22:18:03 +00:00
parent 1f4d72724e
commit 3f59729549
5 changed files with 114 additions and 96 deletions

View File

@ -244,8 +244,9 @@ private:
// CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr.
QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
AssignmentConversionResult &r);
// Helper function for UsualAssignmentConversions
bool pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType);
// Helper function for UsualAssignmentConversions (C99 6.5.16.1p1)
QualType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType,
AssignmentConversionResult &r);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).

View File

@ -452,37 +452,46 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
return Context.maxIntegerType(lhs, rhs);
}
// C99 6.5.16.1p1: both operands are pointers to qualified or
// unqualified versions of compatible types, and the type *pointed to* by
// the left has all the qualifiers of the type *pointed to* by the right;
bool Sema::pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType) {
QualType lPointee, rPointee;
// CheckPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
QualType Sema::CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType,
AssignmentConversionResult &r) {
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
lPointee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
rPointee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
lhptee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
rhptee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
// make sure we operate on the canonical type
lPointee = lPointee.getCanonicalType();
rPointee = rPointee.getCanonicalType();
while (!rPointee.isNull() && !lPointee.isNull()) {
unsigned rightQuals = rPointee.getQualifiers();
if (rightQuals && (rightQuals != lPointee.getQualifiers()))
return false;
lhptee = lhptee.getCanonicalType();
rhptee = rhptee.getCanonicalType();
// if necessary, continue checking pointees...
if (const PointerType *rPtr = dyn_cast<PointerType>(rPointee))
rPointee = rPtr->getPointeeType().getCanonicalType();
else
rPointee = QualType();
if (const PointerType *lPtr = dyn_cast<PointerType>(lPointee))
lPointee = lPtr->getPointeeType().getCanonicalType();
else
rPointee = QualType();
}
return true;
// C99 6.5.16.1p1: This following citation is common to constraints
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
// qualifiers of the type *pointed to* by the right;
if ((lhptee.getQualifiers() & rhptee.getQualifiers()) !=
rhptee.getQualifiers())
r = CompatiblePointerDiscardsQualifiers;
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
// incomplete type and the other is a pointer to a qualified or unqualified
// version of void...
if (lhptee.getUnqualifiedType()->isVoidType() &&
(rhptee->isObjectType() || rhptee->isIncompleteType()))
;
else if (rhptee.getUnqualifiedType()->isVoidType() &&
(lhptee->isObjectType() || lhptee->isIncompleteType()))
;
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
else if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType()))
r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
return rhsType;
}
/// UsualAssignmentConversions (C99 6.5.16) - This routine currently
@ -519,14 +528,8 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
r = PointerFromInt;
return rhsType;
}
if (rhsType->isPointerType()) {
if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
if (!pointerTypeQualifiersAlign(lhsType, rhsType))
r = CompatiblePointerDiscardsQualifiers;
} else
r = IncompatiblePointer;
return rhsType;
}
if (rhsType->isPointerType())
return CheckPointerTypesForAssignment(lhsType, rhsType, r);
} else if (rhsType->isPointerType()) {
if (lhsType->isIntegerType()) {
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
@ -534,14 +537,8 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
r = IntFromPointer;
return rhsType;
}
if (lhsType->isPointerType()) {
if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
if (!pointerTypeQualifiersAlign(lhsType, rhsType))
r = CompatiblePointerDiscardsQualifiers;
} else
r = IncompatiblePointer;
return rhsType;
}
if (lhsType->isPointerType())
return CheckPointerTypesForAssignment(lhsType, rhsType, r);
} else if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
if (Type::tagTypesAreCompatible(lhsType, rhsType))
return rhsType;
@ -789,6 +786,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
if (dcl && isa<FunctionDecl>(dcl))
; // C99 6.5.3.2p1: Allow function designators.
else {
/* FIXME: The following produces an (incorrect) error. The
Type::isModifiableLvalue() predicate is causing problems.
const char **cpp;
const char c = 'A';
int main() { *cpp = &c; // valid }
*/
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
return QualType();
}

View File

@ -90,12 +90,14 @@ bool Type::tagTypesAreCompatible(QualType lhs, QualType rhs) {
}
bool Type::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
// C99 6.7.5.1p2: For two pointer types to be compatible, both shall be
// identically qualified and both shall be pointers to compatible types.
if (lhs.getQualifiers() != rhs.getQualifiers())
return false;
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);
}
@ -167,8 +169,6 @@ bool Type::typesAreCompatible(QualType lhs, QualType rhs) {
switch (lcanon->getTypeClass()) {
case Type::Pointer:
// C99 6.7.3p9: For two qualified types to be compatible, both shall have
// the identically qualified version of a compatible type. ??
return pointerTypesAreCompatible(lcanon, rcanon);
case Type::Array:
return arrayTypesAreCompatible(lcanon, rcanon);
@ -178,10 +178,16 @@ bool Type::typesAreCompatible(QualType lhs, QualType rhs) {
case Type::Tagged: // handle structures, unions
return tagTypesAreCompatible(lcanon, rcanon);
case Type::Builtin:
// exclude type qualifiers...
// C99 6.7.3p9: For two qualified types to be compatible, both shall
// have the identically qualified version of a compatible type.
if (lhs.getQualifiers() != rhs.getQualifiers())
return false;
// C99 6.2.7p1: Two types have compatible types if their types are the
// same. See 6.7.[2,3,5] for additional rules.
if (lcanon.getTypePtr() == rcanon.getTypePtr())
return true;
return false; // C99 6.2.7p1
return false;
default:
assert(0 && "unexpected type");
}

View File

@ -244,8 +244,9 @@ private:
// CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr.
QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
AssignmentConversionResult &r);
// Helper function for UsualAssignmentConversions
bool pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType);
// Helper function for UsualAssignmentConversions (C99 6.5.16.1p1)
QualType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType,
AssignmentConversionResult &r);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).

View File

@ -452,37 +452,46 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
return Context.maxIntegerType(lhs, rhs);
}
// C99 6.5.16.1p1: both operands are pointers to qualified or
// unqualified versions of compatible types, and the type *pointed to* by
// the left has all the qualifiers of the type *pointed to* by the right;
bool Sema::pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType) {
QualType lPointee, rPointee;
// CheckPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
QualType Sema::CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType,
AssignmentConversionResult &r) {
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
lPointee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
rPointee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
lhptee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
rhptee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
// make sure we operate on the canonical type
lPointee = lPointee.getCanonicalType();
rPointee = rPointee.getCanonicalType();
while (!rPointee.isNull() && !lPointee.isNull()) {
unsigned rightQuals = rPointee.getQualifiers();
if (rightQuals && (rightQuals != lPointee.getQualifiers()))
return false;
lhptee = lhptee.getCanonicalType();
rhptee = rhptee.getCanonicalType();
// if necessary, continue checking pointees...
if (const PointerType *rPtr = dyn_cast<PointerType>(rPointee))
rPointee = rPtr->getPointeeType().getCanonicalType();
else
rPointee = QualType();
if (const PointerType *lPtr = dyn_cast<PointerType>(lPointee))
lPointee = lPtr->getPointeeType().getCanonicalType();
else
rPointee = QualType();
}
return true;
// C99 6.5.16.1p1: This following citation is common to constraints
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
// qualifiers of the type *pointed to* by the right;
if ((lhptee.getQualifiers() & rhptee.getQualifiers()) !=
rhptee.getQualifiers())
r = CompatiblePointerDiscardsQualifiers;
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
// incomplete type and the other is a pointer to a qualified or unqualified
// version of void...
if (lhptee.getUnqualifiedType()->isVoidType() &&
(rhptee->isObjectType() || rhptee->isIncompleteType()))
;
else if (rhptee.getUnqualifiedType()->isVoidType() &&
(lhptee->isObjectType() || lhptee->isIncompleteType()))
;
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
else if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType()))
r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
return rhsType;
}
/// UsualAssignmentConversions (C99 6.5.16) - This routine currently
@ -519,14 +528,8 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
r = PointerFromInt;
return rhsType;
}
if (rhsType->isPointerType()) {
if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
if (!pointerTypeQualifiersAlign(lhsType, rhsType))
r = CompatiblePointerDiscardsQualifiers;
} else
r = IncompatiblePointer;
return rhsType;
}
if (rhsType->isPointerType())
return CheckPointerTypesForAssignment(lhsType, rhsType, r);
} else if (rhsType->isPointerType()) {
if (lhsType->isIntegerType()) {
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
@ -534,14 +537,8 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
r = IntFromPointer;
return rhsType;
}
if (lhsType->isPointerType()) {
if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
if (!pointerTypeQualifiersAlign(lhsType, rhsType))
r = CompatiblePointerDiscardsQualifiers;
} else
r = IncompatiblePointer;
return rhsType;
}
if (lhsType->isPointerType())
return CheckPointerTypesForAssignment(lhsType, rhsType, r);
} else if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
if (Type::tagTypesAreCompatible(lhsType, rhsType))
return rhsType;
@ -789,6 +786,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
if (dcl && isa<FunctionDecl>(dcl))
; // C99 6.5.3.2p1: Allow function designators.
else {
/* FIXME: The following produces an (incorrect) error. The
Type::isModifiableLvalue() predicate is causing problems.
const char **cpp;
const char c = 'A';
int main() { *cpp = &c; // valid }
*/
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
return QualType();
}