[clang] 56bba01 - [c++20] Fix incorrect assumptions in checks for comparison category types.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 9 12:18:50 PST 2019


Author: Richard Smith
Date: 2019-12-09T12:18:33-08:00
New Revision: 56bba012d9729af8ff4252dc860f1f7696942f1a

URL: https://github.com/llvm/llvm-project/commit/56bba012d9729af8ff4252dc860f1f7696942f1a
DIFF: https://github.com/llvm/llvm-project/commit/56bba012d9729af8ff4252dc860f1f7696942f1a.diff

LOG: [c++20] Fix incorrect assumptions in checks for comparison category types.

In the presence of modules, we can have multiple lookup results for the
same entity, and we need to re-check for completeness each time we
consider a type.

Added: 
    clang/test/SemaCXX/compare-modules-cxx2a.cpp

Modified: 
    clang/lib/AST/ComparisonCategories.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/SemaCXX/compare-cxx2a.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp
index 8999913b728b..3fb500c580e8 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -59,7 +59,7 @@ ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
   // a new entry representing it.
   DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
       &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
-  if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front()))
+  if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
     return nullptr;
   Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
   return &Objects.back();
@@ -70,7 +70,7 @@ static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
   if (!StdNS) {
     DeclContextLookupResult Lookup =
         Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
-    if (Lookup.size() == 1)
+    if (!Lookup.empty())
       StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
   }
   return StdNS;
@@ -81,7 +81,7 @@ static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
                                           ComparisonCategoryType Kind) {
   StringRef Name = ComparisonCategories::getCategoryString(Kind);
   DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
-  if (Lookup.size() == 1)
+  if (!Lookup.empty())
     if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
       return RD;
   return nullptr;

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0a7c41c1eda6..28159b9c0812 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7501,8 +7501,7 @@ class DefaultedComparisonSynthesizer
       VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering)
                              .getValueInfo(ComparisonCategoryResult::Equal)
                              ->VD;
-      RetVal = S.BuildDeclarationNameExpr(
-          CXXScopeSpec(), DeclarationNameInfo(), EqualVD);
+      RetVal = getDecl(EqualVD);
       if (RetVal.isInvalid())
         return StmtError();
       RetVal = buildStaticCastToR(RetVal.get());
@@ -7527,10 +7526,14 @@ class DefaultedComparisonSynthesizer
   }
 
 private:
+  ExprResult getDecl(ValueDecl *VD) {
+    return S.BuildDeclarationNameExpr(
+        CXXScopeSpec(), DeclarationNameInfo(VD->getDeclName(), Loc), VD);
+  }
+
   ExprResult getParam(unsigned I) {
     ParmVarDecl *PD = FD->getParamDecl(I);
-    return S.BuildDeclarationNameExpr(
-        CXXScopeSpec(), DeclarationNameInfo(PD->getDeclName(), Loc), PD);
+    return getDecl(PD);
   }
 
   ExprPair getCompleteObject() {
@@ -7622,8 +7625,7 @@ class DefaultedComparisonSynthesizer
       Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(VD), Loc, Loc);
 
       // cmp != 0
-      ExprResult VDRef = S.BuildDeclarationNameExpr(
-          CXXScopeSpec(), DeclarationNameInfo(Name, Loc), VD);
+      ExprResult VDRef = getDecl(VD);
       if (VDRef.isInvalid())
         return StmtError();
       llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
@@ -7639,8 +7641,7 @@ class DefaultedComparisonSynthesizer
         return StmtError();
 
       // return cmp;
-      VDRef = S.BuildDeclarationNameExpr(
-          CXXScopeSpec(), DeclarationNameInfo(Name, Loc), VD);
+      VDRef = getDecl(VD);
       if (VDRef.isInvalid())
         return StmtError();
       StmtResult ReturnStmt = S.BuildReturnStmt(Loc, VDRef.get());
@@ -10235,11 +10236,25 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
   assert(getLangOpts().CPlusPlus &&
          "Looking for comparison category type outside of C++.");
 
