diff --git a/clang/AST/Sema.h b/clang/AST/Sema.h index 98d2bc182106..5d25e01bb07e 100644 --- a/clang/AST/Sema.h +++ b/clang/AST/Sema.h @@ -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). diff --git a/clang/AST/SemaExpr.cpp b/clang/AST/SemaExpr.cpp index 7bed03575bfa..4c886fd429f8 100644 --- a/clang/AST/SemaExpr.cpp +++ b/clang/AST/SemaExpr.cpp @@ -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(lhsType.getCanonicalType())->getPointeeType(); - rPointee = cast(rhsType.getCanonicalType())->getPointeeType(); + lhptee = cast(lhsType.getCanonicalType())->getPointeeType(); + rhptee = cast(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(rPointee)) - rPointee = rPtr->getPointeeType().getCanonicalType(); - else - rPointee = QualType(); - - if (const PointerType *lPtr = dyn_cast(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(lhsType) && isa(rhsType)) { if (Type::tagTypesAreCompatible(lhsType, rhsType)) return rhsType; @@ -789,6 +786,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { if (dcl && isa(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(); } diff --git a/clang/AST/Type.cpp b/clang/AST/Type.cpp index b00de40cdb4d..1ceb6e110ada 100644 --- a/clang/AST/Type.cpp +++ b/clang/AST/Type.cpp @@ -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(lhs.getCanonicalType())->getPointeeType(); QualType rtype = cast(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"); } diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 98d2bc182106..5d25e01bb07e 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -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). diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index 7bed03575bfa..4c886fd429f8 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -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(lhsType.getCanonicalType())->getPointeeType(); - rPointee = cast(rhsType.getCanonicalType())->getPointeeType(); + lhptee = cast(lhsType.getCanonicalType())->getPointeeType(); + rhptee = cast(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(rPointee)) - rPointee = rPtr->getPointeeType().getCanonicalType(); - else - rPointee = QualType(); - - if (const PointerType *lPtr = dyn_cast(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(lhsType) && isa(rhsType)) { if (Type::tagTypesAreCompatible(lhsType, rhsType)) return rhsType; @@ -789,6 +786,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { if (dcl && isa(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(); }