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