[cfe-commits] r55767 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/Basic/DiagnosticKinds.def lib/AST/ASTContext.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp
Eli Friedman
eli.friedman at gmail.com
Thu Sep 4 12:14:13 PDT 2008
On Thu, Sep 4, 2008 at 8:10 AM, Steve Naroff <snaroff at apple.com> wrote:
> +/// typesAreBlockCompatible - This routine is called when comparing two
> +/// closure types. Types must be strictly compatible here.
> +bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
> + if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
> + return false;
> +
> + QualType lcanon = getCanonicalType(lhs);
> + QualType rcanon = getCanonicalType(rhs);
You should be checking qualifiers on the canonical types; the
comparson can get messed up for arrays otherwise. Although, see
below.
> + // If two types are identical, they are are compatible
> + if (lcanon == rcanon)
> + return true;
> + if (isa<FunctionType>(lcanon) && isa<FunctionType>(rcanon)) {
> + const FunctionType *lbase = cast<FunctionType>(lcanon);
> + const FunctionType *rbase = cast<FunctionType>(rcanon);
> +
> + // First check the return types.
> + if (!typesAreBlockCompatible(lbase->getResultType(),rbase->getResultType()))
> + return false;
> +
> + // Return types matched, now check the argument types.
> + const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
> + const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
> +
> + if (lproto && rproto) { // two C99 style function prototypes
> + unsigned lproto_nargs = lproto->getNumArgs();
> + unsigned rproto_nargs = rproto->getNumArgs();
> +
> + if (lproto_nargs != rproto_nargs)
> + return false;
> +
> + if (lproto->isVariadic() || rproto->isVariadic())
> + return false;
> +
> + // The use of ellipsis agree...now check the argument types.
> + for (unsigned i = 0; i < lproto_nargs; i++)
> + if (!typesAreBlockCompatible(lproto->getArgType(i),
> + rproto->getArgType(i)))
> + return false;
> + return true;
> + }
> + return (!lproto && !rproto); // two K&R style function decls match.
> + }
> + return false;
> +}
It looks like you could delete all of the stuff after the "if (lcanon
== rcanon) return true;" without affecting how the code works, unless
I'm mistaken... for two types have identical return types and argument
lists, they'd have to be identical anyways.
You need to modify ASTContext::mergeTypes to handle block pointer
types; otherwise, I think it'll explode with an assertion. Adding a
"case Type::BlockPointer: return false;" should be sufficient, unless
I'm misreading typesAreBlockCompatible.
And at that point, you can just replace all the calls to
typesAreBlockCompatible with calls to typesAreCompatible.
Potentially useful test (should print a warning about comparing
incompatible pointers): int a() {void (^b)(void),void(^c)(int); return
&b == &c;}
> + /// BlockVoidPointer - The assignment is between a closure pointer and
> + /// void*, we accept for now.
I don't see any good reason to accept this; it'll just destroy the
block pointer.
> + // For blocks we enforce that qualifiers are identical.
> + if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
> + ConvTy = CompatiblePointerDiscardsQualifiers;
I thought it was supposed to be illegal to qualify block types?
(Although, actually, I recall making a comment about an earlier patch
rejecting qualifiers on block pointer types... I don't think that ever
got fixed.)
> /// CheckAssignmentConstraints (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:
> @@ -1500,6 +1528,25 @@
>
> if (isa<PointerType>(rhsType))
> return CheckPointerTypesForAssignment(lhsType, rhsType);
> +
> + if (const BlockPointerType *BPT = rhsType->getAsBlockPointerType())
> + if (BPT->getPointeeType()->isVoidType())
> + return BlockVoidPointer;
> +
> + return Incompatible;
> + }
> +
> + if (isa<BlockPointerType>(lhsType)) {
> + if (rhsType->isIntegerType())
> + return IntToPointer;
IntToBlockPointer?
> + if (isa<BlockPointerType>(lhsType) &&
> + rhsType->getAsPointerType()->getPointeeType()->isVoidType())
Isn't this an impossible condition, considering the location in the function?
> return Incompatible;
> }
>
> @@ -1532,6 +1583,11 @@
> ImpCastExprToType(rExpr, lhsType);
> return Compatible;
> }
> +
> + // We don't allow conversion of non-null-pointer constants to integers.
> + if (lhsType->isBlockPointerType() && rExpr->getType()->isIntegerType())
> + return IntToBlockPointer;
This shouldn't be necessary; you already handle this case in
CheckAssignmentConstraints.
> // This check seems unnatural, however it is necessary to ensure the proper
> // conversion of functions/arrays. If the conversion were done for all
> // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
> @@ -1849,6 +1905,21 @@
> ImpCastExprToType(rex, lType); // promote the pointer to pointer
> return Context.IntTy;
> }
> + // Handle block pointer types.
> + if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
> + QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
> + QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
> +
> + if (!LHSIsNull && !RHSIsNull &&
> + !Context.typesAreBlockCompatible(lpointee, rpointee)) {
> + Diag(loc, diag::err_typecheck_comparison_of_distinct_blocks,
> + lType.getAsString(), rType.getAsString(),
> + lex->getSourceRange(), rex->getSourceRange());
> + }
> + ImpCastExprToType(rex, lType); // promote the pointer to pointer
> + return Context.IntTy;
> + }
Just to double-check, the comparison is roughly equivalent to memcmp
for block pointers?
The code as-is won't work correctly for cases like "int
a(int(^b)(void)){return b == (void*)0}".
Some code I spotted while reviewing, not sure when it was committed:
// Handle block pointers.
if (lType->isBlockPointerType() && rType->isIntegerType()) {
if (!RHSIsNull)
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
lType.getAsString(), rType.getAsString(),
lex->getSourceRange(), rex->getSourceRange());
ImpCastExprToType(rex, lType); // promote the integer to pointer
return Context.IntTy;
}
if (lType->isIntegerType() && rType->isBlockPointerType()) {
if (!LHSIsNull)
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
lType.getAsString(), rType.getAsString(),
lex->getSourceRange(), rex->getSourceRange());
ImpCastExprToType(lex, rType); // promote the integer to pointer
return Context.IntTy;
}
This should be merged with the checks above it.
-Eli
More information about the cfe-commits
mailing list