@@ -1917,3 +1917,190 @@ 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+ if (!BaseDecl)
1995+ continue ;
1996+ if (B.isVirtual ())
1997+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
1998+ << diag::TraitNotSatisfiedReason::VBase << B.getType ()
1999+ << B.getSourceRange ();
2000+ if (!SemaRef.IsCXXTriviallyRelocatableType (B.getType ()))
2001+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2002+ << diag::TraitNotSatisfiedReason::NRBase << B.getType ()
2003+ << B.getSourceRange ();
2004+ }
2005+ for (const FieldDecl *Field : D->fields ()) {
2006+ if (Field->getType ()->isReferenceType ())
2007+ continue ;
2008+ if (!SemaRef.IsCXXTriviallyRelocatableType (Field->getType ()))
2009+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2010+ << diag::TraitNotSatisfiedReason::NRField << Field << Field->getType ()
2011+ << Field->getSourceRange ();
2012+ }
2013+ if (D->hasDeletedDestructor ())
2014+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2015+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* Deleted*/ 0
2016+ << D->getDestructor ()->getSourceRange ();
2017+
2018+ if (D->hasAttr <TriviallyRelocatableAttr>())
2019+ return ;
2020+
2021+ if (D->isUnion ()) {
2022+ auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) {
2023+ if (Has)
2024+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2025+ << diag::TraitNotSatisfiedReason::UnionWithUserDeclaredSMF << K;
2026+ };
2027+ DiagSPM (CXXSpecialMemberKind::CopyConstructor,
2028+ D->hasUserDeclaredCopyConstructor ());
2029+ DiagSPM (CXXSpecialMemberKind::CopyAssignment,
2030+ D->hasUserDeclaredCopyAssignment ());
2031+ DiagSPM (CXXSpecialMemberKind::MoveConstructor,
2032+ D->hasUserDeclaredMoveConstructor ());
2033+ DiagSPM (CXXSpecialMemberKind::MoveAssignment,
2034+ D->hasUserDeclaredMoveAssignment ());
2035+ return ;
2036+ }
2037+
2038+ if (!D->hasSimpleMoveConstructor () && !D->hasSimpleCopyConstructor ()) {
2039+ const auto *Decl = cast<CXXConstructorDecl>(
2040+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ false ));
2041+ if (Decl && Decl->isUserProvided ())
2042+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2043+ << diag::TraitNotSatisfiedReason::UserProvidedCtr
2044+ << Decl->isMoveConstructor () << Decl->getSourceRange ();
2045+ }
2046+ if (!D->hasSimpleMoveAssignment () && !D->hasSimpleCopyAssignment ()) {
2047+ CXXMethodDecl *Decl =
2048+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ true );
2049+ if (Decl && Decl->isUserProvided ())
2050+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2051+ << diag::TraitNotSatisfiedReason::UserProvidedAssign
2052+ << Decl->isMoveAssignmentOperator () << Decl->getSourceRange ();
2053+ }
2054+ CXXDestructorDecl *Dtr = D->getDestructor ();
2055+ if (Dtr && Dtr->isUserProvided () && !Dtr->isDefaulted ())
2056+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2057+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* User Provided*/ 1
2058+ << Dtr->getSourceRange ();
2059+ }
2060+
2061+ static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
2062+ SourceLocation Loc,
2063+ QualType T) {
2064+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2065+ << T << diag::TraitName::TriviallyRelocatable;
2066+ if (T->isVariablyModifiedType ())
2067+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2068+ << diag::TraitNotSatisfiedReason::VLA;
2069+
2070+ if (T->isReferenceType ())
2071+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2072+ << diag::TraitNotSatisfiedReason::Ref;
2073+ T = T.getNonReferenceType ();
2074+
2075+ if (T.hasNonTrivialObjCLifetime ())
2076+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2077+ << diag::TraitNotSatisfiedReason::HasArcLifetime;
2078+
2079+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2080+ if (!D)
2081+ return ;
2082+
2083+ if (D->hasDefinition ())
2084+ DiagnoseNonTriviallyRelocatableReason (SemaRef, Loc, D);
2085+
2086+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2087+ }
2088+
2089+ void Sema::DiagnoseTypeTraitDetails (const Expr *E) {
2090+ E = E->IgnoreParenImpCasts ();
2091+ if (E->containsErrors ())
2092+ return ;
2093+
2094+ ExtractedTypeTraitInfo TraitInfo = ExtractTypeTraitFromExpression (E);
2095+ if (!TraitInfo)
2096+ return ;
2097+
2098+ const auto &[Trait, Args] = TraitInfo.value ();
2099+ switch (Trait) {
2100+ case UTT_IsCppTriviallyRelocatable:
2101+ DiagnoseNonTriviallyRelocatableReason (*this , E->getBeginLoc (), Args[0 ]);
2102+ break ;
2103+ default :
2104+ break ;
2105+ }
2106+ }
0 commit comments