aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-02 21:19:23 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-02 21:19:23 +0000
commit7dd900ed308506f9cf1cb72c70db1652f94cab37 (patch)
tree3dc75707934b1fab99a0a36e62e3d312c7ae1bfb /lib/Sema/SemaStmt.cpp
parentb135f0f2d893121ed2cc46d4d6c5bd5ab87d872f (diff)
In blocks, only pretend that enum constants have enum type if necessary.
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++.) Thus, when a block's return type is inferred from an enum constant, it is incompatible with expressions that return the enum type. In r158899, I told block returns to pretend that enum constants have enum type, like in C++. Doug Gregor pointed out that this can break existing code. Now, we don't check the types of return statements until the end of the block. This lets us go back and add implicit casts in blocks with mixed enum constants and enum-typed expressions. <rdar://problem/11662489> (again) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159591 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r--lib/Sema/SemaStmt.cpp65
1 files changed, 21 insertions, 44 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 999be9109d..62cd0d0d60 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2120,40 +2120,22 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// [expr.prim.lambda]p4 in C++11; block literals follow a superset of those
// rules which allows multiple return statements.
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
+ QualType FnRetType = CurCap->ReturnType;
+
+ // For blocks/lambdas with implicit return types, we check each return
+ // statement individually, and deduce the common return type when the block
+ // or lambda is completed.
if (CurCap->HasImplicitReturnType) {
- QualType ReturnT;
if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- if (!RetValExp->isTypeDependent()) {
- ReturnT = RetValExp->getType();
-
- // 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;
- }
+ if (!RetValExp->isTypeDependent())
+ FnRetType = RetValExp->getType();
+ else
+ FnRetType = CurCap->ReturnType = Context.DependentTy;
} else {
if (RetValExp) {
// C++11 [expr.lambda.prim]p4 bans inferring the result from an
@@ -2163,21 +2145,14 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
<< RetValExp->getSourceRange();
}
- ReturnT = Context.VoidTy;
+ FnRetType = Context.VoidTy;
}
- // We require the return types to strictly match here.
- if (!CurCap->ReturnType.isNull() &&
- !CurCap->ReturnType->isDependentType() &&
- !ReturnT->isDependentType() &&
- !Context.hasSameType(ReturnT, CurCap->ReturnType)) {
- Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << ReturnT << CurCap->ReturnType
- << (getCurLambda() != 0);
- return StmtError();
- }
- CurCap->ReturnType = ReturnT;
+
+ // Although we'll properly infer the type of the block once it's completed,
+ // make sure we provide a return type now for better error recovery.
+ if (CurCap->ReturnType.isNull())
+ CurCap->ReturnType = FnRetType;
}
- QualType FnRetType = CurCap->ReturnType;
assert(!FnRetType.isNull());
if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
@@ -2245,10 +2220,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
NRVOCandidate);
- // If we need to check for the named return value optimization, save the
- // return statement in our scope for later processing.
- if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
- !CurContext->isDependentContext())
+ // If we need to check for the named return value optimization,
+ // or if we need to infer the return type,
+ // save the return statement in our scope for later processing.
+ if (CurCap->HasImplicitReturnType ||
+ (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext()))
FunctionScopes.back()->Returns.push_back(Result);
return Owned(Result);