diff options
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 197 |
1 files changed, 108 insertions, 89 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 92bbadd627d..ed86e854894 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9012,6 +9012,96 @@ namespace { } } +QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, + DeclarationName Name, QualType Type, + TypeSourceInfo *TSI, + SourceRange Range, bool DirectInit, + Expr *Init) { + bool IsInitCapture = !VDecl; + assert((!VDecl || !VDecl->isInitCapture()) && + "init captures are expected to be deduced prior to initialization"); + + ArrayRef<Expr *> DeduceInits = Init; + if (DirectInit) { + if (auto *PL = dyn_cast<ParenListExpr>(Init)) + DeduceInits = PL->exprs(); + else if (auto *IL = dyn_cast<InitListExpr>(Init)) + DeduceInits = IL->inits(); + } + + // Deduction only works if we have exactly one source expression. + if (DeduceInits.empty()) { + // It isn't possible to write this directly, but it is possible to + // end up in this situation with "auto x(some_pack...);" + Diag(Init->getLocStart(), IsInitCapture + ? diag::err_init_capture_no_expression + : diag::err_auto_var_init_no_expression) + << Name << Type << Range; + return QualType(); + } + + if (DeduceInits.size() > 1) { + Diag(DeduceInits[1]->getLocStart(), + IsInitCapture ? diag::err_init_capture_multiple_expressions + : diag::err_auto_var_init_multiple_expressions) + << Name << Type << Range; + return QualType(); + } + + Expr *DeduceInit = DeduceInits[0]; + if (DirectInit && isa<InitListExpr>(DeduceInit)) { + Diag(Init->getLocStart(), IsInitCapture + ? diag::err_init_capture_paren_braces + : diag::err_auto_var_init_paren_braces) + << isa<InitListExpr>(Init) << Name << Type << Range; + return QualType(); + } + + // Expressions default to 'id' when we're in a debugger. + bool DefaultedAnyToId = false; + if (getLangOpts().DebuggerCastResultToId && + Init->getType() == Context.UnknownAnyTy && !IsInitCapture) { + ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); + if (Result.isInvalid()) { + return QualType(); + } + Init = Result.get(); + DefaultedAnyToId = true; + } + + QualType DeducedType; + if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { + if (!IsInitCapture) + DiagnoseAutoDeductionFailure(VDecl, DeduceInit); + else if (isa<InitListExpr>(Init)) + Diag(Range.getBegin(), + diag::err_init_capture_deduction_failure_from_init_list) + << Name + << (DeduceInit->getType().isNull() ? TSI->getType() + : DeduceInit->getType()) + << DeduceInit->getSourceRange(); + else + Diag(Range.getBegin(), diag::err_init_capture_deduction_failure) + << Name << TSI->getType() + << (DeduceInit->getType().isNull() ? TSI->getType() + : DeduceInit->getType()) + << DeduceInit->getSourceRange(); + } + + // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using + // 'id' instead of a specific object type prevents most of our usual + // checks. + // We only want to warn outside of template instantiations, though: + // inside a template, the 'id' could have come from a parameter. + if (ActiveTemplateInstantiations.empty() && !DefaultedAnyToId && + !IsInitCapture && !DeducedType.isNull() && DeducedType->isObjCIdType()) { + SourceLocation Loc = TSI->getTypeLoc().getBeginLoc(); + Diag(Loc, diag::warn_auto_var_is_id) << Name << Range; + } + + return DeducedType; +} + /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -9039,79 +9129,27 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, RealDecl->setInvalidDecl(); return; } - ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { // Attempt typo correction early so that the type of the init expression can - // be deduced based on the chosen correction:if the original init contains a + // be deduced based on the chosen correction if the original init contains a // TypoExpr. ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); if (!Res.isUsable()) { RealDecl->setInvalidDecl(); return; } + Init = Res.get(); - if (Res.get() != Init) { - Init = Res.get(); - if (CXXDirectInit) - CXXDirectInit = dyn_cast<ParenListExpr>(Init); - } - - Expr *DeduceInit = Init; - // Initializer could be a C++ direct-initializer. Deduction only works if it - // contains exactly one expression. - if (CXXDirectInit) { - if (CXXDirectInit->getNumExprs() == 0) { - // It isn't possible to write this directly, but it is possible to - // end up in this situation with "auto x(some_pack...);" - Diag(CXXDirectInit->getLocStart(), - VDecl->isInitCapture() ? diag::err_init_capture_no_expression - : diag::err_auto_var_init_no_expression) - << VDecl->getDeclName() << VDecl->getType() - << VDecl->getSourceRange(); - RealDecl->setInvalidDecl(); - return; - } else if (CXXDirectInit->getNumExprs() > 1) { - Diag(CXXDirectInit->getExpr(1)->getLocStart(), - VDecl->isInitCapture() - ? diag::err_init_capture_multiple_expressions - : diag::err_auto_var_init_multiple_expressions) - << VDecl->getDeclName() << VDecl->getType() - << VDecl->getSourceRange(); - RealDecl->setInvalidDecl(); - return; - } else { - DeduceInit = CXXDirectInit->getExpr(0); - if (isa<InitListExpr>(DeduceInit)) - Diag(CXXDirectInit->getLocStart(), - diag::err_auto_var_init_paren_braces) - << VDecl->getDeclName() << VDecl->getType() - << VDecl->getSourceRange(); - } - } - - // Expressions default to 'id' when we're in a debugger. - bool DefaultedToAuto = false; - if (getLangOpts().DebuggerCastResultToId && - Init->getType() == Context.UnknownAnyTy) { - ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); - if (Result.isInvalid()) { - VDecl->setInvalidDecl(); - return; - } - Init = Result.get(); - DefaultedToAuto = true; - } - - QualType DeducedType; - if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == - DAR_Failed) - DiagnoseAutoDeductionFailure(VDecl, DeduceInit); + QualType DeducedType = deduceVarTypeFromInitializer( + VDecl, VDecl->getDeclName(), VDecl->getType(), + VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init); if (DeducedType.isNull()) { RealDecl->setInvalidDecl(); return; } + VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); @@ -9119,38 +9157,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); - // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using - // 'id' instead of a specific object type prevents most of our usual checks. - // We only want to warn outside of template instantiations, though: - // inside a template, the 'id' could have come from a parameter. - if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto && - DeducedType->isObjCIdType()) { - SourceLocation Loc = - VDecl->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); - Diag(Loc, diag::warn_auto_var_is_id) - << VDecl->getDeclName() << DeduceInit->getSourceRange(); - } - // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) { // We never need to merge the type, because we cannot form an incomplete // array of auto, nor deduce such a type. - MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/false); + MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false); } // Check the deduced type is valid for a variable declaration. CheckVariableDeclarationType(VDecl); if (VDecl->isInvalidDecl()) return; - - // If all looks well, warn if this is a case that will change meaning when - // we implement N3922. - if (DirectInit && !CXXDirectInit && isa<InitListExpr>(Init)) { - Diag(Init->getLocStart(), - diag::warn_auto_var_direct_list_init) - << FixItHint::CreateInsertion(Init->getLocStart(), "="); - } } // dllimport cannot be used on variable definitions. @@ -9262,17 +9280,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } // Perform the initialization. + ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); - InitializationKind Kind - = DirectInit ? - CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(), - Init->getLocStart(), - Init->getLocEnd()) - : InitializationKind::CreateDirectList( - VDecl->getLocation()) - : InitializationKind::CreateCopy(VDecl->getLocation(), - Init->getLocStart()); + InitializationKind Kind = + DirectInit + ? CXXDirectInit + ? InitializationKind::CreateDirect(VDecl->getLocation(), + Init->getLocStart(), + Init->getLocEnd()) + : InitializationKind::CreateDirectList(VDecl->getLocation()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + Init->getLocStart()); MultiExprArg Args = Init; if (CXXDirectInit) @@ -9336,7 +9355,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Init->getLocStart())) - getCurFunction()->markSafeWeakUse(Init); + getCurFunction()->markSafeWeakUse(Init); } // The initialization is usually a full-expression. |