[cfe-commits] r158899 - in /cfe/trunk: lib/Sema/SemaStmt.cpp test/SemaObjC/blocks.m
Douglas Gregor
dgregor at apple.com
Fri Jun 29 11:22:25 PDT 2012
On Jun 20, 2012, at 10:54 PM, Jordan Rose <jordan_rose at apple.com> wrote:
> Author: jrose
> Date: Thu Jun 21 00:54:55 2012
> New Revision: 158899
>
> URL: http://llvm.org/viewvc/llvm-project?rev=158899&view=rev
> Log:
> Pretend that enum constants have enum type when inferring a block return type.
>
> In C, enum constants have the type of the enum's underlying integer type,
> rather than the type of the enum. (This is not true in C++.) This leads to
> odd warnings when returning enum constants directly in blocks with inferred
> return types. The easiest way out of this is to pretend that, like C++, enum
> constants have enum type when being returned from a block.
>
> <rdar://problem/11662489>
While possibly convenient, this is a source-compatibility-breaking change to something that has been stable for *years*. I'd support doing this for enumerators of enumerations with a fixed underlying type, because that's a new extension in Objective-C.
- Doug
> Modified:
> cfe/trunk/lib/Sema/SemaStmt.cpp
> cfe/trunk/test/SemaObjC/blocks.m
>
> Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=158899&r1=158898&r2=158899&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jun 21 00:54:55 2012
> @@ -2128,10 +2128,32 @@
> return StmtError();
> RetValExp = Result.take();
>
> - if (!RetValExp->isTypeDependent())
> + if (!RetValExp->isTypeDependent()) {
> ReturnT = RetValExp->getType();
> - else
> +
> + // In C, enum constants have the type of their underlying integer type,
> + // not the enum. When inferring block return values, we should infer
> + // the enum type if an enum constant is used, unless the enum is
> + // anonymous (in which case there can be no variables of its type).
> + if (!getLangOpts().CPlusPlus) {
> + Expr *InsideExpr = RetValExp->IgnoreParenImpCasts();
> + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InsideExpr)) {
> + Decl *D = DRE->getDecl();
> + if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
> + EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
> + if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl()) {
> + ReturnT = Context.getTypeDeclType(Enum);
> + ExprResult Casted = ImpCastExprToType(RetValExp, ReturnT,
> + CK_IntegralCast);
> + assert(Casted.isUsable());
> + RetValExp = Casted.take();
> + }
> + }
> + }
> + }
> + } else {
> ReturnT = Context.DependentTy;
> + }
> } else {
> if (RetValExp) {
> // C++11 [expr.lambda.prim]p4 bans inferring the result from an
> @@ -2147,7 +2169,7 @@
> if (!CurCap->ReturnType.isNull() &&
> !CurCap->ReturnType->isDependentType() &&
> !ReturnT->isDependentType() &&
> - !Context.hasSameType(ReturnT, CurCap->ReturnType)) {
> + !Context.hasSameType(ReturnT, CurCap->ReturnType)) {
> Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
> << ReturnT << CurCap->ReturnType
> << (getCurLambda() != 0);
>
> Modified: cfe/trunk/test/SemaObjC/blocks.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/blocks.m?rev=158899&r1=158898&r2=158899&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaObjC/blocks.m (original)
> +++ cfe/trunk/test/SemaObjC/blocks.m Thu Jun 21 00:54:55 2012
> @@ -73,3 +73,130 @@
> NSLog(@"%@", myBlock);
> }
>
> +
> +// In C, enum constants have the type of the underlying integer type, not the
> +// enumeration they are part of. We pretend the constants have enum type when
> +// inferring block return types, so that they can be mixed-and-matched with
> +// other expressions of enum type.
> +enum CStyleEnum {
> + CSE_Value = 1
> +};
> +enum CStyleEnum getCSE();
> +typedef enum CStyleEnum (^cse_block_t)();
> +
> +void testCStyleEnumInference(bool arg) {
> + cse_block_t a;
> +
> + // No warnings here.
> + a = ^{ return CSE_Value; };
> + a = ^{ return getCSE(); };
> +
> + a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
> + return 1;
> + };
> +
> + // No warnings here.
> + a = ^{ if (arg) return CSE_Value; else return CSE_Value; };
> + a = ^{ if (arg) return getCSE(); else return getCSE(); };
> + a = ^{ if (arg) return CSE_Value; else return getCSE(); };
> + a = ^{ if (arg) return getCSE(); else return CSE_Value; };
> +
> + // Technically these two blocks should return 'int'.
> + // The first case is easy to handle -- just don't cast the enum constant
> + // to the enum type. However, the second guess would require going back
> + // and REMOVING the cast from the first return statement, which isn't really
> + // feasible (there may be more than one previous return statement with enum
> + // type). For symmetry, we just treat them the same way.
> + a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
> + if (arg)
> + return 1;
> + else
> + return CSE_Value; // expected-error {{return type 'enum CStyleEnum' must match previous return type 'int'}}
> + };
> +
> + a = ^{
> + if (arg)
> + return CSE_Value;
> + else
> + return 1; // expected-error {{return type 'int' must match previous return type 'enum CStyleEnum'}}
> + };
> +}
> +
> +
> +enum FixedTypeEnum : unsigned {
> + FTE_Value = 1U
> +};
> +enum FixedTypeEnum getFTE();
> +typedef enum FixedTypeEnum (^fte_block_t)();
> +
> +void testFixedTypeEnumInference(bool arg) {
> + fte_block_t a;
> +
> + // No warnings here.
> + a = ^{ return FTE_Value; };
> + a = ^{ return getFTE(); };
> +
> + // Since we fixed the underlying type of the enum, this is considered a
> + // compatible block type.
> + a = ^{
> + return 1U;
> + };
> +
> + // No warnings here.
> + a = ^{ if (arg) return FTE_Value; else return FTE_Value; };
> + a = ^{ if (arg) return getFTE(); else return getFTE(); };
> + a = ^{ if (arg) return FTE_Value; else return getFTE(); };
> + a = ^{ if (arg) return getFTE(); else return FTE_Value; };
> +
> + // Technically these two blocks should return 'unsigned'.
> + // The first case is easy to handle -- just don't cast the enum constant
> + // to the enum type. However, the second guess would require going back
> + // and REMOVING the cast from the first return statement, which isn't really
> + // feasible (there may be more than one previous return statement with enum
> + // type). For symmetry, we just treat them the same way.
> + a = ^{
> + if (arg)
> + return 1U;
> + else
> + return FTE_Value; // expected-error{{return type 'enum FixedTypeEnum' must match previous return type 'unsigned int'}}
> + };
> +
> + a = ^{
> + if (arg)
> + return FTE_Value;
> + else
> + return 1U; // expected-error{{return type 'unsigned int' must match previous return type 'enum FixedTypeEnum'}}
> + };
> +}
> +
> +
> +enum {
> + AnonymousValue = 1
> +};
> +
> +enum : short {
> + FixedAnonymousValue = 1
> +};
> +
> +typedef enum {
> + TDE_Value
> +} TypeDefEnum;
> +
> +typedef enum : short {
> + TDFTE_Value
> +} TypeDefFixedTypeEnum;
> +
> +
> +typedef int (^int_block_t)();
> +typedef short (^short_block_t)();
> +void testAnonymousEnumTypes() {
> + int_block_t IB;
> + IB = ^{ return AnonymousValue; };
> + IB = ^{ return TDE_Value; }; // expected-error {{incompatible block pointer types assigning to 'int_block_t' (aka 'int (^)()') from 'TypeDefEnum (^)(void)'}}
> + IB = ^{ return CSE_Value; }; // expected-error {{incompatible block pointer types assigning to 'int_block_t' (aka 'int (^)()') from 'enum CStyleEnum (^)(void)'}}
> +
> + short_block_t SB;
> + SB = ^{ return FixedAnonymousValue; };
> + // This is not an error anyway since the enum has a fixed underlying type.
> + SB = ^{ return TDFTE_Value; };
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list