// 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();
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;
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;
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());
}
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() {
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);
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());
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) {
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);
--- /dev/null
+// 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@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); }