[clang] 55b6f68 - Revert "Fix rejects-valid when referencing an implicit operator== from within a"

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 17 16:05:40 PDT 2020


Author: Richard Smith
Date: 2020-06-17T16:05:26-07:00
New Revision: 55b6f68f4b254bd1506ff844fa511b6658607992

URL: https://github.com/llvm/llvm-project/commit/55b6f68f4b254bd1506ff844fa511b6658607992
DIFF: https://github.com/llvm/llvm-project/commit/55b6f68f4b254bd1506ff844fa511b6658607992.diff

LOG: Revert "Fix rejects-valid when referencing an implicit operator== from within a"

This change may have caused some self-host failures. Reverting while
investigating.

This reverts commit c7fbe2191b8b9cd64570ed3906d1bed1dd5fff8e.

Added: 
    

Modified: 
    clang/include/clang/AST/DeclBase.h
    clang/include/clang/Sema/Template.h
    clang/lib/AST/DeclBase.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/PCH/cxx2a-defaulted-comparison.cpp

Removed: 
    clang/test/SemaTemplate/defaulted.cpp


################################################################################
diff  --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 5e00be35d8ce..ba84f27617f5 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -66,7 +66,6 @@ class SourceManager;
 class Stmt;
 class StoredDeclsMap;
 class TemplateDecl;
-class TemplateParameterList;
 class TranslationUnitDecl;
 class UsingDirectiveDecl;
 
