[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