+  // Use an elaborated type for diagnostics which has a name containing the
+  // prepended 'std' namespace but not any inline namespace names.
+  auto TyForDiags = [&](ComparisonCategoryInfo *Info) {
+    auto *NNS =
+        NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
+    return Context.getElaboratedType(ETK_None, NNS, Info->getType());
+  };
+
   // Check if we've already successfully checked the comparison category type
   // before. If so, skip checking it again.
   ComparisonCategoryInfo *Info = Context.CompCategories.lookupInfo(Kind);
-  if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)])
+  if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) {
+    // The only thing we need to check is that the type has a reachable
+    // definition in the current context.
+    if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
+      return QualType();
+
     return Info->getType();
+  }
 
   // If lookup failed
   if (!Info) {
@@ -10258,18 +10273,10 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
   if (Info->Record->hasDefinition())
     Info->Record = Info->Record->getDefinition();
 
-  // Use an elaborated type for diagnostics which has a name containing the
-  // prepended 'std' namespace but not any inline namespace names.
-  QualType TyForDiags = [&]() {
-    auto *NNS =
-        NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
-    return Context.getElaboratedType(ETK_None, NNS, Info->getType());
-  }();
-
-  if (RequireCompleteType(Loc, TyForDiags, diag::err_incomplete_type))
+  if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
     return QualType();
 
-  InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags};
+  InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags(Info)};
 
   if (!Info->Record->isTriviallyCopyable())
     return UnsupportedSTLError(USS_NonTrivial);

diff  --git a/clang/test/SemaCXX/compare-cxx2a.cpp b/clang/test/SemaCXX/compare-cxx2a.cpp
index 1aca2dd86c58..da834e907ee2 100644
--- a/clang/test/SemaCXX/compare-cxx2a.cpp
+++ b/clang/test/SemaCXX/compare-cxx2a.cpp
@@ -3,6 +3,9 @@
 
 // RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s
 
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -std=c++2a -x c++ %S/Inputs/std-compare.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s -include-pch %t.pch
+
 #include "Inputs/std-compare.h"
 
 #define ASSERT_TYPE(...) static_assert(__is_same(__VA_ARGS__))

diff  --git a/clang/test/SemaCXX/compare-modules-cxx2a.cpp b/clang/test/SemaCXX/compare-modules-cxx2a.cpp
new file mode 100644
index 000000000000..fa9180024351
--- /dev/null
+++ b/clang/test/SemaCXX/compare-modules-cxx2a.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -verify -std=c++2a -fmodules -I%S/Inputs %s -fno-modules-error-recovery
+
+#pragma clang module build compare
+module compare {
+  explicit module cmp {}
+  explicit module other {}
+}
+#pragma clang module contents
+#pragma clang module begin compare.cmp
+#include "std-compare.h"
+#pragma clang module end
+#pragma clang module endbuild
+
+struct CC { CC(...); };
+
+void a() { void(0 <=> 0); } // expected-error {{include <compare>}}
+
+struct A {
+  CC operator<=>(const A&) const = default; // expected-error {{include <compare>}}
+};
+auto va = A() <=> A(); // expected-note {{required here}}
+
+#pragma clang module import compare.other
+
+// expected-note at std-compare.h:* 2+{{previous definition}}
+
+void b() { void(0 <=> 0); } // expected-error 1+{{definition of 'strong_ordering' must be imported}}
+
+struct B {
+  CC operator<=>(const B&) const = default; // expected-error 1+{{definition of 'strong_ordering' must be imported}}
+};
+auto vb = B() <=> B(); // expected-note {{required here}}
+
+#pragma clang module import compare.cmp
+
+void c() { void(0 <=> 0); }
+
+struct C {
+  CC operator<=>(const C&) const = default;
+};
+auto vc = C() <=> C();
+
+
+#pragma clang module build compare2
+module compare2 {}
+#pragma clang module contents
+#pragma clang module begin compare2
+#include "std-compare.h"
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import compare2
+
+void g() { void(0.0 <=> 0.0); }


        


More information about the cfe-commits mailing list