@@ -8777,14 +8777,14 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) {
87778777 // Function pointers are okay.
87788778 if (pointeeType->isFunctionType ())
87798779 return false ;
8780-
8780+
87818781 // Pointers to record types are okay if they come in as foreign reference
87828782 // types.
8783- if (auto recordDecl = pointeeType->getAsRecordDecl ()) {
8783+ if (auto * recordDecl = pointeeType->getAsRecordDecl ()) {
87848784 if (hasImportAsRefAttr (recordDecl))
87858785 return false ;
87868786 }
8787-
8787+
87888788 // All other pointers are considered unsafe.
87898789 return true ;
87908790 }
@@ -8793,19 +8793,25 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) {
87938793 if (auto recordDecl = clangType->getAsTagDecl ()) {
87948794 // If we reached this point the types is not imported as a shared reference,
87958795 // so we don't need to check the bases whether they are shared references.
8796- auto safety = evaluateOrDefault (
8797- evaluator, ClangDeclExplicitSafety ({recordDecl, false }),
8798- ExplicitSafety::Unspecified);
8799- switch (safety) {
8800- case ExplicitSafety::Unsafe:
8801- return true ;
8802-
8803- case ExplicitSafety::Safe:
8804- case ExplicitSafety::Unspecified:
8805- return false ;
8806- }
8796+ auto req = ClangDeclExplicitSafety ({recordDecl, false });
8797+ if (evaluator.hasActiveRequest (req))
8798+ // Normally, using hasActiveRequest() to avoid cycles is an anti-pattern
8799+ // because cycles should be treated as errors. However, cycles are allowed
8800+ // in C++ template, e.g.:
8801+ //
8802+ // template <typename> class Foo { ... }; // throws away template arg
8803+ // template <typename T> class Bar : Foo<Bar<T>> { ... };
8804+ //
8805+ // A common use case of cyclic templates is the CRTP pattern.
8806+ //
8807+ // We need to avoid request cycles, so if there is already an active
8808+ // request for this type, just assume it is not explicitly unsafe for now
8809+ // (i.e., as if it were unspecified).
8810+ return false ;
8811+ return evaluateOrDefault (evaluator, req, ExplicitSafety::Unspecified) ==
8812+ ExplicitSafety::Unsafe;
88078813 }
8808-
8814+
88098815 // Everything else is safe.
88108816 return false ;
88118817}
@@ -8845,6 +8851,29 @@ ClangDeclExplicitSafety::evaluate(Evaluator &evaluator,
88458851 ClangTypeEscapability ({recordDecl->getTypeForDecl (), nullptr }),
88468852 CxxEscapability::Unknown) != CxxEscapability::Unknown)
88478853 return ExplicitSafety::Safe;
8854+
8855+ // A template class is unsafe if any of its type arguments are unsafe.
8856+ // Note that this does not rely on the record being defined.
8857+ if (const auto *ctsd =
8858+ dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
8859+ for (auto arg : ctsd->getTemplateArgs ().asArray ()) {
8860+ switch (arg.getKind ()) {
8861+ case clang::TemplateArgument::Type:
8862+ if (hasUnsafeType (evaluator, arg.getAsType ()))
8863+ return ExplicitSafety::Unsafe;
8864+ break ;
8865+ case clang::TemplateArgument::Pack:
8866+ for (auto pkArg : arg.getPackAsArray ()) {
8867+ if (pkArg.getKind () == clang::TemplateArgument::Type &&
8868+ hasUnsafeType (evaluator, pkArg.getAsType ()))
8869+ return ExplicitSafety::Unsafe;
8870+ }
8871+ break ;
8872+ default :
8873+ continue ;
8874+ }
8875+ }
8876+ }
88488877
88498878 // If we don't have a definition, leave it unspecified.
88508879 recordDecl = recordDecl->getDefinition ();
0 commit comments