105 lines · cpp
1//===- LifetimeAnnotations.cpp - -*--------------- C++------------------*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"9#include "clang/AST/ASTContext.h"10#include "clang/AST/Attr.h"11#include "clang/AST/Decl.h"12#include "clang/AST/DeclCXX.h"13#include "clang/AST/DeclTemplate.h"14#include "clang/AST/Type.h"15#include "clang/AST/TypeLoc.h"16 17namespace clang::lifetimes {18 19const FunctionDecl *20getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD) {21 return FD != nullptr ? FD->getMostRecentDecl() : nullptr;22}23 24const CXXMethodDecl *25getDeclWithMergedLifetimeBoundAttrs(const CXXMethodDecl *CMD) {26 const FunctionDecl *FD = CMD;27 return cast_if_present<CXXMethodDecl>(28 getDeclWithMergedLifetimeBoundAttrs(FD));29}30 31bool isNormalAssignmentOperator(const FunctionDecl *FD) {32 OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator();33 bool IsAssignment = OO == OO_Equal || isCompoundAssignmentOperator(OO);34 if (!IsAssignment)35 return false;36 QualType RetT = FD->getReturnType();37 if (!RetT->isLValueReferenceType())38 return false;39 ASTContext &Ctx = FD->getASTContext();40 QualType LHST;41 auto *MD = dyn_cast<CXXMethodDecl>(FD);42 if (MD && MD->isCXXInstanceMember())43 LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType());44 else45 LHST = FD->getParamDecl(0)->getType();46 return Ctx.hasSameType(RetT, LHST);47}48 49bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD) {50 CMD = getDeclWithMergedLifetimeBoundAttrs(CMD);51 return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 &&52 CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();53}54 55bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {56 FD = getDeclWithMergedLifetimeBoundAttrs(FD);57 const TypeSourceInfo *TSI = FD->getTypeSourceInfo();58 if (!TSI)59 return false;60 // Don't declare this variable in the second operand of the for-statement;61 // GCC miscompiles that by ending its lifetime before evaluating the62 // third operand. See gcc.gnu.org/PR86769.63 AttributedTypeLoc ATL;64 for (TypeLoc TL = TSI->getTypeLoc();65 (ATL = TL.getAsAdjusted<AttributedTypeLoc>());66 TL = ATL.getModifiedLoc()) {67 if (ATL.getAttrAs<clang::LifetimeBoundAttr>())68 return true;69 }70 71 return isNormalAssignmentOperator(FD);72}73 74template <typename T> static bool isRecordWithAttr(QualType Type) {75 auto *RD = Type->getAsCXXRecordDecl();76 if (!RD)77 return false;78 // Generally, if a primary template class declaration is annotated with an79 // attribute, all its specializations generated from template instantiations80 // should inherit the attribute.81 //82 // However, since lifetime analysis occurs during parsing, we may encounter83 // cases where a full definition of the specialization is not required. In84 // such cases, the specialization declaration remains incomplete and lacks the85 // attribute. Therefore, we fall back to checking the primary template class.86 //87 // Note: it is possible for a specialization declaration to have an attribute88 // even if the primary template does not.89 //90 // FIXME: What if the primary template and explicit specialization91 // declarations have conflicting attributes? We should consider diagnosing92 // this scenario.93 bool Result = RD->hasAttr<T>();94 95 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))96 Result |= CTSD->getSpecializedTemplate()->getTemplatedDecl()->hasAttr<T>();97 98 return Result;99}100 101bool isGslPointerType(QualType QT) { return isRecordWithAttr<PointerAttr>(QT); }102bool isGslOwnerType(QualType QT) { return isRecordWithAttr<OwnerAttr>(QT); }103 104} // namespace clang::lifetimes105