aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Sema/SemaStmt.cpp28
1 files changed, 25 insertions, 3 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 8bf0b7326d..999be9109d 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2128,10 +2128,32 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
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 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
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);