r296020 - Add context note to diagnostics that occur while declaring an implicit special member function.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 23 13:43:44 PST 2017
Author: rsmith
Date: Thu Feb 23 15:43:43 2017
New Revision: 296020
URL: http://llvm.org/viewvc/llvm-project?rev=296020&view=rev
Log:
Add context note to diagnostics that occur while declaring an implicit special member function.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
cfe/trunk/test/SemaCXX/implicit-member-functions.cpp
cfe/trunk/test/SemaCXX/virtual-base-used.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 23 15:43:43 2017
@@ -1624,7 +1624,14 @@ def err_covariant_return_type_class_type
"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<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb 23 15:43:43 2017
@@ -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;
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Feb 23 15:43:43 2017
@@ -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?
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Feb 23 15:43:43 2017
@@ -196,6 +196,7 @@ bool Sema::CodeSynthesisContext::isInsta
return true;
case DefaultTemplateArgumentChecking:
+ case DeclaringSpecialMember:
return false;
}
@@ -207,8 +208,7 @@ Sema::InstantiatingTemplate::Instantiati
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::Instantiati
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::Instantiati
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::
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::
// 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;
Modified: cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp (original)
+++ cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp Thu Feb 23 15:43:43 2017
@@ -35,13 +35,15 @@ struct E : D {};
// expected-error at -1 {{deleted function '~E' cannot override a non-deleted function}}
// expected-note at -2 {{destructor of 'E' is implicitly deleted because base class 'D' has an inaccessible destructor}}
// expected-error at -3 {{deleted function 'operator=' cannot override a non-deleted function}}
-// expected-note at -4 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
+// expected-note at -4 {{while declaring the implicit copy assignment operator for 'E'}}
+// expected-note at -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 at -1 {{deleted function '~G' cannot override a non-deleted function}}
-// expected-note at -2 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
+// expected-note at -2 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
// expected-error at -3 {{deleted function 'operator=' cannot override a non-deleted function}}
-// expected-note at -4 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
+// expected-note at -4 {{while declaring the implicit move assignment operator for 'G'}}
+// expected-note at -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 at -1 {{deleted function 'operator=' cannot override a non-deleted function}}
Modified: cfe/trunk/test/SemaCXX/implicit-member-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-member-functions.cpp?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/implicit-member-functions.cpp (original)
+++ cfe/trunk/test/SemaCXX/implicit-member-functions.cpp Thu Feb 23 15:43:43 2017
@@ -66,7 +66,8 @@ namespace Recursion {
A(const T &);
// expected-note at -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 at -1 {{candidate constructor (the implicit move }}
B(); // expected-note {{candidate constructor not viable}}
A a;
};
Modified: cfe/trunk/test/SemaCXX/virtual-base-used.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtual-base-used.cpp?rev=296020&r1=296019&r2=296020&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/virtual-base-used.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtual-base-used.cpp Thu Feb 23 15:43:43 2017
@@ -105,9 +105,10 @@ struct F : public E {
#endif
#else
// expected-error at -7 {{non-deleted function '~F' cannot override a deleted function}}
-// expected-note at -8 {{overridden virtual function is here}}
+// expected-note at -8 {{while declaring the implicit destructor for 'F'}}
+// expected-note at -9 {{overridden virtual function is here}}
#ifdef MSABI
-// expected-note at -10 {{default constructor of 'F' is implicitly deleted because base class 'E' has a deleted default constructor}}
+// expected-note at -11 {{default constructor of 'F' is implicitly deleted because base class 'E' has a deleted default constructor}}
#endif
#endif
};
More information about the cfe-commits
mailing list