@@ -863,10 +862,6 @@ class alignas(8) Decl {
   // within the scope of a template parameter).
   bool isTemplated() const;
 
-  /// Determine the number of levels of template parameter surrounding this
-  /// declaration.
-  unsigned getTemplateDepth() const;
-
   /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
   /// scoped decl is defined outside the current function or method.  This is
   /// roughly global variables and functions, but also handles enums (which
@@ -1043,16 +1038,8 @@ class alignas(8) Decl {
 
   /// If this is a declaration that describes some template, this
   /// method returns that template declaration.
-  ///
-  /// Note that this returns nullptr for partial specializations, because they
-  /// are not modeled as TemplateDecls. Use getDescribedTemplateParams to handle
-  /// those cases.
   TemplateDecl *getDescribedTemplate() const;
 
-  /// If this is a declaration that describes some template or partial
-  /// specialization, this returns the corresponding template parameter list.
-  const TemplateParameterList *getDescribedTemplateParams() const;
-
   /// Returns the function itself, or the templated function if this is a
   /// function template.
   FunctionDecl *getAsFunction() LLVM_READONLY;

diff  --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index d05c3a55f89c..8166b6cf9b6f 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -95,10 +95,6 @@ class VarDecl;
       return TemplateArgumentLists.size();
     }
 
-    unsigned getNumRetainedOuterLevels() const {
-      return NumRetainedOuterLevels;
-    }
-
     /// Determine how many of the \p OldDepth outermost template parameter
     /// lists would be removed by substituting these arguments.
     unsigned getNewDepth(unsigned OldDepth) const {
@@ -163,9 +159,6 @@ class VarDecl;
     void addOuterRetainedLevel() {
       ++NumRetainedOuterLevels;
     }
-    void addOuterRetainedLevels(unsigned Num) {
-      NumRetainedOuterLevels += Num;
-    }
 
     /// Retrieve the innermost template argument list.
     const ArgList &getInnermost() const {

diff  --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index a9cd7918da9b..2aab53f4fa90 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -240,16 +240,6 @@ TemplateDecl *Decl::getDescribedTemplate() const {
   return nullptr;
 }
 
-const TemplateParameterList *Decl::getDescribedTemplateParams() const {
-  if (auto *TD = getDescribedTemplate())
-    return TD->getTemplateParameters();
-  if (auto *CTPSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(this))
-    return CTPSD->getTemplateParameters();
-  if (auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(this))
-    return VTPSD->getTemplateParameters();
-  return nullptr;
-}
-
 bool Decl::isTemplated() const {
   // A declaration is dependent if it is a template or a template pattern, or
   // is within (lexcially for a friend, semantically otherwise) a dependent
@@ -258,29 +248,7 @@ bool Decl::isTemplated() const {
   if (auto *AsDC = dyn_cast<DeclContext>(this))
     return AsDC->isDependentContext();
   auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
-  return DC->isDependentContext() || isTemplateDecl() ||
-         getDescribedTemplateParams();
-}
-
-unsigned Decl::getTemplateDepth() const {
-  if (auto *DC = dyn_cast<DeclContext>(this))
-    if (DC->isFileContext())
-      return 0;
-
-  if (auto *TPL = getDescribedTemplateParams())
-    return TPL->getDepth() + 1;
-
-  // If this is a dependent lambda, there might be an enclosing variable
-  // template. In this case, the next step is not the parent DeclContext (or
-  // even a DeclContext at all).
-  auto *RD = dyn_cast<CXXRecordDecl>(this);
-  if (RD && RD->isDependentLambda())
-    if (Decl *Context = RD->getLambdaContextDecl())
-      return Context->getTemplateDepth();
-
-  const DeclContext *DC =
-      getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
-  return cast<Decl>(DC)->getTemplateDepth();
+  return DC->isDependentContext() || isTemplateDecl() || getDescribedTemplate();
 }
 
 const DeclContext *Decl::getParentFunctionOrMethod() const {

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f1da788b1209..80469e3bedbe 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -17170,10 +17170,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
           I.setAccess((*I)->getAccess());
       }
 
-      // Add any implicitly-declared members to this class.
-      AddImplicitlyDeclaredMembersToClass(CXXRecord);
-
       if (!CXXRecord->isDependentType()) {
+        // Add any implicitly-declared members to this class.
+        AddImplicitlyDeclaredMembersToClass(CXXRecord);
+
         if (!CXXRecord->isInvalidDecl()) {
           // If we have virtual base classes, we may end up finding multiple
           // final overriders for a given virtual function. Check for this

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e38ea6d2bc08..a2b669c99125 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9839,95 +9839,86 @@ static void findImplicitlyDeclaredEqualityComparisons(
 /// [special]p1).  This routine can only be executed just before the
 /// definition of the class is complete.
 void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
-  // Don't add implicit special members to templated classes.
-  // FIXME: This means unqualified lookups for 'operator=' within a class
-  // template don't work properly.
-  if (!ClassDecl->isDependentType()) {
-    if (ClassDecl->needsImplicitDefaultConstructor()) {
-      ++getASTContext().NumImplicitDefaultConstructors;
+  if (ClassDecl->needsImplicitDefaultConstructor()) {
+    ++getASTContext().NumImplicitDefaultConstructors;
 
-      if (ClassDecl->hasInheritedConstructor())
-        DeclareImplicitDefaultConstructor(ClassDecl);
-    }
+    if (ClassDecl->hasInheritedConstructor())
+      DeclareImplicitDefaultConstructor(ClassDecl);
+  }
 
-    if (ClassDecl->needsImplicitCopyConstructor()) {
-      ++getASTContext().NumImplicitCopyConstructors;
+  if (ClassDecl->needsImplicitCopyConstructor()) {
+    ++getASTContext().NumImplicitCopyConstructors;
 
-      // If the properties or semantics of the copy constructor couldn't be
-      // determined while the class was being declared, force a declaration
-      // of it now.
-      if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
-          ClassDecl->hasInheritedConstructor())
-        DeclareImplicitCopyConstructor(ClassDecl);
-      // For the MS ABI we need to know whether the copy ctor is deleted. A
-      // prerequisite for deleting the implicit copy ctor is that the class has
-      // a move ctor or move assignment that is either user-declared or whose
-      // semantics are inherited from a subobject. FIXME: We should provide a
-      // more direct way for CodeGen to ask whether the constructor was deleted.
-      else if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
-               (ClassDecl->hasUserDeclaredMoveConstructor() ||
-                ClassDecl->needsOverloadResolutionForMoveConstructor() ||
-                ClassDecl->hasUserDeclaredMoveAssignment() ||
-                ClassDecl->needsOverloadResolutionForMoveAssignment()))
-        DeclareImplicitCopyConstructor(ClassDecl);
-    }
+    // If the properties or semantics of the copy constructor couldn't be
+    // determined while the class was being declared, force a declaration
+    // of it now.
+    if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
+        ClassDecl->hasInheritedConstructor())
+      DeclareImplicitCopyConstructor(ClassDecl);
+    // For the MS ABI we need to know whether the copy ctor is deleted. A
+    // prerequisite for deleting the implicit copy ctor is that the class has a
+    // move ctor or move assignment that is either user-declared or whose
+    // semantics are inherited from a subobject. FIXME: We should provide a more
+    // direct way for CodeGen to ask whether the constructor was deleted.
+    else if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+             (ClassDecl->hasUserDeclaredMoveConstructor() ||
+              ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+              ClassDecl->hasUserDeclaredMoveAssignment() ||
+              ClassDecl->needsOverloadResolutionForMoveAssignment()))
+      DeclareImplicitCopyConstructor(ClassDecl);
+  }
 
-    if (getLangOpts().CPlusPlus11 &&
-        ClassDecl->needsImplicitMoveConstructor()) {
-      ++getASTContext().NumImplicitMoveConstructors;
+  if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
+    ++getASTContext().NumImplicitMoveConstructors;
 
-      if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
-          ClassDecl->hasInheritedConstructor())
-        DeclareImplicitMoveConstructor(ClassDecl);
-    }
+    if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+        ClassDecl->hasInheritedConstructor())
+      DeclareImplicitMoveConstructor(ClassDecl);
+  }
 
-    if (ClassDecl->needsImplicitCopyAssignment()) {
-      ++getASTContext().NumImplicitCopyAssignmentOperators;
+  if (ClassDecl->needsImplicitCopyAssignment()) {
+    ++getASTContext().NumImplicitCopyAssignmentOperators;
 
-      // If we have a dynamic class, then the copy assignment operator may be
-      // virtual, so we have to declare it immediately. This ensures that, e.g.,
-      // it shows up in the right place in the vtable and that we diagnose
-      // problems with the implicit exception specification.
-      if (ClassDecl->isDynamicClass() ||
-          ClassDecl->needsOverloadResolutionForCopyAssignment() ||
-          ClassDecl->hasInheritedAssignment())
-        DeclareImplicitCopyAssignment(ClassDecl);
-    }
+    // If we have a dynamic class, then the copy assignment operator may be
+    // virtual, so we have to declare it immediately. This ensures that, e.g.,
+    // it shows up in the right place in the vtable and that we diagnose
+    // problems with the implicit exception specification.
+    if (ClassDecl->isDynamicClass() ||
+        ClassDecl->needsOverloadResolutionForCopyAssignment() ||
+        ClassDecl->hasInheritedAssignment())
+      DeclareImplicitCopyAssignment(ClassDecl);
+  }
 
-    if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
-      ++getASTContext().NumImplicitMoveAssignmentOperators;
+  if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
+    ++getASTContext().NumImplicitMoveAssignmentOperators;
 
-      // Likewise for the move assignment operator.
-      if (ClassDecl->isDynamicClass() ||
-          ClassDecl->needsOverloadResolutionForMoveAssignment() ||
-          ClassDecl->hasInheritedAssignment())
-        DeclareImplicitMoveAssignment(ClassDecl);
-    }
+    // Likewise for the move assignment operator.
+    if (ClassDecl->isDynamicClass() ||
+        ClassDecl->needsOverloadResolutionForMoveAssignment() ||
+        ClassDecl->hasInheritedAssignment())
+      DeclareImplicitMoveAssignment(ClassDecl);
+  }
 
-    if (ClassDecl->needsImplicitDestructor()) {
-      ++getASTContext().NumImplicitDestructors;
+  if (ClassDecl->needsImplicitDestructor()) {
+    ++getASTContext().NumImplicitDestructors;
 
-      // If we have a dynamic class, then the destructor may be virtual, so we
-      // have to declare the destructor immediately. This ensures that, e.g., it
-      // shows up in the right place in the vtable and that we diagnose problems
-      // with the implicit exception specification.
-      if (ClassDecl->isDynamicClass() ||
-          ClassDecl->needsOverloadResolutionForDestructor())
-        DeclareImplicitDestructor(ClassDecl);
-    }
+    // If we have a dynamic class, then the destructor may be virtual, so we
+    // have to declare the destructor immediately. This ensures that, e.g., it
+    // shows up in the right place in the vtable and that we diagnose problems
+    // with the implicit exception specification.
+    if (ClassDecl->isDynamicClass() ||
+        ClassDecl->needsOverloadResolutionForDestructor())
+      DeclareImplicitDestructor(ClassDecl);
   }
 
   // C++2a [class.compare.default]p3:
   //   If the member-specification does not explicitly declare any member or
   //   friend named operator==, an == operator function is declared implicitly
-  //   for each defaulted three-way comparison operator function defined in
-  //   the member-specification
+  //   for each defaulted three-way comparison operator function defined in the
+  //   member-specification
   // FIXME: Consider doing this lazily.
