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@-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}} 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@-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; }; 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@-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 }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits