forked from OSchip/llvm-project
Bug #:
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:
parent
1f4d72724e
commit
3f59729549
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue