@@ -1917,3 +1917,190 @@ 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
+ 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