mirror of https://github.com/microsoft/clang.git
Add context note to diagnostics that occur while declaring an implicit special member function.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@296020 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
11e7407389
commit
a793abf092
|
@ -1624,7 +1624,14 @@ def err_covariant_return_type_class_type_more_qualified : Error<
|
|||
"return type of virtual function %0 is not covariant with the return type of "
|
||||
"the function it overrides (class type %1 is more qualified than class "
|
||||
"type %2">;
|
||||
|
||||
|
||||
// C++ implicit special member functions
|
||||
def note_in_declaration_of_implicit_special_member : Note<
|
||||
"while declaring the implicit "
|
||||
"%select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}1"
|
||||
" for %0">;
|
||||
|
||||
// C++ constructors
|
||||
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
|
||||
def err_invalid_qualified_constructor : Error<
|
||||
|
|
|
@ -6881,28 +6881,42 @@ public:
|
|||
|
||||
/// We are instantiating the exception specification for a function
|
||||
/// template which was deferred until it was needed.
|
||||
ExceptionSpecInstantiation
|
||||
ExceptionSpecInstantiation,
|
||||
|
||||
/// We are declaring an implicit special member function.
|
||||
DeclaringSpecialMember,
|
||||
} Kind;
|
||||
|
||||
/// \brief The point of instantiation within the source code.
|
||||
/// \brief Was the enclosing context a non-instantiation SFINAE context?
|
||||
bool SavedInNonInstantiationSFINAEContext;
|
||||
|
||||
/// \brief The point of instantiation or synthesis within the source code.
|
||||
SourceLocation PointOfInstantiation;
|
||||
|
||||
/// \brief The entity that is being synthesized.
|
||||
Decl *Entity;
|
||||
|
||||
/// \brief The template (or partial specialization) in which we are
|
||||
/// performing the instantiation, for substitutions of prior template
|
||||
/// arguments.
|
||||
NamedDecl *Template;
|
||||
|
||||
/// \brief The entity that is being instantiated.
|
||||
Decl *Entity;
|
||||
|
||||
/// \brief The list of template arguments we are substituting, if they
|
||||
/// are not part of the entity.
|
||||
const TemplateArgument *TemplateArgs;
|
||||
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
unsigned NumTemplateArgs;
|
||||
// FIXME: Wrap this union around more members, or perhaps store the
|
||||
// kind-specific members in the RAII object owning the context.
|
||||
union {
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// \brief The special member being declared or defined.
|
||||
CXXSpecialMember SpecialMember;
|
||||
};
|
||||
|
||||
ArrayRef<TemplateArgument> template_arguments() const {
|
||||
assert(Kind != DeclaringSpecialMember);
|
||||
return {TemplateArgs, NumTemplateArgs};
|
||||
}
|
||||
|
||||
|
@ -6916,7 +6930,7 @@ public:
|
|||
SourceRange InstantiationRange;
|
||||
|
||||
CodeSynthesisContext()
|
||||
: Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr),
|
||||
: Kind(TemplateInstantiation), Entity(nullptr), Template(nullptr),
|
||||
TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {}
|
||||
|
||||
/// \brief Determines whether this template is an actual instantiation
|
||||
|
@ -7134,7 +7148,6 @@ public:
|
|||
Sema &SemaRef;
|
||||
bool Invalid;
|
||||
bool AlreadyInstantiating;
|
||||
bool SavedInNonInstantiationSFINAEContext;
|
||||
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
|
||||
SourceRange InstantiationRange);
|
||||
|
||||
|
@ -7151,6 +7164,9 @@ public:
|
|||
operator=(const InstantiatingTemplate&) = delete;
|
||||
};
|
||||
|
||||
void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
|
||||
void popCodeSynthesisContext();
|
||||
|
||||
/// Determine whether we are currently performing template instantiation.
|
||||
bool inTemplateInstantiation() const {
|
||||
return CodeSynthesisContexts.size() > NonInstantiationEntries;
|
||||
|
|
|
@ -10164,19 +10164,34 @@ struct DeclaringSpecialMember {
|
|||
bool WasAlreadyBeingDeclared;
|
||||
|
||||
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
|
||||
: S(S), D(RD, CSM), SavedContext(S, RD) {
|
||||
: S(S), D(RD, CSM), SavedContext(S, RD) {
|
||||
WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
|
||||
if (WasAlreadyBeingDeclared)
|
||||
// This almost never happens, but if it does, ensure that our cache
|
||||
// doesn't contain a stale result.
|
||||
S.SpecialMemberCache.clear();
|
||||
|
||||
// FIXME: Register a note to be produced if we encounter an error while
|
||||
// declaring the special member.
|
||||
else {
|
||||
// Register a note to be produced if we encounter an error while
|
||||
// declaring the special member.
|
||||
Sema::CodeSynthesisContext Ctx;
|
||||
Ctx.Kind = Sema::CodeSynthesisContext::DeclaringSpecialMember;
|
||||
// FIXME: We don't have a location to use here. Using the class's
|
||||
// location maintains the fiction that we declare all special members
|
||||
// with the class, but (1) it's not clear that lying about that helps our
|
||||
// users understand what's going on, and (2) there may be outer contexts
|
||||
// on the stack (some of which are relevant) and printing them exposes
|
||||
// our lies.
|
||||
Ctx.PointOfInstantiation = RD->getLocation();
|
||||
Ctx.Entity = RD;
|
||||
Ctx.SpecialMember = CSM;
|
||||
S.pushCodeSynthesisContext(Ctx);
|
||||
}
|
||||
}
|
||||
~DeclaringSpecialMember() {
|
||||
if (!WasAlreadyBeingDeclared)
|
||||
if (!WasAlreadyBeingDeclared) {
|
||||
S.SpecialMembersBeingDeclared.erase(D);
|
||||
S.popCodeSynthesisContext();
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Are we already trying to declare this special member?
|
||||
|
|
|
@ -196,6 +196,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
|
|||
return true;
|
||||
|
||||
case DefaultTemplateArgumentChecking:
|
||||
case DeclaringSpecialMember:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -207,8 +208,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
|
|||
SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
|
||||
Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
sema::TemplateDeductionInfo *DeductionInfo)
|
||||
: SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
|
||||
SemaRef.InNonInstantiationSFINAEContext) {
|
||||
: SemaRef(SemaRef) {
|
||||
// Don't allow further instantiation if a fatal error and an uncompilable
|
||||
// error have occurred. Any diagnostics we might have raised will not be
|
||||
// visible, and we do not need to construct a correct AST.
|
||||
|
@ -228,14 +228,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
|
|||
Inst.NumTemplateArgs = TemplateArgs.size();
|
||||
Inst.DeductionInfo = DeductionInfo;
|
||||
Inst.InstantiationRange = InstantiationRange;
|
||||
SemaRef.pushCodeSynthesisContext(Inst);
|
||||
|
||||
AlreadyInstantiating =
|
||||
!SemaRef.InstantiatingSpecializations
|
||||
.insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))
|
||||
.second;
|
||||
SemaRef.InNonInstantiationSFINAEContext = false;
|
||||
SemaRef.CodeSynthesisContexts.push_back(Inst);
|
||||
if (!Inst.isInstantiationRecord())
|
||||
++SemaRef.NonInstantiationEntries;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,38 +346,55 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
|
|||
PointOfInstantiation, InstantiationRange, Param, Template,
|
||||
TemplateArgs) {}
|
||||
|
||||
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
|
||||
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
|
||||
InNonInstantiationSFINAEContext = false;
|
||||
|
||||
CodeSynthesisContexts.push_back(Ctx);
|
||||
|
||||
if (!Ctx.isInstantiationRecord())
|
||||
++NonInstantiationEntries;
|
||||
}
|
||||
|
||||
void Sema::popCodeSynthesisContext() {
|
||||
auto &Active = CodeSynthesisContexts.back();
|
||||
if (!Active.isInstantiationRecord()) {
|
||||
assert(NonInstantiationEntries > 0);
|
||||
--NonInstantiationEntries;
|
||||
}
|
||||
|
||||
InNonInstantiationSFINAEContext = Active.SavedInNonInstantiationSFINAEContext;
|
||||
|
||||
// Name lookup no longer looks in this template's defining module.
|
||||
assert(CodeSynthesisContexts.size() >=
|
||||
CodeSynthesisContextLookupModules.size() &&
|
||||
"forgot to remove a lookup module for a template instantiation");
|
||||
if (CodeSynthesisContexts.size() ==
|
||||
CodeSynthesisContextLookupModules.size()) {
|
||||
if (Module *M = CodeSynthesisContextLookupModules.back())
|
||||
LookupModulesCache.erase(M);
|
||||
CodeSynthesisContextLookupModules.pop_back();
|
||||
}
|
||||
|
||||
// If we've left the code synthesis context for the current context stack,
|
||||
// stop remembering that we've emitted that stack.
|
||||
if (CodeSynthesisContexts.size() ==
|
||||
LastEmittedCodeSynthesisContextDepth)
|
||||
LastEmittedCodeSynthesisContextDepth = 0;
|
||||
|
||||
CodeSynthesisContexts.pop_back();
|
||||
}
|
||||
|
||||
void Sema::InstantiatingTemplate::Clear() {
|
||||
if (!Invalid) {
|
||||
auto &Active = SemaRef.CodeSynthesisContexts.back();
|
||||
if (!Active.isInstantiationRecord()) {
|
||||
assert(SemaRef.NonInstantiationEntries > 0);
|
||||
--SemaRef.NonInstantiationEntries;
|
||||
}
|
||||
SemaRef.InNonInstantiationSFINAEContext
|
||||
= SavedInNonInstantiationSFINAEContext;
|
||||
|
||||
// Name lookup no longer looks in this template's defining module.
|
||||
assert(SemaRef.CodeSynthesisContexts.size() >=
|
||||
SemaRef.CodeSynthesisContextLookupModules.size() &&
|
||||
"forgot to remove a lookup module for a template instantiation");
|
||||
if (SemaRef.CodeSynthesisContexts.size() ==
|
||||
SemaRef.CodeSynthesisContextLookupModules.size()) {
|
||||
if (Module *M = SemaRef.CodeSynthesisContextLookupModules.back())
|
||||
SemaRef.LookupModulesCache.erase(M);
|
||||
SemaRef.CodeSynthesisContextLookupModules.pop_back();
|
||||
}
|
||||
|
||||
// If we've left the code synthesis context for the current context stack,
|
||||
// stop remembering that we've emitted that stack.
|
||||
if (SemaRef.CodeSynthesisContexts.size() ==
|
||||
SemaRef.LastEmittedCodeSynthesisContextDepth)
|
||||
SemaRef.LastEmittedCodeSynthesisContextDepth = 0;
|
||||
|
||||
if (!AlreadyInstantiating)
|
||||
if (!AlreadyInstantiating) {
|
||||
auto &Active = SemaRef.CodeSynthesisContexts.back();
|
||||
SemaRef.InstantiatingSpecializations.erase(
|
||||
std::make_pair(Active.Entity, Active.Kind));
|
||||
}
|
||||
|
||||
SemaRef.popCodeSynthesisContext();
|
||||
|
||||
SemaRef.CodeSynthesisContexts.pop_back();
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
|
@ -603,6 +618,12 @@ void Sema::PrintInstantiationStack() {
|
|||
<< cast<FunctionDecl>(Active->Entity)
|
||||
<< Active->InstantiationRange;
|
||||
break;
|
||||
|
||||
case CodeSynthesisContext::DeclaringSpecialMember:
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_in_declaration_of_implicit_special_member)
|
||||
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -617,7 +638,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
|
|||
Active != ActiveEnd;
|
||||
++Active)
|
||||
{
|
||||
switch(Active->Kind) {
|
||||
switch (Active->Kind) {
|
||||
case CodeSynthesisContext::TemplateInstantiation:
|
||||
// An instantiation of an alias template may or may not be a SFINAE
|
||||
// context, depending on what else is on the stack.
|
||||
|
@ -643,7 +664,17 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
|
|||
// or deduced template arguments, so SFINAE applies.
|
||||
assert(Active->DeductionInfo && "Missing deduction info pointer");
|
||||
return Active->DeductionInfo;
|
||||
|
||||
case CodeSynthesisContext::DeclaringSpecialMember:
|
||||
// This happens in a context unrelated to template instantiation, so
|
||||
// there is no SFINAE.
|
||||
return None;
|
||||
}
|
||||
|
||||
// The inner context was transparent for SFINAE. If it occurred within a
|
||||
// non-instantiation SFINAE context, then SFINAE applies.
|
||||
if (Active->SavedInNonInstantiationSFINAEContext)
|
||||
return Optional<TemplateDeductionInfo *>(nullptr);
|
||||
}
|
||||
|
||||
return None;
|
||||
|
|
|
@ -35,13 +35,15 @@ struct E : D {};
|
|||
// expected-error@-1 {{deleted function '~E' cannot override a non-deleted function}}
|
||||
// expected-note@-2 {{destructor of 'E' is implicitly deleted because base class 'D' has an inaccessible destructor}}
|
||||
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
|
||||
// expected-note@-4 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
|
||||
// expected-note@-4 {{while declaring the implicit copy assignment operator for 'E'}}
|
||||
// expected-note@-5 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
|
||||
struct F : D {};
|
||||
struct G : D {};
|
||||
// expected-error@-1 {{deleted function '~G' cannot override a non-deleted function}}
|
||||
// expected-note@-2 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
|
||||
// expected-note@-2 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
|
||||
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
|
||||
// expected-note@-4 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
|
||||
// expected-note@-4 {{while declaring the implicit move assignment operator for 'G'}}
|
||||
// expected-note@-5 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
|
||||
struct H : D {
|
||||
H &operator=(H&&) = default;
|
||||
// expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}
|
||||
|
|
|
@ -66,7 +66,8 @@ namespace Recursion {
|
|||
A(const T &);
|
||||
// expected-note@-1 {{in instantiation of default argument}}
|
||||
};
|
||||
struct B { // expected-note {{candidate constructor (the implicit move }}
|
||||
struct B { // expected-note {{while declaring the implicit copy constructor for 'B'}}
|
||||
// expected-note@-1 {{candidate constructor (the implicit move }}
|
||||
B(); // expected-note {{candidate constructor not viable}}
|
||||
A a;
|
||||
};
|
||||
|
|
|
@ -105,9 +105,10 @@ struct F : public E {
|
|||
#endif
|
||||
#else
|
||||
// expected-error@-7 {{non-deleted function '~F' cannot override a deleted function}}
|
||||
// expected-note@-8 {{overridden virtual function is here}}
|
||||
// expected-note@-8 {{while declaring the implicit destructor for 'F'}}
|
||||
// expected-note@-9 {{overridden virtual function is here}}
|
||||
#ifdef MSABI
|
||||
// expected-note@-10 {{default constructor of 'F' is implicitly deleted because base class 'E' has a deleted default constructor}}
|
||||
// expected-note@-11 {{default constructor of 'F' is implicitly deleted because base class 'E' has a deleted default constructor}}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue