@@ -3248,56 +3248,164 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
3248
3248
return false;
3249
3249
}
3250
3250
3251
- static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
3252
- if (T.isNull())
3251
+ namespace {
3252
+ /// Check if a type has any reference to a declaration that is inside the body
3253
+ /// of a function.
3254
+ /// The \c CheckType(QualType) function should be used to determine
3255
+ /// this property.
3256
+ ///
3257
+ /// The type visitor visits one type object only (not recursive).
3258
+ /// To find all referenced declarations we must discover all type objects until
3259
+ /// the canonical type is reached (walk over typedef and similar objects). This
3260
+ /// is done by loop over all "sugar" type objects. For every such type we must
3261
+ /// check all declarations that are referenced from it. For this check the
3262
+ /// visitor is used. In the visit functions all referenced declarations except
3263
+ /// the one that follows in the sugar chain (if any) must be checked. For this
3264
+ /// check the same visitor is re-used (it has no state-dependent data).
3265
+ ///
3266
+ /// The visit functions have 3 possible return values:
3267
+ /// - True, found a declaration inside \c ParentDC.
3268
+ /// - False, found declarations only outside \c ParentDC and it is not possible
3269
+ /// to find more declarations (the "sugar" chain does not continue).
3270
+ /// - Empty optional value, found no declarations or only outside \c ParentDC,
3271
+ /// but it is possible to find more declarations in the type "sugar" chain.
3272
+ /// The loop over the "sugar" types can be implemented by using type visit
3273
+ /// functions only (call \c CheckType with the desugared type). With the current
3274
+ /// solution no visit function is needed if the type has only a desugared type
3275
+ /// as data.
3276
+ class IsTypeDeclaredInsideVisitor
3277
+ : public TypeVisitor<IsTypeDeclaredInsideVisitor, Optional<bool>> {
3278
+ public:
3279
+ IsTypeDeclaredInsideVisitor(const FunctionDecl *ParentDC)
3280
+ : ParentDC(ParentDC) {}
3281
+
3282
+ bool CheckType(QualType T) {
3283
+ // Check the chain of "sugar" types.
3284
+ // The "sugar" types are typedef or similar types that have the same
3285
+ // canonical type.
3286
+ if (Optional<bool> Res = Visit(T.getTypePtr()))
3287
+ return *Res;
3288
+ QualType DsT =
3289
+ T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
3290
+ while (DsT != T) {
3291
+ if (Optional<bool> Res = Visit(DsT.getTypePtr()))
3292
+ return *Res;
3293
+ T = DsT;
3294
+ DsT = T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
3295
+ }
3253
3296
return false;
3297
+ }
3298
+
3299
+ Optional<bool> VisitTagType(const TagType *T) {
3300
+ if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl()))
3301
+ for (const auto &Arg : Spec->getTemplateArgs().asArray())
3302
+ if (checkTemplateArgument(Arg))
3303
+ return true;
3304
+ return isAncestorDeclContextOf(ParentDC, T->getDecl());
3305
+ }
3306
+
3307
+ Optional<bool> VisitPointerType(const PointerType *T) {
3308
+ return CheckType(T->getPointeeType());
3309
+ }
3310
+
3311
+ Optional<bool> VisitReferenceType(const ReferenceType *T) {
3312
+ return CheckType(T->getPointeeTypeAsWritten());
3313
+ }
3314
+
3315
+ Optional<bool> VisitTypedefType(const TypedefType *T) {
3316
+ const TypedefNameDecl *TD = T->getDecl();
3317
+ assert(TD);
3318
+ return isAncestorDeclContextOf(ParentDC, TD);
3319
+ }
3320
+
3321
+ Optional<bool> VisitUsingType(const UsingType *T) {
3322
+ if (T->getFoundDecl() &&
3323
+ isAncestorDeclContextOf(ParentDC, T->getFoundDecl()))
3324
+ return true;
3325
+
3326
+ return {};
3327
+ }
3328
+
3329
+ Optional<bool>
3330
+ VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
3331
+ for (const auto &Arg : T->template_arguments())
3332
+ if (checkTemplateArgument(Arg))
3333
+ return true;
3334
+ // This type is a "sugar" to a record type, it can have a desugared type.
3335
+ return {};
3336
+ }
3337
+
3338
+ Optional<bool> VisitConstantArrayType(const ConstantArrayType *T) {
3339
+ if (T->getSizeExpr() && isAncestorDeclContextOf(ParentDC, T->getSizeExpr()))
3340
+ return true;
3341
+
3342
+ return CheckType(T->getElementType());
3343
+ }
3344
+
3345
+ Optional<bool> VisitVariableArrayType(const VariableArrayType *T) {
3346
+ llvm_unreachable(
3347
+ "Variable array should not occur in deduced return type of a function");
3348
+ }
3349
+
3350
+ Optional<bool> VisitIncompleteArrayType(const IncompleteArrayType *T) {
3351
+ llvm_unreachable("Incomplete array should not occur in deduced return type "
3352
+ "of a function");
3353
+ }
3354
+
3355
+ Optional<bool> VisitDependentArrayType(const IncompleteArrayType *T) {
3356
+ llvm_unreachable("Dependent array should not occur in deduced return type "
3357
+ "of a function");
3358
+ }
3359
+
3360
+ private:
3361
+ const DeclContext *const ParentDC;
3254
3362
3255
- auto CheckTemplateArgument = [FD] (const TemplateArgument &Arg) {
3363
+ bool checkTemplateArgument (const TemplateArgument &Arg) {
3256
3364
switch (Arg.getKind()) {
3365
+ case TemplateArgument::Null:
3366
+ return false;
3367
+ case TemplateArgument::Integral:
3368
+ return CheckType(Arg.getIntegralType());
3257
3369
case TemplateArgument::Type:
3258
- return hasTypeDeclaredInsideFunction (Arg.getAsType(), FD );
3370
+ return CheckType (Arg.getAsType());
3259
3371
case TemplateArgument::Expression:
3260
- return isAncestorDeclContextOf(FD, Arg.getAsExpr());
3261
- default:
3262
- // FIXME: Handle other argument kinds.
3372
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsExpr());
3373
+ case TemplateArgument::Declaration:
3374
+ // FIXME: The declaration in this case is not allowed to be in a function?
3375
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsDecl());
3376
+ case TemplateArgument::NullPtr:
3377
+ // FIXME: The type is not allowed to be in the function?
3378
+ return CheckType(Arg.getNullPtrType());
3379
+ case TemplateArgument::Pack:
3380
+ for (const auto &PackArg : Arg.getPackAsArray())
3381
+ if (checkTemplateArgument(PackArg))
3382
+ return true;
3383
+ return false;
3384
+ case TemplateArgument::Template:
3385
+ // Templates can not be defined locally in functions.
3386
+ // A template passed as argument can be not in ParentDC.
3387
+ return false;
3388
+ case TemplateArgument::TemplateExpansion:
3389
+ // Templates can not be defined locally in functions.
3390
+ // A template passed as argument can be not in ParentDC.
3263
3391
return false;
3264
3392
}
3265
3393
};
3266
-
3267
- if (const auto *RecordT = T->getAs<RecordType>()) {
3268
- const RecordDecl *RD = RecordT->getDecl();
3269
- assert(RD);
3270
- if (isAncestorDeclContextOf(FD, RD)) {
3271
- assert(RD->getLexicalDeclContext() == RD->getDeclContext());
3272
- return true;
3273
- }
3274
- if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
3275
- if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
3276
- CheckTemplateArgument))
3277
- return true;
3278
- // Note: It is possible that T can be get as both a RecordType and a
3279
- // TemplateSpecializationType.
3280
- }
3281
- if (const auto *TST = T->getAs<TemplateSpecializationType>())
3282
- return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
3283
-
3284
- return false;
3285
- }
3394
+ };
3395
+ } // namespace
3286
3396
3287
3397
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
3288
3398
QualType FromTy = D->getType();
3289
3399
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
3290
3400
assert(FromFPT && "Must be called on FunctionProtoType");
3291
- if (const AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType())
3292
- return hasTypeDeclaredInsideFunction(AutoT->getDeducedType(), D);
3293
- if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
3294
- const TypedefNameDecl *TD = TypedefT->getDecl();
3295
- assert(TD);
3296
- if (isAncestorDeclContextOf(D, TD)) {
3297
- assert(TD->getLexicalDeclContext() == TD->getDeclContext());
3298
- return true;
3299
- }
3401
+
3402
+ QualType RetT = FromFPT->getReturnType();
3403
+ if (isa<AutoType>(RetT.getTypePtr())) {
3404
+ FunctionDecl *Def = D->getDefinition();
3405
+ IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
3406
+ return Visitor.CheckType(RetT);
3300
3407
}
3408
+
3301
3409
return false;
3302
3410
}
3303
3411
0 commit comments