@@ -1917,3 +1917,188 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc,
1917
1917
return new (Context)
1918
1918
ExpressionTraitExpr (KWLoc, ET, Queried, Value, RParen, Context.BoolTy );
1919
1919
}
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