@@ -1917,3 +1917,188 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc,
19171917 return new (Context)
19181918 ExpressionTraitExpr (KWLoc, ET, Queried, Value, RParen, Context.BoolTy );
19191919}
1920+
1921+ static std::optional<TypeTrait> StdNameToTypeTrait (StringRef Name) {
1922+ return llvm::StringSwitch<std::optional<TypeTrait>>(Name)
1923+ .Case (" is_trivially_relocatable" ,
1924+ TypeTrait::UTT_IsCppTriviallyRelocatable)
1925+ .Default (std::nullopt );
1926+ }
1927+
1928+ using ExtractedTypeTraitInfo =
1929+ std::optional<std::pair<TypeTrait, llvm::SmallVector<QualType, 1 >>>;
1930+
1931+ // Recognize type traits that are builting type traits, or known standard
1932+ // type traits in <type_traits>. Note that at this point we assume the
1933+ // trait evaluated to false, so we need only to recognize the shape of the
1934+ // outer-most symbol.
1935+ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression (const Expr *E) {
1936+ llvm::SmallVector<QualType, 1 > Args;
1937+ std::optional<TypeTrait> Trait;
1938+
1939+ // builtins
1940+ if (const auto *TraitExpr = dyn_cast<TypeTraitExpr>(E)) {
1941+ Trait = TraitExpr->getTrait ();
1942+ for (const auto *Arg : TraitExpr->getArgs ())
1943+ Args.push_back (Arg->getType ());
1944+ return {{Trait.value (), std::move (Args)}};
1945+ }
1946+ const auto *Ref = dyn_cast<DeclRefExpr>(E);
1947+ if (!Ref)
1948+ return std::nullopt ;
1949+
1950+ // std::is_xxx_v<>
1951+ if (const auto *VD =
1952+ dyn_cast<VarTemplateSpecializationDecl>(Ref->getDecl ())) {
1953+ if (!VD->isInStdNamespace ())
1954+ return std::nullopt ;
1955+ StringRef Name = VD->getIdentifier ()->getName ();
1956+ if (!Name.consume_back (" _v" ))
1957+ return std::nullopt ;
1958+ Trait = StdNameToTypeTrait (Name);
1959+ if (!Trait)
1960+ return std::nullopt ;
1961+ for (const auto &Arg : VD->getTemplateArgs ().asArray ())
1962+ Args.push_back (Arg.getAsType ());
1963+ return {{Trait.value (), std::move (Args)}};
1964+ }
1965+
1966+ // std::is_xxx<>::value
1967+ if (const auto *VD = dyn_cast<VarDecl>(Ref->getDecl ());
1968+ Ref->hasQualifier () && VD && VD->getIdentifier ()->isStr (" value" )) {
1969+ const Type *T = Ref->getQualifier ()->getAsType ();
1970+ if (!T)
1971+ return std::nullopt ;
1972+ const TemplateSpecializationType *Ts =
1973+ T->getAs <TemplateSpecializationType>();
1974+ if (!Ts)
1975+ return std::nullopt ;
1976+ const TemplateDecl *D = Ts->getTemplateName ().getAsTemplateDecl ();
1977+ if (!D || !D->isInStdNamespace ())
1978+ return std::nullopt ;
1979+ Trait = StdNameToTypeTrait (D->getIdentifier ()->getName ());
1980+ if (!Trait)
1981+ return std::nullopt ;
1982+ for (const auto &Arg : Ts->template_arguments ())
1983+ Args.push_back (Arg.getAsType ());
1984+ return {{Trait.value (), std::move (Args)}};
1985+ }
1986+ return std::nullopt ;
1987+ }
1988+
1989+ static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
1990+ SourceLocation Loc,
1991+ const CXXRecordDecl *D) {
1992+ for (const CXXBaseSpecifier &B : D->bases ()) {
1993+ const auto *BaseDecl = B.getType ()->getAsCXXRecordDecl ();
1994+ assert (BaseDecl && " invalid base?" );
1995+ if (B.isVirtual ())
1996+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
1997+ << diag::TraitNotSatisfiedReason::VBase << B.getType ()
1998+ << B.getSourceRange ();
1999+ if (!SemaRef.IsCXXTriviallyRelocatableType (B.getType ()))
2000+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2001+ << diag::TraitNotSatisfiedReason::NRBase << B.getType ()
2002+ << B.getSourceRange ();
2003+ }
2004+ for (const FieldDecl *Field : D->fields ()) {
2005+ if (!Field->getType ()->isReferenceType () &&
2006+ !SemaRef.IsCXXTriviallyRelocatableType (Field->getType ()))
2007+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2008+ << diag::TraitNotSatisfiedReason::NRField << Field << Field->getType ()
2009+ << Field->getSourceRange ();
2010+ }
2011+ if (D->hasDeletedDestructor ())
2012+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2013+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* Deleted*/ 0
2014+ << D->getDestructor ()->getSourceRange ();
2015+
2016+ if (D->hasAttr <TriviallyRelocatableAttr>())
2017+ return ;
2018+
2019+ if (D->isUnion ()) {
2020+ auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) {
2021+ if (Has)
2022+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2023+ << diag::TraitNotSatisfiedReason::UnionWithUserDeclaredSMF << K;
2024+ };
2025+ DiagSPM (CXXSpecialMemberKind::CopyConstructor,
2026+ D->hasUserDeclaredCopyConstructor ());
2027+ DiagSPM (CXXSpecialMemberKind::CopyAssignment,
2028+ D->hasUserDeclaredCopyAssignment ());
2029+ DiagSPM (CXXSpecialMemberKind::MoveConstructor,
2030+ D->hasUserDeclaredMoveConstructor ());
2031+ DiagSPM (CXXSpecialMemberKind::MoveAssignment,
2032+ D->hasUserDeclaredMoveAssignment ());
2033+ return ;
2034+ }
2035+
2036+ if (!D->hasSimpleMoveConstructor () && !D->hasSimpleCopyConstructor ()) {
2037+ const auto *Decl = cast<CXXConstructorDecl>(
2038+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ false ));
2039+ if (Decl && Decl->isUserProvided ())
2040+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2041+ << diag::TraitNotSatisfiedReason::UserProvidedCtr
2042+ << Decl->isMoveConstructor () << Decl->getSourceRange ();
2043+ }
2044+ if (!D->hasSimpleMoveAssignment () && !D->hasSimpleCopyAssignment ()) {
2045+ CXXMethodDecl *Decl =
2046+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ true );
2047+ if (Decl && Decl->isUserProvided ())
2048+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2049+ << diag::TraitNotSatisfiedReason::UserProvidedAssign
2050+ << Decl->isMoveAssignmentOperator () << Decl->getSourceRange ();
2051+ }
2052+ CXXDestructorDecl *Dtr = D->getDestructor ();
2053+ if (Dtr && Dtr->isUserProvided () && !Dtr->isDefaulted ())
2054+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2055+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* User Provided*/ 1
2056+ << Dtr->getSourceRange ();
2057+ }
2058+
2059+ static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
2060+ SourceLocation Loc,
2061+ QualType T) {
2062+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2063+ << T << diag::TraitName::TriviallyRelocatable;
2064+ if (T->isVariablyModifiedType ())
2065+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2066+ << diag::TraitNotSatisfiedReason::VLA;
2067+
2068+ if (T->isReferenceType ())
2069+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2070+ << diag::TraitNotSatisfiedReason::Ref;
2071+ T = T.getNonReferenceType ();
2072+
2073+ if (T.hasNonTrivialObjCLifetime ())
2074+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2075+ << diag::TraitNotSatisfiedReason::HasArcLifetime;
2076+
2077+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2078+ if (!D || D->isInvalidDecl ())
2079+ return ;
2080+
2081+ if (D->hasDefinition ())
2082+ DiagnoseNonTriviallyRelocatableReason (SemaRef, Loc, D);
2083+
2084+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2085+ }
2086+
2087+ void Sema::DiagnoseTypeTraitDetails (const Expr *E) {
2088+ E = E->IgnoreParenImpCasts ();
2089+ if (E->containsErrors ())
2090+ return ;
2091+
2092+ ExtractedTypeTraitInfo TraitInfo = ExtractTypeTraitFromExpression (E);
2093+ if (!TraitInfo)
2094+ return ;
2095+
2096+ const auto &[Trait, Args] = TraitInfo.value ();
2097+ switch (Trait) {
2098+ case UTT_IsCppTriviallyRelocatable:
2099+ DiagnoseNonTriviallyRelocatableReason (*this , E->getBeginLoc (), Args[0 ]);
2100+ break ;
2101+ default :
2102+ break ;
2103+ }
2104+ }
0 commit comments