diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-05-16 10:23:58 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-05-16 10:23:58 +0000 |
commit | af473b4213ef00e23a340ec013a827e4c8c96d5b (patch) | |
tree | e822938c06b3ef38c535e5657c8482dd9009aed2 /lib/Sema/SemaInit.cpp | |
parent | 8c199f23fb6405e08d4f888dfdd141a895ee5413 (diff) | |
download | clang-af473b4213ef00e23a340ec013a827e4c8c96d5b.tar.gz |
Fix PR 10758: Infinite recursion when dealing with copy-initialization
This commit fixes a bug that's tracked by PR 10758 and duplicates like PR 30343.
The bug causes clang to crash with a stack overflow while recursing infinitely
trying to perform copy-initialization on a type without a copy constructor but
with a constructor that accepts another type that can be constructed using the
original type.
The commit fixes this bug by detecting the recursive behavior and failing
correctly with an appropriate error message. It also tries to provide a
meaningful diagnostic note about the constructor which leads to this behavior.
rdar://28483944
Differential Revision: https://reviews.llvm.org/D25051
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303156 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 8d19b82c3f..32024cb335 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -8296,8 +8296,46 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, AllowExplicit); InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList); + // Prevent infinite recursion when performing parameter copy-initialization. + const bool ShouldTrackCopy = + Entity.isParameterKind() && Seq.isConstructorInitialization(); + if (ShouldTrackCopy) { + if (llvm::find(CurrentParameterCopyTypes, Entity.getType()) != + CurrentParameterCopyTypes.end()) { + Seq.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + OR_No_Viable_Function); + + // Try to give a meaningful diagnostic note for the problematic + // constructor. + const auto LastStep = Seq.step_end() - 1; + assert(LastStep->Kind == + InitializationSequence::SK_ConstructorInitialization); + const FunctionDecl *Function = LastStep->Function.Function; + auto Candidate = + llvm::find_if(Seq.getFailedCandidateSet(), + [Function](const OverloadCandidate &Candidate) -> bool { + return Candidate.Viable && + Candidate.Function == Function && + Candidate.Conversions.size() > 0; + }); + if (Candidate != Seq.getFailedCandidateSet().end() && + Function->getNumParams() > 0) { + Candidate->Viable = false; + Candidate->FailureKind = ovl_fail_bad_conversion; + Candidate->Conversions[0].setBad(BadConversionSequence::no_conversion, + InitE, + Function->getParamDecl(0)->getType()); + } + } + CurrentParameterCopyTypes.push_back(Entity.getType()); + } + ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE); + if (ShouldTrackCopy) + CurrentParameterCopyTypes.pop_back(); + return Result; } |