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

llvm-svn: 303156
This commit is contained in:
Alex Lorenz 2017-05-16 10:23:58 +00:00
parent 390242d0e9
commit de69ff9b7c
3 changed files with 61 additions and 0 deletions

View File

@ -1074,6 +1074,10 @@ public:
/// correctly named definition after the renamed definition.
llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions;
/// Stack of types that correspond to the parameter entities that are
/// currently being copy-initialized. Can be empty.
llvm::SmallVector<QualType, 4> CurrentParameterCopyTypes;
void ReadMethodPool(Selector Sel);
void updateOutOfDateSelector(Selector Sel);

View File

@ -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;
}

View File

@ -302,3 +302,22 @@ namespace PR14073 {
struct S2 { union { union { int n; }; char c; }; S2() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
struct S3 { struct { int n; }; S3() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
}
namespace PR10758 {
struct A;
struct B {
B (A const &); // expected-note 2 {{candidate constructor not viable: no known conversion from 'const PR10758::B' to 'const PR10758::A &' for 1st argument}}
B (B &); // expected-note 2 {{candidate constructor not viable: 1st argument ('const PR10758::B') would lose const qualifier}}
};
struct A {
A (B); // expected-note 2 {{passing argument to parameter here}}
};
B f(B const &b) {
return b; // expected-error {{no matching constructor for initialization of 'PR10758::B'}}
}
A f2(const B &b) {
return b; // expected-error {{no matching constructor for initialization of 'PR10758::B'}}
}
}