-  // We do this during the initial parse for a class template, not during
-  // instantiation, so that we can handle unqualified lookups for 'operator=='
-  // when parsing the template.
-  if (getLangOpts().CPlusPlus20 && !inTemplateInstantiation()) {
-    llvm::SmallVector<FunctionDecl *, 4> DefaultedSpaceships;
+  if (getLangOpts().CPlusPlus20) {
+    llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships;
     findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl,
                                               DefaultedSpaceships);
     for (auto *FD : DefaultedSpaceships)

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ee91c51e2046..7d0777cce6ae 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3719,7 +3719,6 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
   //   access and function-definition and in the same class scope as the
   //   three-way comparison operator function
   MultiLevelTemplateArgumentList NoTemplateArgs;
-  NoTemplateArgs.addOuterRetainedLevels(RD->getTemplateDepth());
   TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs);
   Decl *R;
   if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
@@ -5606,20 +5605,6 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
   } else return DC;
 }
 
-/// Determine whether the given context is dependent on template parameters at
-/// level \p Level or below.
-///
-/// Sometimes we only substitute an inner set of template arguments and leave
-/// the outer templates alone. In such cases, contexts dependent only on the
-/// outer levels are not effectively dependent.
-static bool isDependentContextAtLevel(DeclContext *DC, unsigned Level) {
-  if (!DC->isDependentContext())
-    return false;
-  if (!Level)
-    return true;
-  return cast<Decl>(DC)->getTemplateDepth() > Level;
-}
-
 /// Find the instantiation of the given declaration within the
 /// current instantiation.
 ///
@@ -5650,10 +5635,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
                           const MultiLevelTemplateArgumentList &TemplateArgs,
                           bool FindingInstantiatedContext) {
   DeclContext *ParentDC = D->getDeclContext();
-  // Determine whether our parent context depends on any of the tempalte
-  // arguments we're currently substituting.
-  bool ParentDependsOnArgs = isDependentContextAtLevel(
-      ParentDC, TemplateArgs.getNumRetainedOuterLevels());
   // FIXME: Parmeters of pointer to functions (y below) that are themselves
   // parameters (p below) can have their ParentDC set to the translation-unit
   // - thus we can not consistently check if the ParentDC of such a parameter
@@ -5670,14 +5651,15 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
   //  - as long as we have a ParmVarDecl whose parent is non-dependent and
   //    whose type is not instantiation dependent, do nothing to the decl
   //  - otherwise find its instantiated decl.
-  if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
+  if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
       !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
     return D;
   if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
       isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
-      (ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
-                               isa<OMPDeclareReductionDecl>(ParentDC) ||
-                               isa<OMPDeclareMapperDecl>(ParentDC))) ||
+      ((ParentDC->isFunctionOrMethod() ||
+        isa<OMPDeclareReductionDecl>(ParentDC) ||
+        isa<OMPDeclareMapperDecl>(ParentDC)) &&
+       ParentDC->isDependentContext()) ||
       (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
     // D is a local of some kind. Look into the map of local
     // declarations to their instantiations.
@@ -5831,7 +5813,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
     // anonymous unions in class templates).
   }
 
-  if (!ParentDependsOnArgs)
+  if (!ParentDC->isDependentContext())
     return D;
 
   ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);

diff  --git a/clang/test/PCH/cxx2a-defaulted-comparison.cpp b/clang/test/PCH/cxx2a-defaulted-comparison.cpp
index d771424ad4fb..4fb0b83b2648 100644
--- a/clang/test/PCH/cxx2a-defaulted-comparison.cpp
+++ b/clang/test/PCH/cxx2a-defaulted-comparison.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2a -verify -Wno-defaulted-function-deleted -include %s %s
+// RxN: %clang_cc1 -std=c++2a -verify -Wno-defaulted-function-deleted -include %s %s
 //
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t.pch
 // RUN: %clang_cc1 -std=c++2a -include-pch %t.pch %s -verify

diff  --git a/clang/test/SemaTemplate/defaulted.cpp b/clang/test/SemaTemplate/defaulted.cpp
deleted file mode 100644
index 15111f71202d..000000000000
--- a/clang/test/SemaTemplate/defaulted.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
-
-namespace SpaceshipImpliesEq {
-  template<typename T> struct A {
-    int operator<=>(const A&) const = default;
-    constexpr bool f() { return operator==(*this); }
-  };
-  static_assert(A<int>().f());
-}


        


More information about the cfe-commits mailing list