diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-11-11 01:36:17 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-11-11 01:36:17 +0000 |
commit | 42b10572443e3f3f3c4a113f88ad4e9b504df900 (patch) | |
tree | b826b89beb307ed24b6ffedf840c5605ccabb3f4 /clang/lib/Sema/SemaDecl.cpp | |
parent | 754cd11d9019e62a4c6a0aee62159e707f6f51d9 (diff) | |
download | bcm5719-llvm-42b10572443e3f3f3c4a113f88ad4e9b504df900.tar.gz bcm5719-llvm-42b10572443e3f3f3c4a113f88ad4e9b504df900.zip |
N3922: direct-list-initialization of an auto-typed variable no longer deduces a
std::initializer_list<T> type. Instead, the list must contain a single element
and the type is deduced from that.
In Clang 3.7, we warned by default on all the cases that would change meaning
due to this change. In Clang 3.8, we will support only the new rules -- per
the request in N3922, this change is applied as a Defect Report against earlier
versions of the C++ standard.
This change is not entirely trivial, because for lambda init-captures we
previously did not track the difference between direct-list-initialization and
copy-list-initialization. The difference was not previously observable, because
the two forms of initialization always did the same thing (the elements of the
initializer list were always copy-initialized regardless of the initialization
style used for the init-capture).
llvm-svn: 252688
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. |