1e5dd7070Spatrick //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements decl-related attribute processing.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/AST/ASTConsumer.h"
14e5dd7070Spatrick #include "clang/AST/ASTContext.h"
15e5dd7070Spatrick #include "clang/AST/ASTMutationListener.h"
16e5dd7070Spatrick #include "clang/AST/CXXInheritance.h"
17e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
18e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
19e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
20e5dd7070Spatrick #include "clang/AST/Expr.h"
21e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
22e5dd7070Spatrick #include "clang/AST/Mangle.h"
23e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
24a0747c9fSpatrick #include "clang/AST/Type.h"
25e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
26a0747c9fSpatrick #include "clang/Basic/DarwinSDKInfo.h"
27*7a9b00ceSrobert #include "clang/Basic/HLSLRuntime.h"
28*7a9b00ceSrobert #include "clang/Basic/LangOptions.h"
29a0747c9fSpatrick #include "clang/Basic/SourceLocation.h"
30e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
31e5dd7070Spatrick #include "clang/Basic/TargetBuiltins.h"
32e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
33e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
34e5dd7070Spatrick #include "clang/Sema/DeclSpec.h"
35e5dd7070Spatrick #include "clang/Sema/DelayedDiagnostic.h"
36e5dd7070Spatrick #include "clang/Sema/Initialization.h"
37e5dd7070Spatrick #include "clang/Sema/Lookup.h"
38a0747c9fSpatrick #include "clang/Sema/ParsedAttr.h"
39e5dd7070Spatrick #include "clang/Sema/Scope.h"
40e5dd7070Spatrick #include "clang/Sema/ScopeInfo.h"
41e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
42e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
43e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
44a0747c9fSpatrick #include "llvm/IR/Assumptions.h"
45a0747c9fSpatrick #include "llvm/MC/MCSectionMachO.h"
46a0747c9fSpatrick #include "llvm/Support/Error.h"
47e5dd7070Spatrick #include "llvm/Support/MathExtras.h"
48a0747c9fSpatrick #include "llvm/Support/raw_ostream.h"
49*7a9b00ceSrobert #include <optional>
50e5dd7070Spatrick
51e5dd7070Spatrick using namespace clang;
52e5dd7070Spatrick using namespace sema;
53e5dd7070Spatrick
54e5dd7070Spatrick namespace AttributeLangSupport {
55e5dd7070Spatrick enum LANG {
56e5dd7070Spatrick C,
57e5dd7070Spatrick Cpp,
58e5dd7070Spatrick ObjC
59e5dd7070Spatrick };
60e5dd7070Spatrick } // end namespace AttributeLangSupport
61e5dd7070Spatrick
62e5dd7070Spatrick //===----------------------------------------------------------------------===//
63e5dd7070Spatrick // Helper functions
64e5dd7070Spatrick //===----------------------------------------------------------------------===//
65e5dd7070Spatrick
66e5dd7070Spatrick /// isFunctionOrMethod - Return true if the given decl has function
67e5dd7070Spatrick /// type (function or function-typed variable) or an Objective-C
68e5dd7070Spatrick /// method.
isFunctionOrMethod(const Decl * D)69e5dd7070Spatrick static bool isFunctionOrMethod(const Decl *D) {
70e5dd7070Spatrick return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
71e5dd7070Spatrick }
72e5dd7070Spatrick
73e5dd7070Spatrick /// Return true if the given decl has function type (function or
74e5dd7070Spatrick /// function-typed variable) or an Objective-C method or a block.
isFunctionOrMethodOrBlock(const Decl * D)75e5dd7070Spatrick static bool isFunctionOrMethodOrBlock(const Decl *D) {
76e5dd7070Spatrick return isFunctionOrMethod(D) || isa<BlockDecl>(D);
77e5dd7070Spatrick }
78e5dd7070Spatrick
79e5dd7070Spatrick /// Return true if the given decl has a declarator that should have
80e5dd7070Spatrick /// been processed by Sema::GetTypeForDeclarator.
hasDeclarator(const Decl * D)81e5dd7070Spatrick static bool hasDeclarator(const Decl *D) {
82e5dd7070Spatrick // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
83e5dd7070Spatrick return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) ||
84e5dd7070Spatrick isa<ObjCPropertyDecl>(D);
85e5dd7070Spatrick }
86e5dd7070Spatrick
87e5dd7070Spatrick /// hasFunctionProto - Return true if the given decl has a argument
88e5dd7070Spatrick /// information. This decl should have already passed
89e5dd7070Spatrick /// isFunctionOrMethod or isFunctionOrMethodOrBlock.
hasFunctionProto(const Decl * D)90e5dd7070Spatrick static bool hasFunctionProto(const Decl *D) {
91e5dd7070Spatrick if (const FunctionType *FnTy = D->getFunctionType())
92e5dd7070Spatrick return isa<FunctionProtoType>(FnTy);
93e5dd7070Spatrick return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
94e5dd7070Spatrick }
95e5dd7070Spatrick
96e5dd7070Spatrick /// getFunctionOrMethodNumParams - Return number of function or method
97e5dd7070Spatrick /// parameters. It is an error to call this on a K&R function (use
98e5dd7070Spatrick /// hasFunctionProto first).
getFunctionOrMethodNumParams(const Decl * D)99e5dd7070Spatrick static unsigned getFunctionOrMethodNumParams(const Decl *D) {
100e5dd7070Spatrick if (const FunctionType *FnTy = D->getFunctionType())
101e5dd7070Spatrick return cast<FunctionProtoType>(FnTy)->getNumParams();
102e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D))
103e5dd7070Spatrick return BD->getNumParams();
104e5dd7070Spatrick return cast<ObjCMethodDecl>(D)->param_size();
105e5dd7070Spatrick }
106e5dd7070Spatrick
getFunctionOrMethodParam(const Decl * D,unsigned Idx)107e5dd7070Spatrick static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D,
108e5dd7070Spatrick unsigned Idx) {
109e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D))
110e5dd7070Spatrick return FD->getParamDecl(Idx);
111e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
112e5dd7070Spatrick return MD->getParamDecl(Idx);
113e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D))
114e5dd7070Spatrick return BD->getParamDecl(Idx);
115e5dd7070Spatrick return nullptr;
116e5dd7070Spatrick }
117e5dd7070Spatrick
getFunctionOrMethodParamType(const Decl * D,unsigned Idx)118e5dd7070Spatrick static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
119e5dd7070Spatrick if (const FunctionType *FnTy = D->getFunctionType())
120e5dd7070Spatrick return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
121e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D))
122e5dd7070Spatrick return BD->getParamDecl(Idx)->getType();
123e5dd7070Spatrick
124e5dd7070Spatrick return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
125e5dd7070Spatrick }
126e5dd7070Spatrick
getFunctionOrMethodParamRange(const Decl * D,unsigned Idx)127e5dd7070Spatrick static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
128e5dd7070Spatrick if (auto *PVD = getFunctionOrMethodParam(D, Idx))
129e5dd7070Spatrick return PVD->getSourceRange();
130e5dd7070Spatrick return SourceRange();
131e5dd7070Spatrick }
132e5dd7070Spatrick
getFunctionOrMethodResultType(const Decl * D)133e5dd7070Spatrick static QualType getFunctionOrMethodResultType(const Decl *D) {
134e5dd7070Spatrick if (const FunctionType *FnTy = D->getFunctionType())
135e5dd7070Spatrick return FnTy->getReturnType();
136e5dd7070Spatrick return cast<ObjCMethodDecl>(D)->getReturnType();
137e5dd7070Spatrick }
138e5dd7070Spatrick
getFunctionOrMethodResultSourceRange(const Decl * D)139e5dd7070Spatrick static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
140e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D))
141e5dd7070Spatrick return FD->getReturnTypeSourceRange();
142e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
143e5dd7070Spatrick return MD->getReturnTypeSourceRange();
144e5dd7070Spatrick return SourceRange();
145e5dd7070Spatrick }
146e5dd7070Spatrick
isFunctionOrMethodVariadic(const Decl * D)147e5dd7070Spatrick static bool isFunctionOrMethodVariadic(const Decl *D) {
148e5dd7070Spatrick if (const FunctionType *FnTy = D->getFunctionType())
149e5dd7070Spatrick return cast<FunctionProtoType>(FnTy)->isVariadic();
150e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D))
151e5dd7070Spatrick return BD->isVariadic();
152e5dd7070Spatrick return cast<ObjCMethodDecl>(D)->isVariadic();
153e5dd7070Spatrick }
154e5dd7070Spatrick
isInstanceMethod(const Decl * D)155e5dd7070Spatrick static bool isInstanceMethod(const Decl *D) {
156e5dd7070Spatrick if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
157e5dd7070Spatrick return MethodDecl->isInstance();
158e5dd7070Spatrick return false;
159e5dd7070Spatrick }
160e5dd7070Spatrick
isNSStringType(QualType T,ASTContext & Ctx,bool AllowNSAttributedString=false)161a0747c9fSpatrick static inline bool isNSStringType(QualType T, ASTContext &Ctx,
162a0747c9fSpatrick bool AllowNSAttributedString = false) {
163e5dd7070Spatrick const auto *PT = T->getAs<ObjCObjectPointerType>();
164e5dd7070Spatrick if (!PT)
165e5dd7070Spatrick return false;
166e5dd7070Spatrick
167e5dd7070Spatrick ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface();
168e5dd7070Spatrick if (!Cls)
169e5dd7070Spatrick return false;
170e5dd7070Spatrick
171e5dd7070Spatrick IdentifierInfo* ClsName = Cls->getIdentifier();
172e5dd7070Spatrick
173a0747c9fSpatrick if (AllowNSAttributedString &&
174a0747c9fSpatrick ClsName == &Ctx.Idents.get("NSAttributedString"))
175a0747c9fSpatrick return true;
176e5dd7070Spatrick // FIXME: Should we walk the chain of classes?
177e5dd7070Spatrick return ClsName == &Ctx.Idents.get("NSString") ||
178e5dd7070Spatrick ClsName == &Ctx.Idents.get("NSMutableString");
179e5dd7070Spatrick }
180e5dd7070Spatrick
isCFStringType(QualType T,ASTContext & Ctx)181e5dd7070Spatrick static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
182e5dd7070Spatrick const auto *PT = T->getAs<PointerType>();
183e5dd7070Spatrick if (!PT)
184e5dd7070Spatrick return false;
185e5dd7070Spatrick
186e5dd7070Spatrick const auto *RT = PT->getPointeeType()->getAs<RecordType>();
187e5dd7070Spatrick if (!RT)
188e5dd7070Spatrick return false;
189e5dd7070Spatrick
190e5dd7070Spatrick const RecordDecl *RD = RT->getDecl();
191e5dd7070Spatrick if (RD->getTagKind() != TTK_Struct)
192e5dd7070Spatrick return false;
193e5dd7070Spatrick
194e5dd7070Spatrick return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
195e5dd7070Spatrick }
196e5dd7070Spatrick
getNumAttributeArgs(const ParsedAttr & AL)197e5dd7070Spatrick static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
198e5dd7070Spatrick // FIXME: Include the type in the argument list.
199e5dd7070Spatrick return AL.getNumArgs() + AL.hasParsedType();
200e5dd7070Spatrick }
201e5dd7070Spatrick
202e5dd7070Spatrick /// A helper function to provide Attribute Location for the Attr types
203e5dd7070Spatrick /// AND the ParsedAttr.
204e5dd7070Spatrick template <typename AttrInfo>
205*7a9b00ceSrobert static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation>
getAttrLoc(const AttrInfo & AL)206e5dd7070Spatrick getAttrLoc(const AttrInfo &AL) {
207e5dd7070Spatrick return AL.getLocation();
208e5dd7070Spatrick }
getAttrLoc(const ParsedAttr & AL)209e5dd7070Spatrick static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); }
210e5dd7070Spatrick
211e5dd7070Spatrick /// If Expr is a valid integer constant, get the value of the integer
212e5dd7070Spatrick /// expression and return success or failure. May output an error.
213e5dd7070Spatrick ///
214e5dd7070Spatrick /// Negative argument is implicitly converted to unsigned, unless
215e5dd7070Spatrick /// \p StrictlyUnsigned is true.
216e5dd7070Spatrick template <typename AttrInfo>
checkUInt32Argument(Sema & S,const AttrInfo & AI,const Expr * Expr,uint32_t & Val,unsigned Idx=UINT_MAX,bool StrictlyUnsigned=false)217e5dd7070Spatrick static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
218e5dd7070Spatrick uint32_t &Val, unsigned Idx = UINT_MAX,
219e5dd7070Spatrick bool StrictlyUnsigned = false) {
220*7a9b00ceSrobert std::optional<llvm::APSInt> I = llvm::APSInt(32);
221*7a9b00ceSrobert if (Expr->isTypeDependent() ||
222a0747c9fSpatrick !(I = Expr->getIntegerConstantExpr(S.Context))) {
223e5dd7070Spatrick if (Idx != UINT_MAX)
224e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
225e5dd7070Spatrick << &AI << Idx << AANT_ArgumentIntegerConstant
226e5dd7070Spatrick << Expr->getSourceRange();
227e5dd7070Spatrick else
228e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
229e5dd7070Spatrick << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
230e5dd7070Spatrick return false;
231e5dd7070Spatrick }
232e5dd7070Spatrick
233a0747c9fSpatrick if (!I->isIntN(32)) {
234e5dd7070Spatrick S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
235a0747c9fSpatrick << toString(*I, 10, false) << 32 << /* Unsigned */ 1;
236e5dd7070Spatrick return false;
237e5dd7070Spatrick }
238e5dd7070Spatrick
239a0747c9fSpatrick if (StrictlyUnsigned && I->isSigned() && I->isNegative()) {
240e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
241e5dd7070Spatrick << &AI << /*non-negative*/ 1;
242e5dd7070Spatrick return false;
243e5dd7070Spatrick }
244e5dd7070Spatrick
245a0747c9fSpatrick Val = (uint32_t)I->getZExtValue();
246e5dd7070Spatrick return true;
247e5dd7070Spatrick }
248e5dd7070Spatrick
249e5dd7070Spatrick /// Wrapper around checkUInt32Argument, with an extra check to be sure
250e5dd7070Spatrick /// that the result will fit into a regular (signed) int. All args have the same
251e5dd7070Spatrick /// purpose as they do in checkUInt32Argument.
252e5dd7070Spatrick template <typename AttrInfo>
checkPositiveIntArgument(Sema & S,const AttrInfo & AI,const Expr * Expr,int & Val,unsigned Idx=UINT_MAX)253e5dd7070Spatrick static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr,
254e5dd7070Spatrick int &Val, unsigned Idx = UINT_MAX) {
255e5dd7070Spatrick uint32_t UVal;
256e5dd7070Spatrick if (!checkUInt32Argument(S, AI, Expr, UVal, Idx))
257e5dd7070Spatrick return false;
258e5dd7070Spatrick
259e5dd7070Spatrick if (UVal > (uint32_t)std::numeric_limits<int>::max()) {
260e5dd7070Spatrick llvm::APSInt I(32); // for toString
261e5dd7070Spatrick I = UVal;
262e5dd7070Spatrick S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
263a0747c9fSpatrick << toString(I, 10, false) << 32 << /* Unsigned */ 0;
264e5dd7070Spatrick return false;
265e5dd7070Spatrick }
266e5dd7070Spatrick
267e5dd7070Spatrick Val = UVal;
268e5dd7070Spatrick return true;
269e5dd7070Spatrick }
270e5dd7070Spatrick
271e5dd7070Spatrick /// Diagnose mutually exclusive attributes when present on a given
272e5dd7070Spatrick /// declaration. Returns true if diagnosed.
273e5dd7070Spatrick template <typename AttrTy>
checkAttrMutualExclusion(Sema & S,Decl * D,const ParsedAttr & AL)274e5dd7070Spatrick static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) {
275e5dd7070Spatrick if (const auto *A = D->getAttr<AttrTy>()) {
276e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A;
277e5dd7070Spatrick S.Diag(A->getLocation(), diag::note_conflicting_attribute);
278e5dd7070Spatrick return true;
279e5dd7070Spatrick }
280e5dd7070Spatrick return false;
281e5dd7070Spatrick }
282e5dd7070Spatrick
283e5dd7070Spatrick template <typename AttrTy>
checkAttrMutualExclusion(Sema & S,Decl * D,const Attr & AL)284e5dd7070Spatrick static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) {
285e5dd7070Spatrick if (const auto *A = D->getAttr<AttrTy>()) {
286e5dd7070Spatrick S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL
287e5dd7070Spatrick << A;
288e5dd7070Spatrick S.Diag(A->getLocation(), diag::note_conflicting_attribute);
289e5dd7070Spatrick return true;
290e5dd7070Spatrick }
291e5dd7070Spatrick return false;
292e5dd7070Spatrick }
293e5dd7070Spatrick
294e5dd7070Spatrick /// Check if IdxExpr is a valid parameter index for a function or
295e5dd7070Spatrick /// instance method D. May output an error.
296e5dd7070Spatrick ///
297e5dd7070Spatrick /// \returns true if IdxExpr is a valid index.
298e5dd7070Spatrick template <typename AttrInfo>
checkFunctionOrMethodParameterIndex(Sema & S,const Decl * D,const AttrInfo & AI,unsigned AttrArgNum,const Expr * IdxExpr,ParamIdx & Idx,bool CanIndexImplicitThis=false)299e5dd7070Spatrick static bool checkFunctionOrMethodParameterIndex(
300e5dd7070Spatrick Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum,
301e5dd7070Spatrick const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) {
302e5dd7070Spatrick assert(isFunctionOrMethodOrBlock(D));
303e5dd7070Spatrick
304e5dd7070Spatrick // In C++ the implicit 'this' function parameter also counts.
305e5dd7070Spatrick // Parameters are counted from one.
306e5dd7070Spatrick bool HP = hasFunctionProto(D);
307e5dd7070Spatrick bool HasImplicitThisParam = isInstanceMethod(D);
308e5dd7070Spatrick bool IV = HP && isFunctionOrMethodVariadic(D);
309e5dd7070Spatrick unsigned NumParams =
310e5dd7070Spatrick (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
311e5dd7070Spatrick
312*7a9b00ceSrobert std::optional<llvm::APSInt> IdxInt;
313*7a9b00ceSrobert if (IdxExpr->isTypeDependent() ||
314a0747c9fSpatrick !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) {
315e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
316e5dd7070Spatrick << &AI << AttrArgNum << AANT_ArgumentIntegerConstant
317e5dd7070Spatrick << IdxExpr->getSourceRange();
318e5dd7070Spatrick return false;
319e5dd7070Spatrick }
320e5dd7070Spatrick
321a0747c9fSpatrick unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX);
322e5dd7070Spatrick if (IdxSource < 1 || (!IV && IdxSource > NumParams)) {
323e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
324e5dd7070Spatrick << &AI << AttrArgNum << IdxExpr->getSourceRange();
325e5dd7070Spatrick return false;
326e5dd7070Spatrick }
327e5dd7070Spatrick if (HasImplicitThisParam && !CanIndexImplicitThis) {
328e5dd7070Spatrick if (IdxSource == 1) {
329e5dd7070Spatrick S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument)
330e5dd7070Spatrick << &AI << IdxExpr->getSourceRange();
331e5dd7070Spatrick return false;
332e5dd7070Spatrick }
333e5dd7070Spatrick }
334e5dd7070Spatrick
335e5dd7070Spatrick Idx = ParamIdx(IdxSource, D);
336e5dd7070Spatrick return true;
337e5dd7070Spatrick }
338e5dd7070Spatrick
339*7a9b00ceSrobert /// Check if the argument \p E is a ASCII string literal. If not emit an error
340*7a9b00ceSrobert /// and return false, otherwise set \p Str to the value of the string literal
341*7a9b00ceSrobert /// and return true.
checkStringLiteralArgumentAttr(const AttributeCommonInfo & CI,const Expr * E,StringRef & Str,SourceLocation * ArgLocation)342*7a9b00ceSrobert bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI,
343*7a9b00ceSrobert const Expr *E, StringRef &Str,
344*7a9b00ceSrobert SourceLocation *ArgLocation) {
345*7a9b00ceSrobert const auto *Literal = dyn_cast<StringLiteral>(E->IgnoreParenCasts());
346*7a9b00ceSrobert if (ArgLocation)
347*7a9b00ceSrobert *ArgLocation = E->getBeginLoc();
348*7a9b00ceSrobert
349*7a9b00ceSrobert if (!Literal || !Literal->isOrdinary()) {
350*7a9b00ceSrobert Diag(E->getBeginLoc(), diag::err_attribute_argument_type)
351*7a9b00ceSrobert << CI << AANT_ArgumentString;
352*7a9b00ceSrobert return false;
353*7a9b00ceSrobert }
354*7a9b00ceSrobert
355*7a9b00ceSrobert Str = Literal->getString();
356*7a9b00ceSrobert return true;
357*7a9b00ceSrobert }
358*7a9b00ceSrobert
359e5dd7070Spatrick /// Check if the argument \p ArgNum of \p Attr is a ASCII string literal.
360e5dd7070Spatrick /// If not emit an error and return false. If the argument is an identifier it
361e5dd7070Spatrick /// will emit an error with a fixit hint and treat it as if it was a string
362e5dd7070Spatrick /// literal.
checkStringLiteralArgumentAttr(const ParsedAttr & AL,unsigned ArgNum,StringRef & Str,SourceLocation * ArgLocation)363e5dd7070Spatrick bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
364e5dd7070Spatrick StringRef &Str,
365e5dd7070Spatrick SourceLocation *ArgLocation) {
366e5dd7070Spatrick // Look for identifiers. If we have one emit a hint to fix it to a literal.
367e5dd7070Spatrick if (AL.isArgIdent(ArgNum)) {
368e5dd7070Spatrick IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum);
369e5dd7070Spatrick Diag(Loc->Loc, diag::err_attribute_argument_type)
370e5dd7070Spatrick << AL << AANT_ArgumentString
371e5dd7070Spatrick << FixItHint::CreateInsertion(Loc->Loc, "\"")
372e5dd7070Spatrick << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\"");
373e5dd7070Spatrick Str = Loc->Ident->getName();
374e5dd7070Spatrick if (ArgLocation)
375e5dd7070Spatrick *ArgLocation = Loc->Loc;
376e5dd7070Spatrick return true;
377e5dd7070Spatrick }
378e5dd7070Spatrick
379e5dd7070Spatrick // Now check for an actual string literal.
380e5dd7070Spatrick Expr *ArgExpr = AL.getArgAsExpr(ArgNum);
381*7a9b00ceSrobert return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation);
382e5dd7070Spatrick }
383e5dd7070Spatrick
384e5dd7070Spatrick /// Applies the given attribute to the Decl without performing any
385e5dd7070Spatrick /// additional semantic checking.
386e5dd7070Spatrick template <typename AttrType>
handleSimpleAttribute(Sema & S,Decl * D,const AttributeCommonInfo & CI)387e5dd7070Spatrick static void handleSimpleAttribute(Sema &S, Decl *D,
388e5dd7070Spatrick const AttributeCommonInfo &CI) {
389e5dd7070Spatrick D->addAttr(::new (S.Context) AttrType(S.Context, CI));
390e5dd7070Spatrick }
391e5dd7070Spatrick
392e5dd7070Spatrick template <typename... DiagnosticArgs>
393e5dd7070Spatrick static const Sema::SemaDiagnosticBuilder&
appendDiagnostics(const Sema::SemaDiagnosticBuilder & Bldr)394e5dd7070Spatrick appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) {
395e5dd7070Spatrick return Bldr;
396e5dd7070Spatrick }
397e5dd7070Spatrick
398e5dd7070Spatrick template <typename T, typename... DiagnosticArgs>
399e5dd7070Spatrick static const Sema::SemaDiagnosticBuilder&
appendDiagnostics(const Sema::SemaDiagnosticBuilder & Bldr,T && ExtraArg,DiagnosticArgs &&...ExtraArgs)400e5dd7070Spatrick appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
401e5dd7070Spatrick DiagnosticArgs &&... ExtraArgs) {
402e5dd7070Spatrick return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
403e5dd7070Spatrick std::forward<DiagnosticArgs>(ExtraArgs)...);
404e5dd7070Spatrick }
405e5dd7070Spatrick
406a0747c9fSpatrick /// Add an attribute @c AttrType to declaration @c D, provided that
407a0747c9fSpatrick /// @c PassesCheck is true.
408a0747c9fSpatrick /// Otherwise, emit diagnostic @c DiagID, passing in all parameters
409a0747c9fSpatrick /// specified in @c ExtraArgs.
410e5dd7070Spatrick template <typename AttrType, typename... DiagnosticArgs>
handleSimpleAttributeOrDiagnose(Sema & S,Decl * D,const AttributeCommonInfo & CI,bool PassesCheck,unsigned DiagID,DiagnosticArgs &&...ExtraArgs)411e5dd7070Spatrick static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
412e5dd7070Spatrick const AttributeCommonInfo &CI,
413e5dd7070Spatrick bool PassesCheck, unsigned DiagID,
414e5dd7070Spatrick DiagnosticArgs &&... ExtraArgs) {
415e5dd7070Spatrick if (!PassesCheck) {
416e5dd7070Spatrick Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
417e5dd7070Spatrick appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
418e5dd7070Spatrick return;
419e5dd7070Spatrick }
420e5dd7070Spatrick handleSimpleAttribute<AttrType>(S, D, CI);
421e5dd7070Spatrick }
422e5dd7070Spatrick
423e5dd7070Spatrick /// Check if the passed-in expression is of type int or bool.
isIntOrBool(Expr * Exp)424e5dd7070Spatrick static bool isIntOrBool(Expr *Exp) {
425e5dd7070Spatrick QualType QT = Exp->getType();
426e5dd7070Spatrick return QT->isBooleanType() || QT->isIntegerType();
427e5dd7070Spatrick }
428e5dd7070Spatrick
429e5dd7070Spatrick
430e5dd7070Spatrick // Check to see if the type is a smart pointer of some kind. We assume
431e5dd7070Spatrick // it's a smart pointer if it defines both operator-> and operator*.
threadSafetyCheckIsSmartPointer(Sema & S,const RecordType * RT)432e5dd7070Spatrick static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
433e5dd7070Spatrick auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record,
434e5dd7070Spatrick OverloadedOperatorKind Op) {
435e5dd7070Spatrick DeclContextLookupResult Result =
436e5dd7070Spatrick Record->lookup(S.Context.DeclarationNames.getCXXOperatorName(Op));
437e5dd7070Spatrick return !Result.empty();
438e5dd7070Spatrick };
439e5dd7070Spatrick
440e5dd7070Spatrick const RecordDecl *Record = RT->getDecl();
441e5dd7070Spatrick bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
442e5dd7070Spatrick bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
443e5dd7070Spatrick if (foundStarOperator && foundArrowOperator)
444e5dd7070Spatrick return true;
445e5dd7070Spatrick
446e5dd7070Spatrick const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record);
447e5dd7070Spatrick if (!CXXRecord)
448e5dd7070Spatrick return false;
449e5dd7070Spatrick
450e5dd7070Spatrick for (auto BaseSpecifier : CXXRecord->bases()) {
451e5dd7070Spatrick if (!foundStarOperator)
452e5dd7070Spatrick foundStarOperator = IsOverloadedOperatorPresent(
453e5dd7070Spatrick BaseSpecifier.getType()->getAsRecordDecl(), OO_Star);
454e5dd7070Spatrick if (!foundArrowOperator)
455e5dd7070Spatrick foundArrowOperator = IsOverloadedOperatorPresent(
456e5dd7070Spatrick BaseSpecifier.getType()->getAsRecordDecl(), OO_Arrow);
457e5dd7070Spatrick }
458e5dd7070Spatrick
459e5dd7070Spatrick if (foundStarOperator && foundArrowOperator)
460e5dd7070Spatrick return true;
461e5dd7070Spatrick
462e5dd7070Spatrick return false;
463e5dd7070Spatrick }
464e5dd7070Spatrick
465e5dd7070Spatrick /// Check if passed in Decl is a pointer type.
466e5dd7070Spatrick /// Note that this function may produce an error message.
467e5dd7070Spatrick /// \return true if the Decl is a pointer type; false otherwise
threadSafetyCheckIsPointer(Sema & S,const Decl * D,const ParsedAttr & AL)468e5dd7070Spatrick static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
469e5dd7070Spatrick const ParsedAttr &AL) {
470e5dd7070Spatrick const auto *VD = cast<ValueDecl>(D);
471e5dd7070Spatrick QualType QT = VD->getType();
472e5dd7070Spatrick if (QT->isAnyPointerType())
473e5dd7070Spatrick return true;
474e5dd7070Spatrick
475e5dd7070Spatrick if (const auto *RT = QT->getAs<RecordType>()) {
476e5dd7070Spatrick // If it's an incomplete type, it could be a smart pointer; skip it.
477e5dd7070Spatrick // (We don't want to force template instantiation if we can avoid it,
478e5dd7070Spatrick // since that would alter the order in which templates are instantiated.)
479e5dd7070Spatrick if (RT->isIncompleteType())
480e5dd7070Spatrick return true;
481e5dd7070Spatrick
482e5dd7070Spatrick if (threadSafetyCheckIsSmartPointer(S, RT))
483e5dd7070Spatrick return true;
484e5dd7070Spatrick }
485e5dd7070Spatrick
486e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) << AL << QT;
487e5dd7070Spatrick return false;
488e5dd7070Spatrick }
489e5dd7070Spatrick
490e5dd7070Spatrick /// Checks that the passed in QualType either is of RecordType or points
491e5dd7070Spatrick /// to RecordType. Returns the relevant RecordType, null if it does not exit.
getRecordType(QualType QT)492e5dd7070Spatrick static const RecordType *getRecordType(QualType QT) {
493e5dd7070Spatrick if (const auto *RT = QT->getAs<RecordType>())
494e5dd7070Spatrick return RT;
495e5dd7070Spatrick
496e5dd7070Spatrick // Now check if we point to record type.
497e5dd7070Spatrick if (const auto *PT = QT->getAs<PointerType>())
498e5dd7070Spatrick return PT->getPointeeType()->getAs<RecordType>();
499e5dd7070Spatrick
500e5dd7070Spatrick return nullptr;
501e5dd7070Spatrick }
502e5dd7070Spatrick
503e5dd7070Spatrick template <typename AttrType>
checkRecordDeclForAttr(const RecordDecl * RD)504e5dd7070Spatrick static bool checkRecordDeclForAttr(const RecordDecl *RD) {
505e5dd7070Spatrick // Check if the record itself has the attribute.
506e5dd7070Spatrick if (RD->hasAttr<AttrType>())
507e5dd7070Spatrick return true;
508e5dd7070Spatrick
509e5dd7070Spatrick // Else check if any base classes have the attribute.
510e5dd7070Spatrick if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) {
511a0747c9fSpatrick if (!CRD->forallBases([](const CXXRecordDecl *Base) {
512a0747c9fSpatrick return !Base->hasAttr<AttrType>();
513a0747c9fSpatrick }))
514e5dd7070Spatrick return true;
515e5dd7070Spatrick }
516e5dd7070Spatrick return false;
517e5dd7070Spatrick }
518e5dd7070Spatrick
checkRecordTypeForCapability(Sema & S,QualType Ty)519e5dd7070Spatrick static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
520e5dd7070Spatrick const RecordType *RT = getRecordType(Ty);
521e5dd7070Spatrick
522e5dd7070Spatrick if (!RT)
523e5dd7070Spatrick return false;
524e5dd7070Spatrick
525e5dd7070Spatrick // Don't check for the capability if the class hasn't been defined yet.
526e5dd7070Spatrick if (RT->isIncompleteType())
527e5dd7070Spatrick return true;
528e5dd7070Spatrick
529e5dd7070Spatrick // Allow smart pointers to be used as capability objects.
530e5dd7070Spatrick // FIXME -- Check the type that the smart pointer points to.
531e5dd7070Spatrick if (threadSafetyCheckIsSmartPointer(S, RT))
532e5dd7070Spatrick return true;
533e5dd7070Spatrick
534e5dd7070Spatrick return checkRecordDeclForAttr<CapabilityAttr>(RT->getDecl());
535e5dd7070Spatrick }
536e5dd7070Spatrick
checkTypedefTypeForCapability(QualType Ty)537e5dd7070Spatrick static bool checkTypedefTypeForCapability(QualType Ty) {
538e5dd7070Spatrick const auto *TD = Ty->getAs<TypedefType>();
539e5dd7070Spatrick if (!TD)
540e5dd7070Spatrick return false;
541e5dd7070Spatrick
542e5dd7070Spatrick TypedefNameDecl *TN = TD->getDecl();
543e5dd7070Spatrick if (!TN)
544e5dd7070Spatrick return false;
545e5dd7070Spatrick
546e5dd7070Spatrick return TN->hasAttr<CapabilityAttr>();
547e5dd7070Spatrick }
548e5dd7070Spatrick
typeHasCapability(Sema & S,QualType Ty)549e5dd7070Spatrick static bool typeHasCapability(Sema &S, QualType Ty) {
550e5dd7070Spatrick if (checkTypedefTypeForCapability(Ty))
551e5dd7070Spatrick return true;
552e5dd7070Spatrick
553e5dd7070Spatrick if (checkRecordTypeForCapability(S, Ty))
554e5dd7070Spatrick return true;
555e5dd7070Spatrick
556e5dd7070Spatrick return false;
557e5dd7070Spatrick }
558e5dd7070Spatrick
isCapabilityExpr(Sema & S,const Expr * Ex)559e5dd7070Spatrick static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
560e5dd7070Spatrick // Capability expressions are simple expressions involving the boolean logic
561e5dd7070Spatrick // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once
562e5dd7070Spatrick // a DeclRefExpr is found, its type should be checked to determine whether it
563e5dd7070Spatrick // is a capability or not.
564e5dd7070Spatrick
565e5dd7070Spatrick if (const auto *E = dyn_cast<CastExpr>(Ex))
566e5dd7070Spatrick return isCapabilityExpr(S, E->getSubExpr());
567e5dd7070Spatrick else if (const auto *E = dyn_cast<ParenExpr>(Ex))
568e5dd7070Spatrick return isCapabilityExpr(S, E->getSubExpr());
569e5dd7070Spatrick else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
570e5dd7070Spatrick if (E->getOpcode() == UO_LNot || E->getOpcode() == UO_AddrOf ||
571e5dd7070Spatrick E->getOpcode() == UO_Deref)
572e5dd7070Spatrick return isCapabilityExpr(S, E->getSubExpr());
573e5dd7070Spatrick return false;
574e5dd7070Spatrick } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) {
575e5dd7070Spatrick if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr)
576e5dd7070Spatrick return isCapabilityExpr(S, E->getLHS()) &&
577e5dd7070Spatrick isCapabilityExpr(S, E->getRHS());
578e5dd7070Spatrick return false;
579e5dd7070Spatrick }
580e5dd7070Spatrick
581e5dd7070Spatrick return typeHasCapability(S, Ex->getType());
582e5dd7070Spatrick }
583e5dd7070Spatrick
584e5dd7070Spatrick /// Checks that all attribute arguments, starting from Sidx, resolve to
585e5dd7070Spatrick /// a capability object.
586e5dd7070Spatrick /// \param Sidx The attribute argument index to start checking with.
587e5dd7070Spatrick /// \param ParamIdxOk Whether an argument can be indexing into a function
588e5dd7070Spatrick /// parameter list.
checkAttrArgsAreCapabilityObjs(Sema & S,Decl * D,const ParsedAttr & AL,SmallVectorImpl<Expr * > & Args,unsigned Sidx=0,bool ParamIdxOk=false)589e5dd7070Spatrick static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
590e5dd7070Spatrick const ParsedAttr &AL,
591e5dd7070Spatrick SmallVectorImpl<Expr *> &Args,
592e5dd7070Spatrick unsigned Sidx = 0,
593e5dd7070Spatrick bool ParamIdxOk = false) {
594e5dd7070Spatrick if (Sidx == AL.getNumArgs()) {
595e5dd7070Spatrick // If we don't have any capability arguments, the attribute implicitly
596e5dd7070Spatrick // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're
597e5dd7070Spatrick // a non-static method, and that the class is a (scoped) capability.
598e5dd7070Spatrick const auto *MD = dyn_cast<const CXXMethodDecl>(D);
599e5dd7070Spatrick if (MD && !MD->isStatic()) {
600e5dd7070Spatrick const CXXRecordDecl *RD = MD->getParent();
601e5dd7070Spatrick // FIXME -- need to check this again on template instantiation
602e5dd7070Spatrick if (!checkRecordDeclForAttr<CapabilityAttr>(RD) &&
603e5dd7070Spatrick !checkRecordDeclForAttr<ScopedLockableAttr>(RD))
604e5dd7070Spatrick S.Diag(AL.getLoc(),
605e5dd7070Spatrick diag::warn_thread_attribute_not_on_capability_member)
606e5dd7070Spatrick << AL << MD->getParent();
607e5dd7070Spatrick } else {
608e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member)
609e5dd7070Spatrick << AL;
610e5dd7070Spatrick }
611e5dd7070Spatrick }
612e5dd7070Spatrick
613e5dd7070Spatrick for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) {
614e5dd7070Spatrick Expr *ArgExp = AL.getArgAsExpr(Idx);
615e5dd7070Spatrick
616e5dd7070Spatrick if (ArgExp->isTypeDependent()) {
617e5dd7070Spatrick // FIXME -- need to check this again on template instantiation
618e5dd7070Spatrick Args.push_back(ArgExp);
619e5dd7070Spatrick continue;
620e5dd7070Spatrick }
621e5dd7070Spatrick
622e5dd7070Spatrick if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
623e5dd7070Spatrick if (StrLit->getLength() == 0 ||
624*7a9b00ceSrobert (StrLit->isOrdinary() && StrLit->getString() == StringRef("*"))) {
625e5dd7070Spatrick // Pass empty strings to the analyzer without warnings.
626e5dd7070Spatrick // Treat "*" as the universal lock.
627e5dd7070Spatrick Args.push_back(ArgExp);
628e5dd7070Spatrick continue;
629e5dd7070Spatrick }
630e5dd7070Spatrick
631e5dd7070Spatrick // We allow constant strings to be used as a placeholder for expressions
632e5dd7070Spatrick // that are not valid C++ syntax, but warn that they are ignored.
633e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL;
634e5dd7070Spatrick Args.push_back(ArgExp);
635e5dd7070Spatrick continue;
636e5dd7070Spatrick }
637e5dd7070Spatrick
638e5dd7070Spatrick QualType ArgTy = ArgExp->getType();
639e5dd7070Spatrick
640e5dd7070Spatrick // A pointer to member expression of the form &MyClass::mu is treated
641e5dd7070Spatrick // specially -- we need to look at the type of the member.
642e5dd7070Spatrick if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp))
643e5dd7070Spatrick if (UOp->getOpcode() == UO_AddrOf)
644e5dd7070Spatrick if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
645e5dd7070Spatrick if (DRE->getDecl()->isCXXInstanceMember())
646e5dd7070Spatrick ArgTy = DRE->getDecl()->getType();
647e5dd7070Spatrick
648e5dd7070Spatrick // First see if we can just cast to record type, or pointer to record type.
649e5dd7070Spatrick const RecordType *RT = getRecordType(ArgTy);
650e5dd7070Spatrick
651e5dd7070Spatrick // Now check if we index into a record type function param.
652e5dd7070Spatrick if(!RT && ParamIdxOk) {
653e5dd7070Spatrick const auto *FD = dyn_cast<FunctionDecl>(D);
654e5dd7070Spatrick const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
655e5dd7070Spatrick if(FD && IL) {
656e5dd7070Spatrick unsigned int NumParams = FD->getNumParams();
657e5dd7070Spatrick llvm::APInt ArgValue = IL->getValue();
658e5dd7070Spatrick uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
659e5dd7070Spatrick uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
660e5dd7070Spatrick if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
661e5dd7070Spatrick S.Diag(AL.getLoc(),
662e5dd7070Spatrick diag::err_attribute_argument_out_of_bounds_extra_info)
663e5dd7070Spatrick << AL << Idx + 1 << NumParams;
664e5dd7070Spatrick continue;
665e5dd7070Spatrick }
666e5dd7070Spatrick ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
667e5dd7070Spatrick }
668e5dd7070Spatrick }
669e5dd7070Spatrick
670e5dd7070Spatrick // If the type does not have a capability, see if the components of the
671e5dd7070Spatrick // expression have capabilities. This allows for writing C code where the
672e5dd7070Spatrick // capability may be on the type, and the expression is a capability
673e5dd7070Spatrick // boolean logic expression. Eg) requires_capability(A || B && !C)
674e5dd7070Spatrick if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
675e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
676e5dd7070Spatrick << AL << ArgTy;
677e5dd7070Spatrick
678e5dd7070Spatrick Args.push_back(ArgExp);
679e5dd7070Spatrick }
680e5dd7070Spatrick }
681e5dd7070Spatrick
682e5dd7070Spatrick //===----------------------------------------------------------------------===//
683e5dd7070Spatrick // Attribute Implementations
684e5dd7070Spatrick //===----------------------------------------------------------------------===//
685e5dd7070Spatrick
handlePtGuardedVarAttr(Sema & S,Decl * D,const ParsedAttr & AL)686e5dd7070Spatrick static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
687e5dd7070Spatrick if (!threadSafetyCheckIsPointer(S, D, AL))
688e5dd7070Spatrick return;
689e5dd7070Spatrick
690e5dd7070Spatrick D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL));
691e5dd7070Spatrick }
692e5dd7070Spatrick
checkGuardedByAttrCommon(Sema & S,Decl * D,const ParsedAttr & AL,Expr * & Arg)693e5dd7070Spatrick static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
694e5dd7070Spatrick Expr *&Arg) {
695e5dd7070Spatrick SmallVector<Expr *, 1> Args;
696e5dd7070Spatrick // check that all arguments are lockable objects
697e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
698e5dd7070Spatrick unsigned Size = Args.size();
699e5dd7070Spatrick if (Size != 1)
700e5dd7070Spatrick return false;
701e5dd7070Spatrick
702e5dd7070Spatrick Arg = Args[0];
703e5dd7070Spatrick
704e5dd7070Spatrick return true;
705e5dd7070Spatrick }
706e5dd7070Spatrick
handleGuardedByAttr(Sema & S,Decl * D,const ParsedAttr & AL)707e5dd7070Spatrick static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
708e5dd7070Spatrick Expr *Arg = nullptr;
709e5dd7070Spatrick if (!checkGuardedByAttrCommon(S, D, AL, Arg))
710e5dd7070Spatrick return;
711e5dd7070Spatrick
712e5dd7070Spatrick D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg));
713e5dd7070Spatrick }
714e5dd7070Spatrick
handlePtGuardedByAttr(Sema & S,Decl * D,const ParsedAttr & AL)715e5dd7070Spatrick static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
716e5dd7070Spatrick Expr *Arg = nullptr;
717e5dd7070Spatrick if (!checkGuardedByAttrCommon(S, D, AL, Arg))
718e5dd7070Spatrick return;
719e5dd7070Spatrick
720e5dd7070Spatrick if (!threadSafetyCheckIsPointer(S, D, AL))
721e5dd7070Spatrick return;
722e5dd7070Spatrick
723e5dd7070Spatrick D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg));
724e5dd7070Spatrick }
725e5dd7070Spatrick
checkAcquireOrderAttrCommon(Sema & S,Decl * D,const ParsedAttr & AL,SmallVectorImpl<Expr * > & Args)726e5dd7070Spatrick static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
727e5dd7070Spatrick SmallVectorImpl<Expr *> &Args) {
728a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
729e5dd7070Spatrick return false;
730e5dd7070Spatrick
731e5dd7070Spatrick // Check that this attribute only applies to lockable types.
732e5dd7070Spatrick QualType QT = cast<ValueDecl>(D)->getType();
733e5dd7070Spatrick if (!QT->isDependentType() && !typeHasCapability(S, QT)) {
734e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << AL;
735e5dd7070Spatrick return false;
736e5dd7070Spatrick }
737e5dd7070Spatrick
738e5dd7070Spatrick // Check that all arguments are lockable objects.
739e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
740e5dd7070Spatrick if (Args.empty())
741e5dd7070Spatrick return false;
742e5dd7070Spatrick
743e5dd7070Spatrick return true;
744e5dd7070Spatrick }
745e5dd7070Spatrick
handleAcquiredAfterAttr(Sema & S,Decl * D,const ParsedAttr & AL)746e5dd7070Spatrick static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
747e5dd7070Spatrick SmallVector<Expr *, 1> Args;
748e5dd7070Spatrick if (!checkAcquireOrderAttrCommon(S, D, AL, Args))
749e5dd7070Spatrick return;
750e5dd7070Spatrick
751e5dd7070Spatrick Expr **StartArg = &Args[0];
752e5dd7070Spatrick D->addAttr(::new (S.Context)
753e5dd7070Spatrick AcquiredAfterAttr(S.Context, AL, StartArg, Args.size()));
754e5dd7070Spatrick }
755e5dd7070Spatrick
handleAcquiredBeforeAttr(Sema & S,Decl * D,const ParsedAttr & AL)756e5dd7070Spatrick static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
757e5dd7070Spatrick SmallVector<Expr *, 1> Args;
758e5dd7070Spatrick if (!checkAcquireOrderAttrCommon(S, D, AL, Args))
759e5dd7070Spatrick return;
760e5dd7070Spatrick
761e5dd7070Spatrick Expr **StartArg = &Args[0];
762e5dd7070Spatrick D->addAttr(::new (S.Context)
763e5dd7070Spatrick AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size()));
764e5dd7070Spatrick }
765e5dd7070Spatrick
checkLockFunAttrCommon(Sema & S,Decl * D,const ParsedAttr & AL,SmallVectorImpl<Expr * > & Args)766e5dd7070Spatrick static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
767e5dd7070Spatrick SmallVectorImpl<Expr *> &Args) {
768e5dd7070Spatrick // zero or more arguments ok
769e5dd7070Spatrick // check that all arguments are lockable objects
770e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true);
771e5dd7070Spatrick
772e5dd7070Spatrick return true;
773e5dd7070Spatrick }
774e5dd7070Spatrick
handleAssertSharedLockAttr(Sema & S,Decl * D,const ParsedAttr & AL)775e5dd7070Spatrick static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
776e5dd7070Spatrick SmallVector<Expr *, 1> Args;
777e5dd7070Spatrick if (!checkLockFunAttrCommon(S, D, AL, Args))
778e5dd7070Spatrick return;
779e5dd7070Spatrick
780e5dd7070Spatrick unsigned Size = Args.size();
781e5dd7070Spatrick Expr **StartArg = Size == 0 ? nullptr : &Args[0];
782e5dd7070Spatrick D->addAttr(::new (S.Context)
783e5dd7070Spatrick AssertSharedLockAttr(S.Context, AL, StartArg, Size));
784e5dd7070Spatrick }
785e5dd7070Spatrick
handleAssertExclusiveLockAttr(Sema & S,Decl * D,const ParsedAttr & AL)786e5dd7070Spatrick static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
787e5dd7070Spatrick const ParsedAttr &AL) {
788e5dd7070Spatrick SmallVector<Expr *, 1> Args;
789e5dd7070Spatrick if (!checkLockFunAttrCommon(S, D, AL, Args))
790e5dd7070Spatrick return;
791e5dd7070Spatrick
792e5dd7070Spatrick unsigned Size = Args.size();
793e5dd7070Spatrick Expr **StartArg = Size == 0 ? nullptr : &Args[0];
794e5dd7070Spatrick D->addAttr(::new (S.Context)
795e5dd7070Spatrick AssertExclusiveLockAttr(S.Context, AL, StartArg, Size));
796e5dd7070Spatrick }
797e5dd7070Spatrick
798e5dd7070Spatrick /// Checks to be sure that the given parameter number is in bounds, and
799e5dd7070Spatrick /// is an integral type. Will emit appropriate diagnostics if this returns
800e5dd7070Spatrick /// false.
801e5dd7070Spatrick ///
802e5dd7070Spatrick /// AttrArgNo is used to actually retrieve the argument, so it's base-0.
803e5dd7070Spatrick template <typename AttrInfo>
checkParamIsIntegerType(Sema & S,const Decl * D,const AttrInfo & AI,unsigned AttrArgNo)804a0747c9fSpatrick static bool checkParamIsIntegerType(Sema &S, const Decl *D, const AttrInfo &AI,
805a0747c9fSpatrick unsigned AttrArgNo) {
806e5dd7070Spatrick assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument");
807e5dd7070Spatrick Expr *AttrArg = AI.getArgAsExpr(AttrArgNo);
808e5dd7070Spatrick ParamIdx Idx;
809a0747c9fSpatrick if (!checkFunctionOrMethodParameterIndex(S, D, AI, AttrArgNo + 1, AttrArg,
810e5dd7070Spatrick Idx))
811e5dd7070Spatrick return false;
812e5dd7070Spatrick
813a0747c9fSpatrick QualType ParamTy = getFunctionOrMethodParamType(D, Idx.getASTIndex());
814a0747c9fSpatrick if (!ParamTy->isIntegerType() && !ParamTy->isCharType()) {
815e5dd7070Spatrick SourceLocation SrcLoc = AttrArg->getBeginLoc();
816e5dd7070Spatrick S.Diag(SrcLoc, diag::err_attribute_integers_only)
817a0747c9fSpatrick << AI << getFunctionOrMethodParamRange(D, Idx.getASTIndex());
818e5dd7070Spatrick return false;
819e5dd7070Spatrick }
820e5dd7070Spatrick return true;
821e5dd7070Spatrick }
822e5dd7070Spatrick
handleAllocSizeAttr(Sema & S,Decl * D,const ParsedAttr & AL)823e5dd7070Spatrick static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
824a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
825e5dd7070Spatrick return;
826e5dd7070Spatrick
827a0747c9fSpatrick assert(isFunctionOrMethod(D) && hasFunctionProto(D));
828a0747c9fSpatrick
829a0747c9fSpatrick QualType RetTy = getFunctionOrMethodResultType(D);
830a0747c9fSpatrick if (!RetTy->isPointerType()) {
831e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) << AL;
832e5dd7070Spatrick return;
833e5dd7070Spatrick }
834e5dd7070Spatrick
835e5dd7070Spatrick const Expr *SizeExpr = AL.getArgAsExpr(0);
836e5dd7070Spatrick int SizeArgNoVal;
837e5dd7070Spatrick // Parameter indices are 1-indexed, hence Index=1
838e5dd7070Spatrick if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Idx=*/1))
839e5dd7070Spatrick return;
840a0747c9fSpatrick if (!checkParamIsIntegerType(S, D, AL, /*AttrArgNo=*/0))
841e5dd7070Spatrick return;
842e5dd7070Spatrick ParamIdx SizeArgNo(SizeArgNoVal, D);
843e5dd7070Spatrick
844e5dd7070Spatrick ParamIdx NumberArgNo;
845e5dd7070Spatrick if (AL.getNumArgs() == 2) {
846e5dd7070Spatrick const Expr *NumberExpr = AL.getArgAsExpr(1);
847e5dd7070Spatrick int Val;
848e5dd7070Spatrick // Parameter indices are 1-based, hence Index=2
849e5dd7070Spatrick if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Idx=*/2))
850e5dd7070Spatrick return;
851a0747c9fSpatrick if (!checkParamIsIntegerType(S, D, AL, /*AttrArgNo=*/1))
852e5dd7070Spatrick return;
853e5dd7070Spatrick NumberArgNo = ParamIdx(Val, D);
854e5dd7070Spatrick }
855e5dd7070Spatrick
856e5dd7070Spatrick D->addAttr(::new (S.Context)
857e5dd7070Spatrick AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo));
858e5dd7070Spatrick }
859e5dd7070Spatrick
checkTryLockFunAttrCommon(Sema & S,Decl * D,const ParsedAttr & AL,SmallVectorImpl<Expr * > & Args)860e5dd7070Spatrick static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
861e5dd7070Spatrick SmallVectorImpl<Expr *> &Args) {
862a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
863e5dd7070Spatrick return false;
864e5dd7070Spatrick
865e5dd7070Spatrick if (!isIntOrBool(AL.getArgAsExpr(0))) {
866e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
867e5dd7070Spatrick << AL << 1 << AANT_ArgumentIntOrBool;
868e5dd7070Spatrick return false;
869e5dd7070Spatrick }
870e5dd7070Spatrick
871e5dd7070Spatrick // check that all arguments are lockable objects
872e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1);
873e5dd7070Spatrick
874e5dd7070Spatrick return true;
875e5dd7070Spatrick }
876e5dd7070Spatrick
handleSharedTrylockFunctionAttr(Sema & S,Decl * D,const ParsedAttr & AL)877e5dd7070Spatrick static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
878e5dd7070Spatrick const ParsedAttr &AL) {
879e5dd7070Spatrick SmallVector<Expr*, 2> Args;
880e5dd7070Spatrick if (!checkTryLockFunAttrCommon(S, D, AL, Args))
881e5dd7070Spatrick return;
882e5dd7070Spatrick
883e5dd7070Spatrick D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(
884e5dd7070Spatrick S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
885e5dd7070Spatrick }
886e5dd7070Spatrick
handleExclusiveTrylockFunctionAttr(Sema & S,Decl * D,const ParsedAttr & AL)887e5dd7070Spatrick static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
888e5dd7070Spatrick const ParsedAttr &AL) {
889e5dd7070Spatrick SmallVector<Expr*, 2> Args;
890e5dd7070Spatrick if (!checkTryLockFunAttrCommon(S, D, AL, Args))
891e5dd7070Spatrick return;
892e5dd7070Spatrick
893e5dd7070Spatrick D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
894e5dd7070Spatrick S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
895e5dd7070Spatrick }
896e5dd7070Spatrick
handleLockReturnedAttr(Sema & S,Decl * D,const ParsedAttr & AL)897e5dd7070Spatrick static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
898e5dd7070Spatrick // check that the argument is lockable object
899e5dd7070Spatrick SmallVector<Expr*, 1> Args;
900e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
901e5dd7070Spatrick unsigned Size = Args.size();
902e5dd7070Spatrick if (Size == 0)
903e5dd7070Spatrick return;
904e5dd7070Spatrick
905e5dd7070Spatrick D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0]));
906e5dd7070Spatrick }
907e5dd7070Spatrick
handleLocksExcludedAttr(Sema & S,Decl * D,const ParsedAttr & AL)908e5dd7070Spatrick static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
909a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
910e5dd7070Spatrick return;
911e5dd7070Spatrick
912e5dd7070Spatrick // check that all arguments are lockable objects
913e5dd7070Spatrick SmallVector<Expr*, 1> Args;
914e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
915e5dd7070Spatrick unsigned Size = Args.size();
916e5dd7070Spatrick if (Size == 0)
917e5dd7070Spatrick return;
918e5dd7070Spatrick Expr **StartArg = &Args[0];
919e5dd7070Spatrick
920e5dd7070Spatrick D->addAttr(::new (S.Context)
921e5dd7070Spatrick LocksExcludedAttr(S.Context, AL, StartArg, Size));
922e5dd7070Spatrick }
923e5dd7070Spatrick
checkFunctionConditionAttr(Sema & S,Decl * D,const ParsedAttr & AL,Expr * & Cond,StringRef & Msg)924e5dd7070Spatrick static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL,
925e5dd7070Spatrick Expr *&Cond, StringRef &Msg) {
926e5dd7070Spatrick Cond = AL.getArgAsExpr(0);
927e5dd7070Spatrick if (!Cond->isTypeDependent()) {
928e5dd7070Spatrick ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
929e5dd7070Spatrick if (Converted.isInvalid())
930e5dd7070Spatrick return false;
931e5dd7070Spatrick Cond = Converted.get();
932e5dd7070Spatrick }
933e5dd7070Spatrick
934e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg))
935e5dd7070Spatrick return false;
936e5dd7070Spatrick
937e5dd7070Spatrick if (Msg.empty())
938e5dd7070Spatrick Msg = "<no message provided>";
939e5dd7070Spatrick
940e5dd7070Spatrick SmallVector<PartialDiagnosticAt, 8> Diags;
941e5dd7070Spatrick if (isa<FunctionDecl>(D) && !Cond->isValueDependent() &&
942e5dd7070Spatrick !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
943e5dd7070Spatrick Diags)) {
944e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) << AL;
945e5dd7070Spatrick for (const PartialDiagnosticAt &PDiag : Diags)
946e5dd7070Spatrick S.Diag(PDiag.first, PDiag.second);
947e5dd7070Spatrick return false;
948e5dd7070Spatrick }
949e5dd7070Spatrick return true;
950e5dd7070Spatrick }
951e5dd7070Spatrick
handleEnableIfAttr(Sema & S,Decl * D,const ParsedAttr & AL)952e5dd7070Spatrick static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
953e5dd7070Spatrick S.Diag(AL.getLoc(), diag::ext_clang_enable_if);
954e5dd7070Spatrick
955e5dd7070Spatrick Expr *Cond;
956e5dd7070Spatrick StringRef Msg;
957e5dd7070Spatrick if (checkFunctionConditionAttr(S, D, AL, Cond, Msg))
958e5dd7070Spatrick D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg));
959e5dd7070Spatrick }
960e5dd7070Spatrick
handleErrorAttr(Sema & S,Decl * D,const ParsedAttr & AL)961*7a9b00ceSrobert static void handleErrorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
962*7a9b00ceSrobert StringRef NewUserDiagnostic;
963*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, NewUserDiagnostic))
964*7a9b00ceSrobert return;
965*7a9b00ceSrobert if (ErrorAttr *EA = S.mergeErrorAttr(D, AL, NewUserDiagnostic))
966*7a9b00ceSrobert D->addAttr(EA);
967*7a9b00ceSrobert }
968*7a9b00ceSrobert
969e5dd7070Spatrick namespace {
970e5dd7070Spatrick /// Determines if a given Expr references any of the given function's
971e5dd7070Spatrick /// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
972e5dd7070Spatrick class ArgumentDependenceChecker
973e5dd7070Spatrick : public RecursiveASTVisitor<ArgumentDependenceChecker> {
974e5dd7070Spatrick #ifndef NDEBUG
975e5dd7070Spatrick const CXXRecordDecl *ClassType;
976e5dd7070Spatrick #endif
977e5dd7070Spatrick llvm::SmallPtrSet<const ParmVarDecl *, 16> Parms;
978e5dd7070Spatrick bool Result;
979e5dd7070Spatrick
980e5dd7070Spatrick public:
ArgumentDependenceChecker(const FunctionDecl * FD)981e5dd7070Spatrick ArgumentDependenceChecker(const FunctionDecl *FD) {
982e5dd7070Spatrick #ifndef NDEBUG
983e5dd7070Spatrick if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
984e5dd7070Spatrick ClassType = MD->getParent();
985e5dd7070Spatrick else
986e5dd7070Spatrick ClassType = nullptr;
987e5dd7070Spatrick #endif
988e5dd7070Spatrick Parms.insert(FD->param_begin(), FD->param_end());
989e5dd7070Spatrick }
990e5dd7070Spatrick
referencesArgs(Expr * E)991e5dd7070Spatrick bool referencesArgs(Expr *E) {
992e5dd7070Spatrick Result = false;
993e5dd7070Spatrick TraverseStmt(E);
994e5dd7070Spatrick return Result;
995e5dd7070Spatrick }
996e5dd7070Spatrick
VisitCXXThisExpr(CXXThisExpr * E)997e5dd7070Spatrick bool VisitCXXThisExpr(CXXThisExpr *E) {
998e5dd7070Spatrick assert(E->getType()->getPointeeCXXRecordDecl() == ClassType &&
999e5dd7070Spatrick "`this` doesn't refer to the enclosing class?");
1000e5dd7070Spatrick Result = true;
1001e5dd7070Spatrick return false;
1002e5dd7070Spatrick }
1003e5dd7070Spatrick
VisitDeclRefExpr(DeclRefExpr * DRE)1004e5dd7070Spatrick bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1005e5dd7070Spatrick if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
1006e5dd7070Spatrick if (Parms.count(PVD)) {
1007e5dd7070Spatrick Result = true;
1008e5dd7070Spatrick return false;
1009e5dd7070Spatrick }
1010e5dd7070Spatrick return true;
1011e5dd7070Spatrick }
1012e5dd7070Spatrick };
1013e5dd7070Spatrick }
1014e5dd7070Spatrick
handleDiagnoseAsBuiltinAttr(Sema & S,Decl * D,const ParsedAttr & AL)1015*7a9b00ceSrobert static void handleDiagnoseAsBuiltinAttr(Sema &S, Decl *D,
1016*7a9b00ceSrobert const ParsedAttr &AL) {
1017*7a9b00ceSrobert const auto *DeclFD = cast<FunctionDecl>(D);
1018*7a9b00ceSrobert
1019*7a9b00ceSrobert if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(DeclFD))
1020*7a9b00ceSrobert if (!MethodDecl->isStatic()) {
1021*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_no_member_function) << AL;
1022*7a9b00ceSrobert return;
1023*7a9b00ceSrobert }
1024*7a9b00ceSrobert
1025*7a9b00ceSrobert auto DiagnoseType = [&](unsigned Index, AttributeArgumentNType T) {
1026*7a9b00ceSrobert SourceLocation Loc = [&]() {
1027*7a9b00ceSrobert auto Union = AL.getArg(Index - 1);
1028*7a9b00ceSrobert if (Union.is<Expr *>())
1029*7a9b00ceSrobert return Union.get<Expr *>()->getBeginLoc();
1030*7a9b00ceSrobert return Union.get<IdentifierLoc *>()->Loc;
1031*7a9b00ceSrobert }();
1032*7a9b00ceSrobert
1033*7a9b00ceSrobert S.Diag(Loc, diag::err_attribute_argument_n_type) << AL << Index << T;
1034*7a9b00ceSrobert };
1035*7a9b00ceSrobert
1036*7a9b00ceSrobert FunctionDecl *AttrFD = [&]() -> FunctionDecl * {
1037*7a9b00ceSrobert if (!AL.isArgExpr(0))
1038*7a9b00ceSrobert return nullptr;
1039*7a9b00ceSrobert auto *F = dyn_cast_or_null<DeclRefExpr>(AL.getArgAsExpr(0));
1040*7a9b00ceSrobert if (!F)
1041*7a9b00ceSrobert return nullptr;
1042*7a9b00ceSrobert return dyn_cast_or_null<FunctionDecl>(F->getFoundDecl());
1043*7a9b00ceSrobert }();
1044*7a9b00ceSrobert
1045*7a9b00ceSrobert if (!AttrFD || !AttrFD->getBuiltinID(true)) {
1046*7a9b00ceSrobert DiagnoseType(1, AANT_ArgumentBuiltinFunction);
1047*7a9b00ceSrobert return;
1048*7a9b00ceSrobert }
1049*7a9b00ceSrobert
1050*7a9b00ceSrobert if (AttrFD->getNumParams() != AL.getNumArgs() - 1) {
1051*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments_for)
1052*7a9b00ceSrobert << AL << AttrFD << AttrFD->getNumParams();
1053*7a9b00ceSrobert return;
1054*7a9b00ceSrobert }
1055*7a9b00ceSrobert
1056*7a9b00ceSrobert SmallVector<unsigned, 8> Indices;
1057*7a9b00ceSrobert
1058*7a9b00ceSrobert for (unsigned I = 1; I < AL.getNumArgs(); ++I) {
1059*7a9b00ceSrobert if (!AL.isArgExpr(I)) {
1060*7a9b00ceSrobert DiagnoseType(I + 1, AANT_ArgumentIntegerConstant);
1061*7a9b00ceSrobert return;
1062*7a9b00ceSrobert }
1063*7a9b00ceSrobert
1064*7a9b00ceSrobert const Expr *IndexExpr = AL.getArgAsExpr(I);
1065*7a9b00ceSrobert uint32_t Index;
1066*7a9b00ceSrobert
1067*7a9b00ceSrobert if (!checkUInt32Argument(S, AL, IndexExpr, Index, I + 1, false))
1068*7a9b00ceSrobert return;
1069*7a9b00ceSrobert
1070*7a9b00ceSrobert if (Index > DeclFD->getNumParams()) {
1071*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_bounds_for_function)
1072*7a9b00ceSrobert << AL << Index << DeclFD << DeclFD->getNumParams();
1073*7a9b00ceSrobert return;
1074*7a9b00ceSrobert }
1075*7a9b00ceSrobert
1076*7a9b00ceSrobert QualType T1 = AttrFD->getParamDecl(I - 1)->getType();
1077*7a9b00ceSrobert QualType T2 = DeclFD->getParamDecl(Index - 1)->getType();
1078*7a9b00ceSrobert
1079*7a9b00ceSrobert if (T1.getCanonicalType().getUnqualifiedType() !=
1080*7a9b00ceSrobert T2.getCanonicalType().getUnqualifiedType()) {
1081*7a9b00ceSrobert S.Diag(IndexExpr->getBeginLoc(), diag::err_attribute_parameter_types)
1082*7a9b00ceSrobert << AL << Index << DeclFD << T2 << I << AttrFD << T1;
1083*7a9b00ceSrobert return;
1084*7a9b00ceSrobert }
1085*7a9b00ceSrobert
1086*7a9b00ceSrobert Indices.push_back(Index - 1);
1087*7a9b00ceSrobert }
1088*7a9b00ceSrobert
1089*7a9b00ceSrobert D->addAttr(::new (S.Context) DiagnoseAsBuiltinAttr(
1090*7a9b00ceSrobert S.Context, AL, AttrFD, Indices.data(), Indices.size()));
1091*7a9b00ceSrobert }
1092*7a9b00ceSrobert
handleDiagnoseIfAttr(Sema & S,Decl * D,const ParsedAttr & AL)1093e5dd7070Spatrick static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1094e5dd7070Spatrick S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if);
1095e5dd7070Spatrick
1096e5dd7070Spatrick Expr *Cond;
1097e5dd7070Spatrick StringRef Msg;
1098e5dd7070Spatrick if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg))
1099e5dd7070Spatrick return;
1100e5dd7070Spatrick
1101e5dd7070Spatrick StringRef DiagTypeStr;
1102e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr))
1103e5dd7070Spatrick return;
1104e5dd7070Spatrick
1105e5dd7070Spatrick DiagnoseIfAttr::DiagnosticType DiagType;
1106e5dd7070Spatrick if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) {
1107e5dd7070Spatrick S.Diag(AL.getArgAsExpr(2)->getBeginLoc(),
1108e5dd7070Spatrick diag::err_diagnose_if_invalid_diagnostic_type);
1109e5dd7070Spatrick return;
1110e5dd7070Spatrick }
1111e5dd7070Spatrick
1112e5dd7070Spatrick bool ArgDependent = false;
1113e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D))
1114e5dd7070Spatrick ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
1115e5dd7070Spatrick D->addAttr(::new (S.Context) DiagnoseIfAttr(
1116e5dd7070Spatrick S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
1117e5dd7070Spatrick }
1118e5dd7070Spatrick
handleNoBuiltinAttr(Sema & S,Decl * D,const ParsedAttr & AL)1119e5dd7070Spatrick static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1120e5dd7070Spatrick static constexpr const StringRef kWildcard = "*";
1121e5dd7070Spatrick
1122e5dd7070Spatrick llvm::SmallVector<StringRef, 16> Names;
1123e5dd7070Spatrick bool HasWildcard = false;
1124e5dd7070Spatrick
1125e5dd7070Spatrick const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) {
1126e5dd7070Spatrick if (Name == kWildcard)
1127e5dd7070Spatrick HasWildcard = true;
1128e5dd7070Spatrick Names.push_back(Name);
1129e5dd7070Spatrick };
1130e5dd7070Spatrick
1131e5dd7070Spatrick // Add previously defined attributes.
1132e5dd7070Spatrick if (const auto *NBA = D->getAttr<NoBuiltinAttr>())
1133e5dd7070Spatrick for (StringRef BuiltinName : NBA->builtinNames())
1134e5dd7070Spatrick AddBuiltinName(BuiltinName);
1135e5dd7070Spatrick
1136e5dd7070Spatrick // Add current attributes.
1137e5dd7070Spatrick if (AL.getNumArgs() == 0)
1138e5dd7070Spatrick AddBuiltinName(kWildcard);
1139e5dd7070Spatrick else
1140e5dd7070Spatrick for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
1141e5dd7070Spatrick StringRef BuiltinName;
1142e5dd7070Spatrick SourceLocation LiteralLoc;
1143e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc))
1144e5dd7070Spatrick return;
1145e5dd7070Spatrick
1146e5dd7070Spatrick if (Builtin::Context::isBuiltinFunc(BuiltinName))
1147e5dd7070Spatrick AddBuiltinName(BuiltinName);
1148e5dd7070Spatrick else
1149e5dd7070Spatrick S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name)
1150ec727ea7Spatrick << BuiltinName << AL;
1151e5dd7070Spatrick }
1152e5dd7070Spatrick
1153e5dd7070Spatrick // Repeating the same attribute is fine.
1154e5dd7070Spatrick llvm::sort(Names);
1155e5dd7070Spatrick Names.erase(std::unique(Names.begin(), Names.end()), Names.end());
1156e5dd7070Spatrick
1157e5dd7070Spatrick // Empty no_builtin must be on its own.
1158e5dd7070Spatrick if (HasWildcard && Names.size() > 1)
1159e5dd7070Spatrick S.Diag(D->getLocation(),
1160e5dd7070Spatrick diag::err_attribute_no_builtin_wildcard_or_builtin_name)
1161ec727ea7Spatrick << AL;
1162e5dd7070Spatrick
1163e5dd7070Spatrick if (D->hasAttr<NoBuiltinAttr>())
1164e5dd7070Spatrick D->dropAttr<NoBuiltinAttr>();
1165e5dd7070Spatrick D->addAttr(::new (S.Context)
1166e5dd7070Spatrick NoBuiltinAttr(S.Context, AL, Names.data(), Names.size()));
1167e5dd7070Spatrick }
1168e5dd7070Spatrick
handlePassObjectSizeAttr(Sema & S,Decl * D,const ParsedAttr & AL)1169e5dd7070Spatrick static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1170e5dd7070Spatrick if (D->hasAttr<PassObjectSizeAttr>()) {
1171e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;
1172e5dd7070Spatrick return;
1173e5dd7070Spatrick }
1174e5dd7070Spatrick
1175e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
1176e5dd7070Spatrick uint32_t Type;
1177e5dd7070Spatrick if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1))
1178e5dd7070Spatrick return;
1179e5dd7070Spatrick
1180e5dd7070Spatrick // pass_object_size's argument is passed in as the second argument of
1181e5dd7070Spatrick // __builtin_object_size. So, it has the same constraints as that second
1182e5dd7070Spatrick // argument; namely, it must be in the range [0, 3].
1183e5dd7070Spatrick if (Type > 3) {
1184e5dd7070Spatrick S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range)
1185e5dd7070Spatrick << AL << 0 << 3 << E->getSourceRange();
1186e5dd7070Spatrick return;
1187e5dd7070Spatrick }
1188e5dd7070Spatrick
1189e5dd7070Spatrick // pass_object_size is only supported on constant pointer parameters; as a
1190e5dd7070Spatrick // kindness to users, we allow the parameter to be non-const for declarations.
1191e5dd7070Spatrick // At this point, we have no clue if `D` belongs to a function declaration or
1192e5dd7070Spatrick // definition, so we defer the constness check until later.
1193e5dd7070Spatrick if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) {
1194e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_attribute_pointers_only) << AL << 1;
1195e5dd7070Spatrick return;
1196e5dd7070Spatrick }
1197e5dd7070Spatrick
1198e5dd7070Spatrick D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type));
1199e5dd7070Spatrick }
1200e5dd7070Spatrick
handleConsumableAttr(Sema & S,Decl * D,const ParsedAttr & AL)1201e5dd7070Spatrick static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1202e5dd7070Spatrick ConsumableAttr::ConsumedState DefaultState;
1203e5dd7070Spatrick
1204e5dd7070Spatrick if (AL.isArgIdent(0)) {
1205e5dd7070Spatrick IdentifierLoc *IL = AL.getArgAsIdent(0);
1206e5dd7070Spatrick if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(),
1207e5dd7070Spatrick DefaultState)) {
1208e5dd7070Spatrick S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL
1209e5dd7070Spatrick << IL->Ident;
1210e5dd7070Spatrick return;
1211e5dd7070Spatrick }
1212e5dd7070Spatrick } else {
1213e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
1214e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
1215e5dd7070Spatrick return;
1216e5dd7070Spatrick }
1217e5dd7070Spatrick
1218e5dd7070Spatrick D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState));
1219e5dd7070Spatrick }
1220e5dd7070Spatrick
checkForConsumableClass(Sema & S,const CXXMethodDecl * MD,const ParsedAttr & AL)1221e5dd7070Spatrick static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
1222e5dd7070Spatrick const ParsedAttr &AL) {
1223e5dd7070Spatrick QualType ThisType = MD->getThisType()->getPointeeType();
1224e5dd7070Spatrick
1225e5dd7070Spatrick if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) {
1226e5dd7070Spatrick if (!RD->hasAttr<ConsumableAttr>()) {
1227ec727ea7Spatrick S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD;
1228e5dd7070Spatrick
1229e5dd7070Spatrick return false;
1230e5dd7070Spatrick }
1231e5dd7070Spatrick }
1232e5dd7070Spatrick
1233e5dd7070Spatrick return true;
1234e5dd7070Spatrick }
1235e5dd7070Spatrick
handleCallableWhenAttr(Sema & S,Decl * D,const ParsedAttr & AL)1236e5dd7070Spatrick static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1237a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
1238e5dd7070Spatrick return;
1239e5dd7070Spatrick
1240e5dd7070Spatrick if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
1241e5dd7070Spatrick return;
1242e5dd7070Spatrick
1243e5dd7070Spatrick SmallVector<CallableWhenAttr::ConsumedState, 3> States;
1244e5dd7070Spatrick for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) {
1245e5dd7070Spatrick CallableWhenAttr::ConsumedState CallableState;
1246e5dd7070Spatrick
1247e5dd7070Spatrick StringRef StateString;
1248e5dd7070Spatrick SourceLocation Loc;
1249e5dd7070Spatrick if (AL.isArgIdent(ArgIndex)) {
1250e5dd7070Spatrick IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex);
1251e5dd7070Spatrick StateString = Ident->Ident->getName();
1252e5dd7070Spatrick Loc = Ident->Loc;
1253e5dd7070Spatrick } else {
1254e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc))
1255e5dd7070Spatrick return;
1256e5dd7070Spatrick }
1257e5dd7070Spatrick
1258e5dd7070Spatrick if (!CallableWhenAttr::ConvertStrToConsumedState(StateString,
1259e5dd7070Spatrick CallableState)) {
1260e5dd7070Spatrick S.Diag(Loc, diag::warn_attribute_type_not_supported) << AL << StateString;
1261e5dd7070Spatrick return;
1262e5dd7070Spatrick }
1263e5dd7070Spatrick
1264e5dd7070Spatrick States.push_back(CallableState);
1265e5dd7070Spatrick }
1266e5dd7070Spatrick
1267e5dd7070Spatrick D->addAttr(::new (S.Context)
1268e5dd7070Spatrick CallableWhenAttr(S.Context, AL, States.data(), States.size()));
1269e5dd7070Spatrick }
1270e5dd7070Spatrick
handleParamTypestateAttr(Sema & S,Decl * D,const ParsedAttr & AL)1271e5dd7070Spatrick static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1272e5dd7070Spatrick ParamTypestateAttr::ConsumedState ParamState;
1273e5dd7070Spatrick
1274e5dd7070Spatrick if (AL.isArgIdent(0)) {
1275e5dd7070Spatrick IdentifierLoc *Ident = AL.getArgAsIdent(0);
1276e5dd7070Spatrick StringRef StateString = Ident->Ident->getName();
1277e5dd7070Spatrick
1278e5dd7070Spatrick if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString,
1279e5dd7070Spatrick ParamState)) {
1280e5dd7070Spatrick S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported)
1281e5dd7070Spatrick << AL << StateString;
1282e5dd7070Spatrick return;
1283e5dd7070Spatrick }
1284e5dd7070Spatrick } else {
1285e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
1286e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
1287e5dd7070Spatrick return;
1288e5dd7070Spatrick }
1289e5dd7070Spatrick
1290e5dd7070Spatrick // FIXME: This check is currently being done in the analysis. It can be
1291e5dd7070Spatrick // enabled here only after the parser propagates attributes at
1292e5dd7070Spatrick // template specialization definition, not declaration.
1293e5dd7070Spatrick //QualType ReturnType = cast<ParmVarDecl>(D)->getType();
1294e5dd7070Spatrick //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1295e5dd7070Spatrick //
1296e5dd7070Spatrick //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1297e5dd7070Spatrick // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
1298e5dd7070Spatrick // ReturnType.getAsString();
1299e5dd7070Spatrick // return;
1300e5dd7070Spatrick //}
1301e5dd7070Spatrick
1302e5dd7070Spatrick D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState));
1303e5dd7070Spatrick }
1304e5dd7070Spatrick
handleReturnTypestateAttr(Sema & S,Decl * D,const ParsedAttr & AL)1305e5dd7070Spatrick static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1306e5dd7070Spatrick ReturnTypestateAttr::ConsumedState ReturnState;
1307e5dd7070Spatrick
1308e5dd7070Spatrick if (AL.isArgIdent(0)) {
1309e5dd7070Spatrick IdentifierLoc *IL = AL.getArgAsIdent(0);
1310e5dd7070Spatrick if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(),
1311e5dd7070Spatrick ReturnState)) {
1312e5dd7070Spatrick S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL
1313e5dd7070Spatrick << IL->Ident;
1314e5dd7070Spatrick return;
1315e5dd7070Spatrick }
1316e5dd7070Spatrick } else {
1317e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
1318e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
1319e5dd7070Spatrick return;
1320e5dd7070Spatrick }
1321e5dd7070Spatrick
1322e5dd7070Spatrick // FIXME: This check is currently being done in the analysis. It can be
1323e5dd7070Spatrick // enabled here only after the parser propagates attributes at
1324e5dd7070Spatrick // template specialization definition, not declaration.
1325e5dd7070Spatrick //QualType ReturnType;
1326e5dd7070Spatrick //
1327e5dd7070Spatrick //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
1328e5dd7070Spatrick // ReturnType = Param->getType();
1329e5dd7070Spatrick //
1330e5dd7070Spatrick //} else if (const CXXConstructorDecl *Constructor =
1331e5dd7070Spatrick // dyn_cast<CXXConstructorDecl>(D)) {
1332e5dd7070Spatrick // ReturnType = Constructor->getThisType()->getPointeeType();
1333e5dd7070Spatrick //
1334e5dd7070Spatrick //} else {
1335e5dd7070Spatrick //
1336e5dd7070Spatrick // ReturnType = cast<FunctionDecl>(D)->getCallResultType();
1337e5dd7070Spatrick //}
1338e5dd7070Spatrick //
1339e5dd7070Spatrick //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1340e5dd7070Spatrick //
1341e5dd7070Spatrick //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1342e5dd7070Spatrick // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
1343e5dd7070Spatrick // ReturnType.getAsString();
1344e5dd7070Spatrick // return;
1345e5dd7070Spatrick //}
1346e5dd7070Spatrick
1347e5dd7070Spatrick D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState));
1348e5dd7070Spatrick }
1349e5dd7070Spatrick
handleSetTypestateAttr(Sema & S,Decl * D,const ParsedAttr & AL)1350e5dd7070Spatrick static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1351e5dd7070Spatrick if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
1352e5dd7070Spatrick return;
1353e5dd7070Spatrick
1354e5dd7070Spatrick SetTypestateAttr::ConsumedState NewState;
1355e5dd7070Spatrick if (AL.isArgIdent(0)) {
1356e5dd7070Spatrick IdentifierLoc *Ident = AL.getArgAsIdent(0);
1357e5dd7070Spatrick StringRef Param = Ident->Ident->getName();
1358e5dd7070Spatrick if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) {
1359e5dd7070Spatrick S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL
1360e5dd7070Spatrick << Param;
1361e5dd7070Spatrick return;
1362e5dd7070Spatrick }
1363e5dd7070Spatrick } else {
1364e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
1365e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
1366e5dd7070Spatrick return;
1367e5dd7070Spatrick }
1368e5dd7070Spatrick
1369e5dd7070Spatrick D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState));
1370e5dd7070Spatrick }
1371e5dd7070Spatrick
handleTestTypestateAttr(Sema & S,Decl * D,const ParsedAttr & AL)1372e5dd7070Spatrick static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1373e5dd7070Spatrick if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
1374e5dd7070Spatrick return;
1375e5dd7070Spatrick
1376e5dd7070Spatrick TestTypestateAttr::ConsumedState TestState;
1377e5dd7070Spatrick if (AL.isArgIdent(0)) {
1378e5dd7070Spatrick IdentifierLoc *Ident = AL.getArgAsIdent(0);
1379e5dd7070Spatrick StringRef Param = Ident->Ident->getName();
1380e5dd7070Spatrick if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) {
1381e5dd7070Spatrick S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL
1382e5dd7070Spatrick << Param;
1383e5dd7070Spatrick return;
1384e5dd7070Spatrick }
1385e5dd7070Spatrick } else {
1386e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
1387e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
1388e5dd7070Spatrick return;
1389e5dd7070Spatrick }
1390e5dd7070Spatrick
1391e5dd7070Spatrick D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState));
1392e5dd7070Spatrick }
1393e5dd7070Spatrick
handleExtVectorTypeAttr(Sema & S,Decl * D,const ParsedAttr & AL)1394e5dd7070Spatrick static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1395e5dd7070Spatrick // Remember this typedef decl, we will need it later for diagnostics.
1396e5dd7070Spatrick S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D));
1397e5dd7070Spatrick }
1398e5dd7070Spatrick
handlePackedAttr(Sema & S,Decl * D,const ParsedAttr & AL)1399e5dd7070Spatrick static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1400e5dd7070Spatrick if (auto *TD = dyn_cast<TagDecl>(D))
1401e5dd7070Spatrick TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
1402e5dd7070Spatrick else if (auto *FD = dyn_cast<FieldDecl>(D)) {
1403e5dd7070Spatrick bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
1404e5dd7070Spatrick !FD->getType()->isIncompleteType() &&
1405e5dd7070Spatrick FD->isBitField() &&
1406e5dd7070Spatrick S.Context.getTypeAlign(FD->getType()) <= 8);
1407e5dd7070Spatrick
1408*7a9b00ceSrobert if (S.getASTContext().getTargetInfo().getTriple().isPS()) {
1409e5dd7070Spatrick if (BitfieldByteAligned)
1410*7a9b00ceSrobert // The PS4/PS5 targets need to maintain ABI backwards compatibility.
1411e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
1412e5dd7070Spatrick << AL << FD->getType();
1413e5dd7070Spatrick else
1414e5dd7070Spatrick FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
1415e5dd7070Spatrick } else {
1416e5dd7070Spatrick // Report warning about changed offset in the newer compiler versions.
1417e5dd7070Spatrick if (BitfieldByteAligned)
1418e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield);
1419e5dd7070Spatrick
1420e5dd7070Spatrick FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
1421e5dd7070Spatrick }
1422e5dd7070Spatrick
1423e5dd7070Spatrick } else
1424e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
1425e5dd7070Spatrick }
1426e5dd7070Spatrick
handlePreferredName(Sema & S,Decl * D,const ParsedAttr & AL)1427a0747c9fSpatrick static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
1428a0747c9fSpatrick auto *RD = cast<CXXRecordDecl>(D);
1429a0747c9fSpatrick ClassTemplateDecl *CTD = RD->getDescribedClassTemplate();
1430a0747c9fSpatrick assert(CTD && "attribute does not appertain to this declaration");
1431a0747c9fSpatrick
1432a0747c9fSpatrick ParsedType PT = AL.getTypeArg();
1433a0747c9fSpatrick TypeSourceInfo *TSI = nullptr;
1434a0747c9fSpatrick QualType T = S.GetTypeFromParser(PT, &TSI);
1435a0747c9fSpatrick if (!TSI)
1436a0747c9fSpatrick TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc());
1437a0747c9fSpatrick
1438a0747c9fSpatrick if (!T.hasQualifiers() && T->isTypedefNameType()) {
1439a0747c9fSpatrick // Find the template name, if this type names a template specialization.
1440a0747c9fSpatrick const TemplateDecl *Template = nullptr;
1441a0747c9fSpatrick if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
1442a0747c9fSpatrick T->getAsCXXRecordDecl())) {
1443a0747c9fSpatrick Template = CTSD->getSpecializedTemplate();
1444a0747c9fSpatrick } else if (const auto *TST = T->getAs<TemplateSpecializationType>()) {
1445a0747c9fSpatrick while (TST && TST->isTypeAlias())
1446a0747c9fSpatrick TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
1447a0747c9fSpatrick if (TST)
1448a0747c9fSpatrick Template = TST->getTemplateName().getAsTemplateDecl();
1449a0747c9fSpatrick }
1450a0747c9fSpatrick
1451a0747c9fSpatrick if (Template && declaresSameEntity(Template, CTD)) {
1452a0747c9fSpatrick D->addAttr(::new (S.Context) PreferredNameAttr(S.Context, AL, TSI));
1453a0747c9fSpatrick return;
1454a0747c9fSpatrick }
1455a0747c9fSpatrick }
1456a0747c9fSpatrick
1457a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_preferred_name_arg_invalid)
1458a0747c9fSpatrick << T << CTD;
1459a0747c9fSpatrick if (const auto *TT = T->getAs<TypedefType>())
1460a0747c9fSpatrick S.Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at)
1461a0747c9fSpatrick << TT->getDecl();
1462a0747c9fSpatrick }
1463a0747c9fSpatrick
checkIBOutletCommon(Sema & S,Decl * D,const ParsedAttr & AL)1464e5dd7070Spatrick static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
1465e5dd7070Spatrick // The IBOutlet/IBOutletCollection attributes only apply to instance
1466e5dd7070Spatrick // variables or properties of Objective-C classes. The outlet must also
1467e5dd7070Spatrick // have an object reference type.
1468e5dd7070Spatrick if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) {
1469e5dd7070Spatrick if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
1470e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
1471e5dd7070Spatrick << AL << VD->getType() << 0;
1472e5dd7070Spatrick return false;
1473e5dd7070Spatrick }
1474e5dd7070Spatrick }
1475e5dd7070Spatrick else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
1476e5dd7070Spatrick if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
1477e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
1478e5dd7070Spatrick << AL << PD->getType() << 1;
1479e5dd7070Spatrick return false;
1480e5dd7070Spatrick }
1481e5dd7070Spatrick }
1482e5dd7070Spatrick else {
1483e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL;
1484e5dd7070Spatrick return false;
1485e5dd7070Spatrick }
1486e5dd7070Spatrick
1487e5dd7070Spatrick return true;
1488e5dd7070Spatrick }
1489e5dd7070Spatrick
handleIBOutlet(Sema & S,Decl * D,const ParsedAttr & AL)1490e5dd7070Spatrick static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) {
1491e5dd7070Spatrick if (!checkIBOutletCommon(S, D, AL))
1492e5dd7070Spatrick return;
1493e5dd7070Spatrick
1494e5dd7070Spatrick D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL));
1495e5dd7070Spatrick }
1496e5dd7070Spatrick
handleIBOutletCollection(Sema & S,Decl * D,const ParsedAttr & AL)1497e5dd7070Spatrick static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
1498e5dd7070Spatrick
1499e5dd7070Spatrick // The iboutletcollection attribute can have zero or one arguments.
1500e5dd7070Spatrick if (AL.getNumArgs() > 1) {
1501e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1502e5dd7070Spatrick return;
1503e5dd7070Spatrick }
1504e5dd7070Spatrick
1505e5dd7070Spatrick if (!checkIBOutletCommon(S, D, AL))
1506e5dd7070Spatrick return;
1507e5dd7070Spatrick
1508e5dd7070Spatrick ParsedType PT;
1509e5dd7070Spatrick
1510e5dd7070Spatrick if (AL.hasParsedType())
1511e5dd7070Spatrick PT = AL.getTypeArg();
1512e5dd7070Spatrick else {
1513e5dd7070Spatrick PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(),
1514e5dd7070Spatrick S.getScopeForContext(D->getDeclContext()->getParent()));
1515e5dd7070Spatrick if (!PT) {
1516e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
1517e5dd7070Spatrick return;
1518e5dd7070Spatrick }
1519e5dd7070Spatrick }
1520e5dd7070Spatrick
1521e5dd7070Spatrick TypeSourceInfo *QTLoc = nullptr;
1522e5dd7070Spatrick QualType QT = S.GetTypeFromParser(PT, &QTLoc);
1523e5dd7070Spatrick if (!QTLoc)
1524e5dd7070Spatrick QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc());
1525e5dd7070Spatrick
1526e5dd7070Spatrick // Diagnose use of non-object type in iboutletcollection attribute.
1527e5dd7070Spatrick // FIXME. Gnu attribute extension ignores use of builtin types in
1528e5dd7070Spatrick // attributes. So, __attribute__((iboutletcollection(char))) will be
1529e5dd7070Spatrick // treated as __attribute__((iboutletcollection())).
1530e5dd7070Spatrick if (!QT->isObjCIdType() && !QT->isObjCObjectType()) {
1531e5dd7070Spatrick S.Diag(AL.getLoc(),
1532e5dd7070Spatrick QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype
1533e5dd7070Spatrick : diag::err_iboutletcollection_type) << QT;
1534e5dd7070Spatrick return;
1535e5dd7070Spatrick }
1536e5dd7070Spatrick
1537e5dd7070Spatrick D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc));
1538e5dd7070Spatrick }
1539e5dd7070Spatrick
isValidPointerAttrType(QualType T,bool RefOkay)1540e5dd7070Spatrick bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
1541e5dd7070Spatrick if (RefOkay) {
1542e5dd7070Spatrick if (T->isReferenceType())
1543e5dd7070Spatrick return true;
1544e5dd7070Spatrick } else {
1545e5dd7070Spatrick T = T.getNonReferenceType();
1546e5dd7070Spatrick }
1547e5dd7070Spatrick
1548e5dd7070Spatrick // The nonnull attribute, and other similar attributes, can be applied to a
1549e5dd7070Spatrick // transparent union that contains a pointer type.
1550e5dd7070Spatrick if (const RecordType *UT = T->getAsUnionType()) {
1551e5dd7070Spatrick if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
1552e5dd7070Spatrick RecordDecl *UD = UT->getDecl();
1553e5dd7070Spatrick for (const auto *I : UD->fields()) {
1554e5dd7070Spatrick QualType QT = I->getType();
1555e5dd7070Spatrick if (QT->isAnyPointerType() || QT->isBlockPointerType())
1556e5dd7070Spatrick return true;
1557e5dd7070Spatrick }
1558e5dd7070Spatrick }
1559e5dd7070Spatrick }
1560e5dd7070Spatrick
1561e5dd7070Spatrick return T->isAnyPointerType() || T->isBlockPointerType();
1562e5dd7070Spatrick }
1563e5dd7070Spatrick
attrNonNullArgCheck(Sema & S,QualType T,const ParsedAttr & AL,SourceRange AttrParmRange,SourceRange TypeRange,bool isReturnValue=false)1564e5dd7070Spatrick static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL,
1565e5dd7070Spatrick SourceRange AttrParmRange,
1566e5dd7070Spatrick SourceRange TypeRange,
1567e5dd7070Spatrick bool isReturnValue = false) {
1568e5dd7070Spatrick if (!S.isValidPointerAttrType(T)) {
1569e5dd7070Spatrick if (isReturnValue)
1570e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
1571e5dd7070Spatrick << AL << AttrParmRange << TypeRange;
1572e5dd7070Spatrick else
1573e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
1574e5dd7070Spatrick << AL << AttrParmRange << TypeRange << 0;
1575e5dd7070Spatrick return false;
1576e5dd7070Spatrick }
1577e5dd7070Spatrick return true;
1578e5dd7070Spatrick }
1579e5dd7070Spatrick
handleNonNullAttr(Sema & S,Decl * D,const ParsedAttr & AL)1580e5dd7070Spatrick static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1581e5dd7070Spatrick SmallVector<ParamIdx, 8> NonNullArgs;
1582e5dd7070Spatrick for (unsigned I = 0; I < AL.getNumArgs(); ++I) {
1583e5dd7070Spatrick Expr *Ex = AL.getArgAsExpr(I);
1584e5dd7070Spatrick ParamIdx Idx;
1585e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx))
1586e5dd7070Spatrick return;
1587e5dd7070Spatrick
1588e5dd7070Spatrick // Is the function argument a pointer type?
1589e5dd7070Spatrick if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) &&
1590e5dd7070Spatrick !attrNonNullArgCheck(
1591e5dd7070Spatrick S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL,
1592e5dd7070Spatrick Ex->getSourceRange(),
1593e5dd7070Spatrick getFunctionOrMethodParamRange(D, Idx.getASTIndex())))
1594e5dd7070Spatrick continue;
1595e5dd7070Spatrick
1596e5dd7070Spatrick NonNullArgs.push_back(Idx);
1597e5dd7070Spatrick }
1598e5dd7070Spatrick
1599e5dd7070Spatrick // If no arguments were specified to __attribute__((nonnull)) then all pointer
1600e5dd7070Spatrick // arguments have a nonnull attribute; warn if there aren't any. Skip this
1601e5dd7070Spatrick // check if the attribute came from a macro expansion or a template
1602e5dd7070Spatrick // instantiation.
1603e5dd7070Spatrick if (NonNullArgs.empty() && AL.getLoc().isFileID() &&
1604e5dd7070Spatrick !S.inTemplateInstantiation()) {
1605e5dd7070Spatrick bool AnyPointers = isFunctionOrMethodVariadic(D);
1606e5dd7070Spatrick for (unsigned I = 0, E = getFunctionOrMethodNumParams(D);
1607e5dd7070Spatrick I != E && !AnyPointers; ++I) {
1608e5dd7070Spatrick QualType T = getFunctionOrMethodParamType(D, I);
1609e5dd7070Spatrick if (T->isDependentType() || S.isValidPointerAttrType(T))
1610e5dd7070Spatrick AnyPointers = true;
1611e5dd7070Spatrick }
1612e5dd7070Spatrick
1613e5dd7070Spatrick if (!AnyPointers)
1614e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers);
1615e5dd7070Spatrick }
1616e5dd7070Spatrick
1617e5dd7070Spatrick ParamIdx *Start = NonNullArgs.data();
1618e5dd7070Spatrick unsigned Size = NonNullArgs.size();
1619e5dd7070Spatrick llvm::array_pod_sort(Start, Start + Size);
1620e5dd7070Spatrick D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size));
1621e5dd7070Spatrick }
1622e5dd7070Spatrick
handleNonNullAttrParameter(Sema & S,ParmVarDecl * D,const ParsedAttr & AL)1623e5dd7070Spatrick static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
1624e5dd7070Spatrick const ParsedAttr &AL) {
1625e5dd7070Spatrick if (AL.getNumArgs() > 0) {
1626e5dd7070Spatrick if (D->getFunctionType()) {
1627e5dd7070Spatrick handleNonNullAttr(S, D, AL);
1628e5dd7070Spatrick } else {
1629e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args)
1630e5dd7070Spatrick << D->getSourceRange();
1631e5dd7070Spatrick }
1632e5dd7070Spatrick return;
1633e5dd7070Spatrick }
1634e5dd7070Spatrick
1635e5dd7070Spatrick // Is the argument a pointer type?
1636e5dd7070Spatrick if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(),
1637e5dd7070Spatrick D->getSourceRange()))
1638e5dd7070Spatrick return;
1639e5dd7070Spatrick
1640e5dd7070Spatrick D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0));
1641e5dd7070Spatrick }
1642e5dd7070Spatrick
handleReturnsNonNullAttr(Sema & S,Decl * D,const ParsedAttr & AL)1643e5dd7070Spatrick static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1644e5dd7070Spatrick QualType ResultType = getFunctionOrMethodResultType(D);
1645e5dd7070Spatrick SourceRange SR = getFunctionOrMethodResultSourceRange(D);
1646e5dd7070Spatrick if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR,
1647e5dd7070Spatrick /* isReturnValue */ true))
1648e5dd7070Spatrick return;
1649e5dd7070Spatrick
1650e5dd7070Spatrick D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL));
1651e5dd7070Spatrick }
1652e5dd7070Spatrick
handleNoEscapeAttr(Sema & S,Decl * D,const ParsedAttr & AL)1653e5dd7070Spatrick static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1654e5dd7070Spatrick if (D->isInvalidDecl())
1655e5dd7070Spatrick return;
1656e5dd7070Spatrick
1657e5dd7070Spatrick // noescape only applies to pointer types.
1658e5dd7070Spatrick QualType T = cast<ParmVarDecl>(D)->getType();
1659e5dd7070Spatrick if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
1660e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
1661e5dd7070Spatrick << AL << AL.getRange() << 0;
1662e5dd7070Spatrick return;
1663e5dd7070Spatrick }
1664e5dd7070Spatrick
1665e5dd7070Spatrick D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
1666e5dd7070Spatrick }
1667e5dd7070Spatrick
handleAssumeAlignedAttr(Sema & S,Decl * D,const ParsedAttr & AL)1668e5dd7070Spatrick static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1669e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0),
1670e5dd7070Spatrick *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr;
1671e5dd7070Spatrick S.AddAssumeAlignedAttr(D, AL, E, OE);
1672e5dd7070Spatrick }
1673e5dd7070Spatrick
handleAllocAlignAttr(Sema & S,Decl * D,const ParsedAttr & AL)1674e5dd7070Spatrick static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1675e5dd7070Spatrick S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0));
1676e5dd7070Spatrick }
1677e5dd7070Spatrick
AddAssumeAlignedAttr(Decl * D,const AttributeCommonInfo & CI,Expr * E,Expr * OE)1678e5dd7070Spatrick void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
1679e5dd7070Spatrick Expr *OE) {
1680e5dd7070Spatrick QualType ResultType = getFunctionOrMethodResultType(D);
1681e5dd7070Spatrick SourceRange SR = getFunctionOrMethodResultSourceRange(D);
1682e5dd7070Spatrick
1683e5dd7070Spatrick AssumeAlignedAttr TmpAttr(Context, CI, E, OE);
1684e5dd7070Spatrick SourceLocation AttrLoc = TmpAttr.getLocation();
1685e5dd7070Spatrick
1686e5dd7070Spatrick if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
1687e5dd7070Spatrick Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
1688e5dd7070Spatrick << &TmpAttr << TmpAttr.getRange() << SR;
1689e5dd7070Spatrick return;
1690e5dd7070Spatrick }
1691e5dd7070Spatrick
1692e5dd7070Spatrick if (!E->isValueDependent()) {
1693*7a9b00ceSrobert std::optional<llvm::APSInt> I = llvm::APSInt(64);
1694a0747c9fSpatrick if (!(I = E->getIntegerConstantExpr(Context))) {
1695e5dd7070Spatrick if (OE)
1696e5dd7070Spatrick Diag(AttrLoc, diag::err_attribute_argument_n_type)
1697e5dd7070Spatrick << &TmpAttr << 1 << AANT_ArgumentIntegerConstant
1698e5dd7070Spatrick << E->getSourceRange();
1699e5dd7070Spatrick else
1700e5dd7070Spatrick Diag(AttrLoc, diag::err_attribute_argument_type)
1701e5dd7070Spatrick << &TmpAttr << AANT_ArgumentIntegerConstant
1702e5dd7070Spatrick << E->getSourceRange();
1703e5dd7070Spatrick return;
1704e5dd7070Spatrick }
1705e5dd7070Spatrick
1706a0747c9fSpatrick if (!I->isPowerOf2()) {
1707e5dd7070Spatrick Diag(AttrLoc, diag::err_alignment_not_power_of_two)
1708e5dd7070Spatrick << E->getSourceRange();
1709e5dd7070Spatrick return;
1710e5dd7070Spatrick }
1711ec727ea7Spatrick
1712a0747c9fSpatrick if (*I > Sema::MaximumAlignment)
1713ec727ea7Spatrick Diag(CI.getLoc(), diag::warn_assume_aligned_too_great)
1714ec727ea7Spatrick << CI.getRange() << Sema::MaximumAlignment;
1715e5dd7070Spatrick }
1716e5dd7070Spatrick
1717a0747c9fSpatrick if (OE && !OE->isValueDependent() && !OE->isIntegerConstantExpr(Context)) {
1718e5dd7070Spatrick Diag(AttrLoc, diag::err_attribute_argument_n_type)
1719e5dd7070Spatrick << &TmpAttr << 2 << AANT_ArgumentIntegerConstant
1720e5dd7070Spatrick << OE->getSourceRange();
1721e5dd7070Spatrick return;
1722e5dd7070Spatrick }
1723e5dd7070Spatrick
1724e5dd7070Spatrick D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE));
1725e5dd7070Spatrick }
1726e5dd7070Spatrick
AddAllocAlignAttr(Decl * D,const AttributeCommonInfo & CI,Expr * ParamExpr)1727e5dd7070Spatrick void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
1728e5dd7070Spatrick Expr *ParamExpr) {
1729e5dd7070Spatrick QualType ResultType = getFunctionOrMethodResultType(D);
1730e5dd7070Spatrick
1731e5dd7070Spatrick AllocAlignAttr TmpAttr(Context, CI, ParamIdx());
1732e5dd7070Spatrick SourceLocation AttrLoc = CI.getLoc();
1733e5dd7070Spatrick
1734e5dd7070Spatrick if (!ResultType->isDependentType() &&
1735e5dd7070Spatrick !isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
1736e5dd7070Spatrick Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
1737e5dd7070Spatrick << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D);
1738e5dd7070Spatrick return;
1739e5dd7070Spatrick }
1740e5dd7070Spatrick
1741e5dd7070Spatrick ParamIdx Idx;
1742e5dd7070Spatrick const auto *FuncDecl = cast<FunctionDecl>(D);
1743e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
1744e5dd7070Spatrick /*AttrArgNum=*/1, ParamExpr, Idx))
1745e5dd7070Spatrick return;
1746e5dd7070Spatrick
1747e5dd7070Spatrick QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
1748ec727ea7Spatrick if (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
1749ec727ea7Spatrick !Ty->isAlignValT()) {
1750e5dd7070Spatrick Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only)
1751e5dd7070Spatrick << &TmpAttr
1752e5dd7070Spatrick << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange();
1753e5dd7070Spatrick return;
1754e5dd7070Spatrick }
1755e5dd7070Spatrick
1756e5dd7070Spatrick D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx));
1757e5dd7070Spatrick }
1758e5dd7070Spatrick
1759a0747c9fSpatrick /// Check if \p AssumptionStr is a known assumption and warn if not.
checkAssumptionAttr(Sema & S,SourceLocation Loc,StringRef AssumptionStr)1760a0747c9fSpatrick static void checkAssumptionAttr(Sema &S, SourceLocation Loc,
1761a0747c9fSpatrick StringRef AssumptionStr) {
1762a0747c9fSpatrick if (llvm::KnownAssumptionStrings.count(AssumptionStr))
1763a0747c9fSpatrick return;
1764a0747c9fSpatrick
1765a0747c9fSpatrick unsigned BestEditDistance = 3;
1766a0747c9fSpatrick StringRef Suggestion;
1767a0747c9fSpatrick for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) {
1768a0747c9fSpatrick unsigned EditDistance =
1769a0747c9fSpatrick AssumptionStr.edit_distance(KnownAssumptionIt.getKey());
1770a0747c9fSpatrick if (EditDistance < BestEditDistance) {
1771a0747c9fSpatrick Suggestion = KnownAssumptionIt.getKey();
1772a0747c9fSpatrick BestEditDistance = EditDistance;
1773a0747c9fSpatrick }
1774a0747c9fSpatrick }
1775a0747c9fSpatrick
1776a0747c9fSpatrick if (!Suggestion.empty())
1777a0747c9fSpatrick S.Diag(Loc, diag::warn_assume_attribute_string_unknown_suggested)
1778a0747c9fSpatrick << AssumptionStr << Suggestion;
1779a0747c9fSpatrick else
1780a0747c9fSpatrick S.Diag(Loc, diag::warn_assume_attribute_string_unknown) << AssumptionStr;
1781a0747c9fSpatrick }
1782a0747c9fSpatrick
handleAssumumptionAttr(Sema & S,Decl * D,const ParsedAttr & AL)1783a0747c9fSpatrick static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1784a0747c9fSpatrick // Handle the case where the attribute has a text message.
1785a0747c9fSpatrick StringRef Str;
1786a0747c9fSpatrick SourceLocation AttrStrLoc;
1787a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc))
1788a0747c9fSpatrick return;
1789a0747c9fSpatrick
1790a0747c9fSpatrick checkAssumptionAttr(S, AttrStrLoc, Str);
1791a0747c9fSpatrick
1792a0747c9fSpatrick D->addAttr(::new (S.Context) AssumptionAttr(S.Context, AL, Str));
1793a0747c9fSpatrick }
1794a0747c9fSpatrick
1795e5dd7070Spatrick /// Normalize the attribute, __foo__ becomes foo.
1796e5dd7070Spatrick /// Returns true if normalization was applied.
normalizeName(StringRef & AttrName)1797e5dd7070Spatrick static bool normalizeName(StringRef &AttrName) {
1798e5dd7070Spatrick if (AttrName.size() > 4 && AttrName.startswith("__") &&
1799e5dd7070Spatrick AttrName.endswith("__")) {
1800e5dd7070Spatrick AttrName = AttrName.drop_front(2).drop_back(2);
1801e5dd7070Spatrick return true;
1802e5dd7070Spatrick }
1803e5dd7070Spatrick return false;
1804e5dd7070Spatrick }
1805e5dd7070Spatrick
handleOwnershipAttr(Sema & S,Decl * D,const ParsedAttr & AL)1806e5dd7070Spatrick static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1807e5dd7070Spatrick // This attribute must be applied to a function declaration. The first
1808e5dd7070Spatrick // argument to the attribute must be an identifier, the name of the resource,
1809e5dd7070Spatrick // for example: malloc. The following arguments must be argument indexes, the
1810e5dd7070Spatrick // arguments must be of integer type for Returns, otherwise of pointer type.
1811e5dd7070Spatrick // The difference between Holds and Takes is that a pointer may still be used
1812e5dd7070Spatrick // after being held. free() should be __attribute((ownership_takes)), whereas
1813e5dd7070Spatrick // a list append function may well be __attribute((ownership_holds)).
1814e5dd7070Spatrick
1815e5dd7070Spatrick if (!AL.isArgIdent(0)) {
1816e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
1817e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
1818e5dd7070Spatrick return;
1819e5dd7070Spatrick }
1820e5dd7070Spatrick
1821e5dd7070Spatrick // Figure out our Kind.
1822e5dd7070Spatrick OwnershipAttr::OwnershipKind K =
1823e5dd7070Spatrick OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind();
1824e5dd7070Spatrick
1825e5dd7070Spatrick // Check arguments.
1826e5dd7070Spatrick switch (K) {
1827e5dd7070Spatrick case OwnershipAttr::Takes:
1828e5dd7070Spatrick case OwnershipAttr::Holds:
1829e5dd7070Spatrick if (AL.getNumArgs() < 2) {
1830e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL << 2;
1831e5dd7070Spatrick return;
1832e5dd7070Spatrick }
1833e5dd7070Spatrick break;
1834e5dd7070Spatrick case OwnershipAttr::Returns:
1835e5dd7070Spatrick if (AL.getNumArgs() > 2) {
1836e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
1837e5dd7070Spatrick return;
1838e5dd7070Spatrick }
1839e5dd7070Spatrick break;
1840e5dd7070Spatrick }
1841e5dd7070Spatrick
1842e5dd7070Spatrick IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident;
1843e5dd7070Spatrick
1844e5dd7070Spatrick StringRef ModuleName = Module->getName();
1845e5dd7070Spatrick if (normalizeName(ModuleName)) {
1846e5dd7070Spatrick Module = &S.PP.getIdentifierTable().get(ModuleName);
1847e5dd7070Spatrick }
1848e5dd7070Spatrick
1849e5dd7070Spatrick SmallVector<ParamIdx, 8> OwnershipArgs;
1850e5dd7070Spatrick for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
1851e5dd7070Spatrick Expr *Ex = AL.getArgAsExpr(i);
1852e5dd7070Spatrick ParamIdx Idx;
1853e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx))
1854e5dd7070Spatrick return;
1855e5dd7070Spatrick
1856e5dd7070Spatrick // Is the function argument a pointer type?
1857e5dd7070Spatrick QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex());
1858e5dd7070Spatrick int Err = -1; // No error
1859e5dd7070Spatrick switch (K) {
1860e5dd7070Spatrick case OwnershipAttr::Takes:
1861e5dd7070Spatrick case OwnershipAttr::Holds:
1862e5dd7070Spatrick if (!T->isAnyPointerType() && !T->isBlockPointerType())
1863e5dd7070Spatrick Err = 0;
1864e5dd7070Spatrick break;
1865e5dd7070Spatrick case OwnershipAttr::Returns:
1866e5dd7070Spatrick if (!T->isIntegerType())
1867e5dd7070Spatrick Err = 1;
1868e5dd7070Spatrick break;
1869e5dd7070Spatrick }
1870e5dd7070Spatrick if (-1 != Err) {
1871e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_ownership_type) << AL << Err
1872e5dd7070Spatrick << Ex->getSourceRange();
1873e5dd7070Spatrick return;
1874e5dd7070Spatrick }
1875e5dd7070Spatrick
1876e5dd7070Spatrick // Check we don't have a conflict with another ownership attribute.
1877e5dd7070Spatrick for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
1878e5dd7070Spatrick // Cannot have two ownership attributes of different kinds for the same
1879e5dd7070Spatrick // index.
1880*7a9b00ceSrobert if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) {
1881e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I;
1882e5dd7070Spatrick return;
1883e5dd7070Spatrick } else if (K == OwnershipAttr::Returns &&
1884e5dd7070Spatrick I->getOwnKind() == OwnershipAttr::Returns) {
1885e5dd7070Spatrick // A returns attribute conflicts with any other returns attribute using
1886e5dd7070Spatrick // a different index.
1887*7a9b00ceSrobert if (!llvm::is_contained(I->args(), Idx)) {
1888e5dd7070Spatrick S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch)
1889e5dd7070Spatrick << I->args_begin()->getSourceIndex();
1890e5dd7070Spatrick if (I->args_size())
1891e5dd7070Spatrick S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch)
1892e5dd7070Spatrick << Idx.getSourceIndex() << Ex->getSourceRange();
1893e5dd7070Spatrick return;
1894e5dd7070Spatrick }
1895e5dd7070Spatrick }
1896e5dd7070Spatrick }
1897e5dd7070Spatrick OwnershipArgs.push_back(Idx);
1898e5dd7070Spatrick }
1899e5dd7070Spatrick
1900e5dd7070Spatrick ParamIdx *Start = OwnershipArgs.data();
1901e5dd7070Spatrick unsigned Size = OwnershipArgs.size();
1902e5dd7070Spatrick llvm::array_pod_sort(Start, Start + Size);
1903e5dd7070Spatrick D->addAttr(::new (S.Context)
1904e5dd7070Spatrick OwnershipAttr(S.Context, AL, Module, Start, Size));
1905e5dd7070Spatrick }
1906e5dd7070Spatrick
handleWeakRefAttr(Sema & S,Decl * D,const ParsedAttr & AL)1907e5dd7070Spatrick static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1908e5dd7070Spatrick // Check the attribute arguments.
1909e5dd7070Spatrick if (AL.getNumArgs() > 1) {
1910e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1911e5dd7070Spatrick return;
1912e5dd7070Spatrick }
1913e5dd7070Spatrick
1914e5dd7070Spatrick // gcc rejects
1915e5dd7070Spatrick // class c {
1916e5dd7070Spatrick // static int a __attribute__((weakref ("v2")));
1917e5dd7070Spatrick // static int b() __attribute__((weakref ("f3")));
1918e5dd7070Spatrick // };
1919e5dd7070Spatrick // and ignores the attributes of
1920e5dd7070Spatrick // void f(void) {
1921e5dd7070Spatrick // static int a __attribute__((weakref ("v2")));
1922e5dd7070Spatrick // }
1923e5dd7070Spatrick // we reject them
1924e5dd7070Spatrick const DeclContext *Ctx = D->getDeclContext()->getRedeclContext();
1925e5dd7070Spatrick if (!Ctx->isFileContext()) {
1926e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context)
1927e5dd7070Spatrick << cast<NamedDecl>(D);
1928e5dd7070Spatrick return;
1929e5dd7070Spatrick }
1930e5dd7070Spatrick
1931e5dd7070Spatrick // The GCC manual says
1932e5dd7070Spatrick //
1933e5dd7070Spatrick // At present, a declaration to which `weakref' is attached can only
1934e5dd7070Spatrick // be `static'.
1935e5dd7070Spatrick //
1936e5dd7070Spatrick // It also says
1937e5dd7070Spatrick //
1938e5dd7070Spatrick // Without a TARGET,
1939e5dd7070Spatrick // given as an argument to `weakref' or to `alias', `weakref' is
1940e5dd7070Spatrick // equivalent to `weak'.
1941e5dd7070Spatrick //
1942e5dd7070Spatrick // gcc 4.4.1 will accept
1943e5dd7070Spatrick // int a7 __attribute__((weakref));
1944e5dd7070Spatrick // as
1945e5dd7070Spatrick // int a7 __attribute__((weak));
1946e5dd7070Spatrick // This looks like a bug in gcc. We reject that for now. We should revisit
1947e5dd7070Spatrick // it if this behaviour is actually used.
1948e5dd7070Spatrick
1949e5dd7070Spatrick // GCC rejects
1950e5dd7070Spatrick // static ((alias ("y"), weakref)).
1951e5dd7070Spatrick // Should we? How to check that weakref is before or after alias?
1952e5dd7070Spatrick
1953e5dd7070Spatrick // FIXME: it would be good for us to keep the WeakRefAttr as-written instead
1954e5dd7070Spatrick // of transforming it into an AliasAttr. The WeakRefAttr never uses the
1955e5dd7070Spatrick // StringRef parameter it was given anyway.
1956e5dd7070Spatrick StringRef Str;
1957e5dd7070Spatrick if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str))
1958e5dd7070Spatrick // GCC will accept anything as the argument of weakref. Should we
1959e5dd7070Spatrick // check for an existing decl?
1960e5dd7070Spatrick D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
1961e5dd7070Spatrick
1962e5dd7070Spatrick D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
1963e5dd7070Spatrick }
1964e5dd7070Spatrick
handleIFuncAttr(Sema & S,Decl * D,const ParsedAttr & AL)1965e5dd7070Spatrick static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1966e5dd7070Spatrick StringRef Str;
1967e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
1968e5dd7070Spatrick return;
1969e5dd7070Spatrick
1970e5dd7070Spatrick // Aliases should be on declarations, not definitions.
1971e5dd7070Spatrick const auto *FD = cast<FunctionDecl>(D);
1972e5dd7070Spatrick if (FD->isThisDeclarationADefinition()) {
1973e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1;
1974e5dd7070Spatrick return;
1975e5dd7070Spatrick }
1976e5dd7070Spatrick
1977e5dd7070Spatrick D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
1978e5dd7070Spatrick }
1979e5dd7070Spatrick
handleAliasAttr(Sema & S,Decl * D,const ParsedAttr & AL)1980e5dd7070Spatrick static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
1981e5dd7070Spatrick StringRef Str;
1982e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
1983e5dd7070Spatrick return;
1984e5dd7070Spatrick
1985e5dd7070Spatrick if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
1986e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin);
1987e5dd7070Spatrick return;
1988e5dd7070Spatrick }
1989e5dd7070Spatrick if (S.Context.getTargetInfo().getTriple().isNVPTX()) {
1990e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx);
1991e5dd7070Spatrick }
1992e5dd7070Spatrick
1993e5dd7070Spatrick // Aliases should be on declarations, not definitions.
1994e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
1995e5dd7070Spatrick if (FD->isThisDeclarationADefinition()) {
1996e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0;
1997e5dd7070Spatrick return;
1998e5dd7070Spatrick }
1999e5dd7070Spatrick } else {
2000e5dd7070Spatrick const auto *VD = cast<VarDecl>(D);
2001e5dd7070Spatrick if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) {
2002e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0;
2003e5dd7070Spatrick return;
2004e5dd7070Spatrick }
2005e5dd7070Spatrick }
2006e5dd7070Spatrick
2007e5dd7070Spatrick // Mark target used to prevent unneeded-internal-declaration warnings.
2008e5dd7070Spatrick if (!S.LangOpts.CPlusPlus) {
2009e5dd7070Spatrick // FIXME: demangle Str for C++, as the attribute refers to the mangled
2010e5dd7070Spatrick // linkage name, not the pre-mangled identifier.
2011e5dd7070Spatrick const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
2012e5dd7070Spatrick LookupResult LR(S, target, Sema::LookupOrdinaryName);
2013e5dd7070Spatrick if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
2014e5dd7070Spatrick for (NamedDecl *ND : LR)
2015e5dd7070Spatrick ND->markUsed(S.Context);
2016e5dd7070Spatrick }
2017e5dd7070Spatrick
2018e5dd7070Spatrick D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
2019e5dd7070Spatrick }
2020e5dd7070Spatrick
handleTLSModelAttr(Sema & S,Decl * D,const ParsedAttr & AL)2021e5dd7070Spatrick static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2022e5dd7070Spatrick StringRef Model;
2023e5dd7070Spatrick SourceLocation LiteralLoc;
2024e5dd7070Spatrick // Check that it is a string.
2025e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc))
2026e5dd7070Spatrick return;
2027e5dd7070Spatrick
2028e5dd7070Spatrick // Check that the value.
2029e5dd7070Spatrick if (Model != "global-dynamic" && Model != "local-dynamic"
2030e5dd7070Spatrick && Model != "initial-exec" && Model != "local-exec") {
2031e5dd7070Spatrick S.Diag(LiteralLoc, diag::err_attr_tlsmodel_arg);
2032e5dd7070Spatrick return;
2033e5dd7070Spatrick }
2034e5dd7070Spatrick
2035a0747c9fSpatrick if (S.Context.getTargetInfo().getTriple().isOSAIX() &&
2036a0747c9fSpatrick Model != "global-dynamic") {
2037a0747c9fSpatrick S.Diag(LiteralLoc, diag::err_aix_attr_unsupported_tls_model) << Model;
2038a0747c9fSpatrick return;
2039a0747c9fSpatrick }
2040a0747c9fSpatrick
2041e5dd7070Spatrick D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model));
2042e5dd7070Spatrick }
2043e5dd7070Spatrick
handleRestrictAttr(Sema & S,Decl * D,const ParsedAttr & AL)2044e5dd7070Spatrick static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2045e5dd7070Spatrick QualType ResultType = getFunctionOrMethodResultType(D);
2046e5dd7070Spatrick if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) {
2047e5dd7070Spatrick D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
2048e5dd7070Spatrick return;
2049e5dd7070Spatrick }
2050e5dd7070Spatrick
2051e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
2052e5dd7070Spatrick << AL << getFunctionOrMethodResultSourceRange(D);
2053e5dd7070Spatrick }
2054e5dd7070Spatrick
handleCPUSpecificAttr(Sema & S,Decl * D,const ParsedAttr & AL)2055e5dd7070Spatrick static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2056*7a9b00ceSrobert // Ensure we don't combine these with themselves, since that causes some
2057*7a9b00ceSrobert // confusing behavior.
2058*7a9b00ceSrobert if (AL.getParsedKind() == ParsedAttr::AT_CPUDispatch) {
2059*7a9b00ceSrobert if (checkAttrMutualExclusion<CPUSpecificAttr>(S, D, AL))
2060*7a9b00ceSrobert return;
2061*7a9b00ceSrobert
2062*7a9b00ceSrobert if (const auto *Other = D->getAttr<CPUDispatchAttr>()) {
2063*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
2064*7a9b00ceSrobert S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
2065*7a9b00ceSrobert return;
2066*7a9b00ceSrobert }
2067*7a9b00ceSrobert } else if (AL.getParsedKind() == ParsedAttr::AT_CPUSpecific) {
2068*7a9b00ceSrobert if (checkAttrMutualExclusion<CPUDispatchAttr>(S, D, AL))
2069*7a9b00ceSrobert return;
2070*7a9b00ceSrobert
2071*7a9b00ceSrobert if (const auto *Other = D->getAttr<CPUSpecificAttr>()) {
2072*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
2073*7a9b00ceSrobert S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
2074*7a9b00ceSrobert return;
2075*7a9b00ceSrobert }
2076*7a9b00ceSrobert }
2077*7a9b00ceSrobert
2078e5dd7070Spatrick FunctionDecl *FD = cast<FunctionDecl>(D);
2079e5dd7070Spatrick
2080e5dd7070Spatrick if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
2081e5dd7070Spatrick if (MD->getParent()->isLambda()) {
2082e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_dll_lambda) << AL;
2083e5dd7070Spatrick return;
2084e5dd7070Spatrick }
2085e5dd7070Spatrick }
2086e5dd7070Spatrick
2087a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
2088e5dd7070Spatrick return;
2089e5dd7070Spatrick
2090e5dd7070Spatrick SmallVector<IdentifierInfo *, 8> CPUs;
2091e5dd7070Spatrick for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) {
2092e5dd7070Spatrick if (!AL.isArgIdent(ArgNo)) {
2093e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
2094e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
2095e5dd7070Spatrick return;
2096e5dd7070Spatrick }
2097e5dd7070Spatrick
2098e5dd7070Spatrick IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo);
2099e5dd7070Spatrick StringRef CPUName = CPUArg->Ident->getName().trim();
2100e5dd7070Spatrick
2101e5dd7070Spatrick if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) {
2102e5dd7070Spatrick S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value)
2103e5dd7070Spatrick << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch);
2104e5dd7070Spatrick return;
2105e5dd7070Spatrick }
2106e5dd7070Spatrick
2107e5dd7070Spatrick const TargetInfo &Target = S.Context.getTargetInfo();
2108e5dd7070Spatrick if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) {
2109e5dd7070Spatrick return Target.CPUSpecificManglingCharacter(CPUName) ==
2110e5dd7070Spatrick Target.CPUSpecificManglingCharacter(Cur->getName());
2111e5dd7070Spatrick })) {
2112e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries);
2113e5dd7070Spatrick return;
2114e5dd7070Spatrick }
2115e5dd7070Spatrick CPUs.push_back(CPUArg->Ident);
2116e5dd7070Spatrick }
2117e5dd7070Spatrick
2118e5dd7070Spatrick FD->setIsMultiVersion(true);
2119e5dd7070Spatrick if (AL.getKind() == ParsedAttr::AT_CPUSpecific)
2120e5dd7070Spatrick D->addAttr(::new (S.Context)
2121e5dd7070Spatrick CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size()));
2122e5dd7070Spatrick else
2123e5dd7070Spatrick D->addAttr(::new (S.Context)
2124e5dd7070Spatrick CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size()));
2125e5dd7070Spatrick }
2126e5dd7070Spatrick
handleCommonAttr(Sema & S,Decl * D,const ParsedAttr & AL)2127e5dd7070Spatrick static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2128e5dd7070Spatrick if (S.LangOpts.CPlusPlus) {
2129e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
2130e5dd7070Spatrick << AL << AttributeLangSupport::Cpp;
2131e5dd7070Spatrick return;
2132e5dd7070Spatrick }
2133e5dd7070Spatrick
2134a0747c9fSpatrick D->addAttr(::new (S.Context) CommonAttr(S.Context, AL));
2135e5dd7070Spatrick }
2136e5dd7070Spatrick
handleCmseNSEntryAttr(Sema & S,Decl * D,const ParsedAttr & AL)2137ec727ea7Spatrick static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2138ec727ea7Spatrick if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) {
2139ec727ea7Spatrick S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
2140ec727ea7Spatrick return;
2141ec727ea7Spatrick }
2142ec727ea7Spatrick
2143ec727ea7Spatrick const auto *FD = cast<FunctionDecl>(D);
2144ec727ea7Spatrick if (!FD->isExternallyVisible()) {
2145ec727ea7Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
2146ec727ea7Spatrick return;
2147ec727ea7Spatrick }
2148ec727ea7Spatrick
2149ec727ea7Spatrick D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL));
2150ec727ea7Spatrick }
2151ec727ea7Spatrick
handleNakedAttr(Sema & S,Decl * D,const ParsedAttr & AL)2152e5dd7070Spatrick static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2153e5dd7070Spatrick if (AL.isDeclspecAttribute()) {
2154e5dd7070Spatrick const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
2155e5dd7070Spatrick const auto &Arch = Triple.getArch();
2156e5dd7070Spatrick if (Arch != llvm::Triple::x86 &&
2157e5dd7070Spatrick (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) {
2158e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch)
2159e5dd7070Spatrick << AL << Triple.getArchName();
2160e5dd7070Spatrick return;
2161e5dd7070Spatrick }
2162*7a9b00ceSrobert
2163*7a9b00ceSrobert // This form is not allowed to be written on a member function (static or
2164*7a9b00ceSrobert // nonstatic) when in Microsoft compatibility mode.
2165*7a9b00ceSrobert if (S.getLangOpts().MSVCCompat && isa<CXXMethodDecl>(D)) {
2166*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
2167*7a9b00ceSrobert << AL << "non-member functions";
2168*7a9b00ceSrobert return;
2169*7a9b00ceSrobert }
2170e5dd7070Spatrick }
2171e5dd7070Spatrick
2172e5dd7070Spatrick D->addAttr(::new (S.Context) NakedAttr(S.Context, AL));
2173e5dd7070Spatrick }
2174e5dd7070Spatrick
handleNoReturnAttr(Sema & S,Decl * D,const ParsedAttr & Attrs)2175e5dd7070Spatrick static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
2176e5dd7070Spatrick if (hasDeclarator(D)) return;
2177e5dd7070Spatrick
2178e5dd7070Spatrick if (!isa<ObjCMethodDecl>(D)) {
2179e5dd7070Spatrick S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
2180e5dd7070Spatrick << Attrs << ExpectedFunctionOrMethod;
2181e5dd7070Spatrick return;
2182e5dd7070Spatrick }
2183e5dd7070Spatrick
2184e5dd7070Spatrick D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs));
2185e5dd7070Spatrick }
2186e5dd7070Spatrick
handleStandardNoReturnAttr(Sema & S,Decl * D,const ParsedAttr & A)2187*7a9b00ceSrobert static void handleStandardNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &A) {
2188*7a9b00ceSrobert // The [[_Noreturn]] spelling is deprecated in C2x, so if that was used,
2189*7a9b00ceSrobert // issue an appropriate diagnostic. However, don't issue a diagnostic if the
2190*7a9b00ceSrobert // attribute name comes from a macro expansion. We don't want to punish users
2191*7a9b00ceSrobert // who write [[noreturn]] after including <stdnoreturn.h> (where 'noreturn'
2192*7a9b00ceSrobert // is defined as a macro which expands to '_Noreturn').
2193*7a9b00ceSrobert if (!S.getLangOpts().CPlusPlus &&
2194*7a9b00ceSrobert A.getSemanticSpelling() == CXX11NoReturnAttr::C2x_Noreturn &&
2195*7a9b00ceSrobert !(A.getLoc().isMacroID() &&
2196*7a9b00ceSrobert S.getSourceManager().isInSystemMacro(A.getLoc())))
2197*7a9b00ceSrobert S.Diag(A.getLoc(), diag::warn_deprecated_noreturn_spelling) << A.getRange();
2198*7a9b00ceSrobert
2199*7a9b00ceSrobert D->addAttr(::new (S.Context) CXX11NoReturnAttr(S.Context, A));
2200*7a9b00ceSrobert }
2201*7a9b00ceSrobert
handleNoCfCheckAttr(Sema & S,Decl * D,const ParsedAttr & Attrs)2202e5dd7070Spatrick static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
2203e5dd7070Spatrick if (!S.getLangOpts().CFProtectionBranch)
2204e5dd7070Spatrick S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored);
2205e5dd7070Spatrick else
2206e5dd7070Spatrick handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs);
2207e5dd7070Spatrick }
2208e5dd7070Spatrick
CheckAttrNoArgs(const ParsedAttr & Attrs)2209e5dd7070Spatrick bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) {
2210a0747c9fSpatrick if (!Attrs.checkExactlyNumArgs(*this, 0)) {
2211e5dd7070Spatrick Attrs.setInvalid();
2212e5dd7070Spatrick return true;
2213e5dd7070Spatrick }
2214e5dd7070Spatrick
2215e5dd7070Spatrick return false;
2216e5dd7070Spatrick }
2217e5dd7070Spatrick
CheckAttrTarget(const ParsedAttr & AL)2218e5dd7070Spatrick bool Sema::CheckAttrTarget(const ParsedAttr &AL) {
2219e5dd7070Spatrick // Check whether the attribute is valid on the current target.
2220e5dd7070Spatrick if (!AL.existsInTarget(Context.getTargetInfo())) {
2221a0747c9fSpatrick Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
2222a0747c9fSpatrick << AL << AL.getRange();
2223e5dd7070Spatrick AL.setInvalid();
2224e5dd7070Spatrick return true;
2225e5dd7070Spatrick }
2226e5dd7070Spatrick
2227e5dd7070Spatrick return false;
2228e5dd7070Spatrick }
2229e5dd7070Spatrick
handleAnalyzerNoReturnAttr(Sema & S,Decl * D,const ParsedAttr & AL)2230e5dd7070Spatrick static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2231e5dd7070Spatrick
2232e5dd7070Spatrick // The checking path for 'noreturn' and 'analyzer_noreturn' are different
2233e5dd7070Spatrick // because 'analyzer_noreturn' does not impact the type.
2234e5dd7070Spatrick if (!isFunctionOrMethodOrBlock(D)) {
2235e5dd7070Spatrick ValueDecl *VD = dyn_cast<ValueDecl>(D);
2236e5dd7070Spatrick if (!VD || (!VD->getType()->isBlockPointerType() &&
2237e5dd7070Spatrick !VD->getType()->isFunctionPointerType())) {
2238a0747c9fSpatrick S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax()
2239e5dd7070Spatrick ? diag::err_attribute_wrong_decl_type
2240e5dd7070Spatrick : diag::warn_attribute_wrong_decl_type)
2241e5dd7070Spatrick << AL << ExpectedFunctionMethodOrBlock;
2242e5dd7070Spatrick return;
2243e5dd7070Spatrick }
2244e5dd7070Spatrick }
2245e5dd7070Spatrick
2246e5dd7070Spatrick D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL));
2247e5dd7070Spatrick }
2248e5dd7070Spatrick
2249e5dd7070Spatrick // PS3 PPU-specific.
handleVecReturnAttr(Sema & S,Decl * D,const ParsedAttr & AL)2250e5dd7070Spatrick static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2251e5dd7070Spatrick /*
2252e5dd7070Spatrick Returning a Vector Class in Registers
2253e5dd7070Spatrick
2254e5dd7070Spatrick According to the PPU ABI specifications, a class with a single member of
2255e5dd7070Spatrick vector type is returned in memory when used as the return value of a
2256e5dd7070Spatrick function.
2257e5dd7070Spatrick This results in inefficient code when implementing vector classes. To return
2258e5dd7070Spatrick the value in a single vector register, add the vecreturn attribute to the
2259e5dd7070Spatrick class definition. This attribute is also applicable to struct types.
2260e5dd7070Spatrick
2261e5dd7070Spatrick Example:
2262e5dd7070Spatrick
2263e5dd7070Spatrick struct Vector
2264e5dd7070Spatrick {
2265e5dd7070Spatrick __vector float xyzw;
2266e5dd7070Spatrick } __attribute__((vecreturn));
2267e5dd7070Spatrick
2268e5dd7070Spatrick Vector Add(Vector lhs, Vector rhs)
2269e5dd7070Spatrick {
2270e5dd7070Spatrick Vector result;
2271e5dd7070Spatrick result.xyzw = vec_add(lhs.xyzw, rhs.xyzw);
2272e5dd7070Spatrick return result; // This will be returned in a register
2273e5dd7070Spatrick }
2274e5dd7070Spatrick */
2275e5dd7070Spatrick if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) {
2276e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A;
2277e5dd7070Spatrick return;
2278e5dd7070Spatrick }
2279e5dd7070Spatrick
2280e5dd7070Spatrick const auto *R = cast<RecordDecl>(D);
2281e5dd7070Spatrick int count = 0;
2282e5dd7070Spatrick
2283e5dd7070Spatrick if (!isa<CXXRecordDecl>(R)) {
2284e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
2285e5dd7070Spatrick return;
2286e5dd7070Spatrick }
2287e5dd7070Spatrick
2288e5dd7070Spatrick if (!cast<CXXRecordDecl>(R)->isPOD()) {
2289e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record);
2290e5dd7070Spatrick return;
2291e5dd7070Spatrick }
2292e5dd7070Spatrick
2293e5dd7070Spatrick for (const auto *I : R->fields()) {
2294e5dd7070Spatrick if ((count == 1) || !I->getType()->isVectorType()) {
2295e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
2296e5dd7070Spatrick return;
2297e5dd7070Spatrick }
2298e5dd7070Spatrick count++;
2299e5dd7070Spatrick }
2300e5dd7070Spatrick
2301e5dd7070Spatrick D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL));
2302e5dd7070Spatrick }
2303e5dd7070Spatrick
handleDependencyAttr(Sema & S,Scope * Scope,Decl * D,const ParsedAttr & AL)2304e5dd7070Spatrick static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
2305e5dd7070Spatrick const ParsedAttr &AL) {
2306e5dd7070Spatrick if (isa<ParmVarDecl>(D)) {
2307e5dd7070Spatrick // [[carries_dependency]] can only be applied to a parameter if it is a
2308e5dd7070Spatrick // parameter of a function declaration or lambda.
2309e5dd7070Spatrick if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) {
2310e5dd7070Spatrick S.Diag(AL.getLoc(),
2311e5dd7070Spatrick diag::err_carries_dependency_param_not_function_decl);
2312e5dd7070Spatrick return;
2313e5dd7070Spatrick }
2314e5dd7070Spatrick }
2315e5dd7070Spatrick
2316e5dd7070Spatrick D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL));
2317e5dd7070Spatrick }
2318e5dd7070Spatrick
handleUnusedAttr(Sema & S,Decl * D,const ParsedAttr & AL)2319e5dd7070Spatrick static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2320e5dd7070Spatrick bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName();
2321e5dd7070Spatrick
2322e5dd7070Spatrick // If this is spelled as the standard C++17 attribute, but not in C++17, warn
2323e5dd7070Spatrick // about using it as an extension.
2324e5dd7070Spatrick if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr)
2325e5dd7070Spatrick S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
2326e5dd7070Spatrick
2327e5dd7070Spatrick D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
2328e5dd7070Spatrick }
2329e5dd7070Spatrick
handleConstructorAttr(Sema & S,Decl * D,const ParsedAttr & AL)2330e5dd7070Spatrick static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2331e5dd7070Spatrick uint32_t priority = ConstructorAttr::DefaultPriority;
2332*7a9b00ceSrobert if (S.getLangOpts().HLSL && AL.getNumArgs()) {
2333*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
2334*7a9b00ceSrobert return;
2335*7a9b00ceSrobert }
2336e5dd7070Spatrick if (AL.getNumArgs() &&
2337e5dd7070Spatrick !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
2338e5dd7070Spatrick return;
2339e5dd7070Spatrick
2340e5dd7070Spatrick D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
2341e5dd7070Spatrick }
2342e5dd7070Spatrick
handleDestructorAttr(Sema & S,Decl * D,const ParsedAttr & AL)2343e5dd7070Spatrick static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2344e5dd7070Spatrick uint32_t priority = DestructorAttr::DefaultPriority;
2345e5dd7070Spatrick if (AL.getNumArgs() &&
2346e5dd7070Spatrick !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
2347e5dd7070Spatrick return;
2348e5dd7070Spatrick
2349e5dd7070Spatrick D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
2350e5dd7070Spatrick }
2351e5dd7070Spatrick
2352e5dd7070Spatrick template <typename AttrTy>
handleAttrWithMessage(Sema & S,Decl * D,const ParsedAttr & AL)2353e5dd7070Spatrick static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
2354e5dd7070Spatrick // Handle the case where the attribute has a text message.
2355e5dd7070Spatrick StringRef Str;
2356e5dd7070Spatrick if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str))
2357e5dd7070Spatrick return;
2358e5dd7070Spatrick
2359e5dd7070Spatrick D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str));
2360e5dd7070Spatrick }
2361e5dd7070Spatrick
handleObjCSuppresProtocolAttr(Sema & S,Decl * D,const ParsedAttr & AL)2362e5dd7070Spatrick static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
2363e5dd7070Spatrick const ParsedAttr &AL) {
2364e5dd7070Spatrick if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) {
2365e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition)
2366e5dd7070Spatrick << AL << AL.getRange();
2367e5dd7070Spatrick return;
2368e5dd7070Spatrick }
2369e5dd7070Spatrick
2370e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL));
2371e5dd7070Spatrick }
2372e5dd7070Spatrick
checkAvailabilityAttr(Sema & S,SourceRange Range,IdentifierInfo * Platform,VersionTuple Introduced,VersionTuple Deprecated,VersionTuple Obsoleted)2373e5dd7070Spatrick static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
2374e5dd7070Spatrick IdentifierInfo *Platform,
2375e5dd7070Spatrick VersionTuple Introduced,
2376e5dd7070Spatrick VersionTuple Deprecated,
2377e5dd7070Spatrick VersionTuple Obsoleted) {
2378e5dd7070Spatrick StringRef PlatformName
2379e5dd7070Spatrick = AvailabilityAttr::getPrettyPlatformName(Platform->getName());
2380e5dd7070Spatrick if (PlatformName.empty())
2381e5dd7070Spatrick PlatformName = Platform->getName();
2382e5dd7070Spatrick
2383e5dd7070Spatrick // Ensure that Introduced <= Deprecated <= Obsoleted (although not all
2384e5dd7070Spatrick // of these steps are needed).
2385e5dd7070Spatrick if (!Introduced.empty() && !Deprecated.empty() &&
2386e5dd7070Spatrick !(Introduced <= Deprecated)) {
2387e5dd7070Spatrick S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
2388e5dd7070Spatrick << 1 << PlatformName << Deprecated.getAsString()
2389e5dd7070Spatrick << 0 << Introduced.getAsString();
2390e5dd7070Spatrick return true;
2391e5dd7070Spatrick }
2392e5dd7070Spatrick
2393e5dd7070Spatrick if (!Introduced.empty() && !Obsoleted.empty() &&
2394e5dd7070Spatrick !(Introduced <= Obsoleted)) {
2395e5dd7070Spatrick S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
2396e5dd7070Spatrick << 2 << PlatformName << Obsoleted.getAsString()
2397e5dd7070Spatrick << 0 << Introduced.getAsString();
2398e5dd7070Spatrick return true;
2399e5dd7070Spatrick }
2400e5dd7070Spatrick
2401e5dd7070Spatrick if (!Deprecated.empty() && !Obsoleted.empty() &&
2402e5dd7070Spatrick !(Deprecated <= Obsoleted)) {
2403e5dd7070Spatrick S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
2404e5dd7070Spatrick << 2 << PlatformName << Obsoleted.getAsString()
2405e5dd7070Spatrick << 1 << Deprecated.getAsString();
2406e5dd7070Spatrick return true;
2407e5dd7070Spatrick }
2408e5dd7070Spatrick
2409e5dd7070Spatrick return false;
2410e5dd7070Spatrick }
2411e5dd7070Spatrick
2412e5dd7070Spatrick /// Check whether the two versions match.
2413e5dd7070Spatrick ///
2414e5dd7070Spatrick /// If either version tuple is empty, then they are assumed to match. If
2415e5dd7070Spatrick /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y.
versionsMatch(const VersionTuple & X,const VersionTuple & Y,bool BeforeIsOkay)2416e5dd7070Spatrick static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
2417e5dd7070Spatrick bool BeforeIsOkay) {
2418e5dd7070Spatrick if (X.empty() || Y.empty())
2419e5dd7070Spatrick return true;
2420e5dd7070Spatrick
2421e5dd7070Spatrick if (X == Y)
2422e5dd7070Spatrick return true;
2423e5dd7070Spatrick
2424e5dd7070Spatrick if (BeforeIsOkay && X < Y)
2425e5dd7070Spatrick return true;
2426e5dd7070Spatrick
2427e5dd7070Spatrick return false;
2428e5dd7070Spatrick }
2429e5dd7070Spatrick
mergeAvailabilityAttr(NamedDecl * D,const AttributeCommonInfo & CI,IdentifierInfo * Platform,bool Implicit,VersionTuple Introduced,VersionTuple Deprecated,VersionTuple Obsoleted,bool IsUnavailable,StringRef Message,bool IsStrict,StringRef Replacement,AvailabilityMergeKind AMK,int Priority)2430e5dd7070Spatrick AvailabilityAttr *Sema::mergeAvailabilityAttr(
2431e5dd7070Spatrick NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
2432e5dd7070Spatrick bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
2433e5dd7070Spatrick VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
2434e5dd7070Spatrick bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
2435e5dd7070Spatrick int Priority) {
2436e5dd7070Spatrick VersionTuple MergedIntroduced = Introduced;
2437e5dd7070Spatrick VersionTuple MergedDeprecated = Deprecated;
2438e5dd7070Spatrick VersionTuple MergedObsoleted = Obsoleted;
2439e5dd7070Spatrick bool FoundAny = false;
2440e5dd7070Spatrick bool OverrideOrImpl = false;
2441e5dd7070Spatrick switch (AMK) {
2442e5dd7070Spatrick case AMK_None:
2443e5dd7070Spatrick case AMK_Redeclaration:
2444e5dd7070Spatrick OverrideOrImpl = false;
2445e5dd7070Spatrick break;
2446e5dd7070Spatrick
2447e5dd7070Spatrick case AMK_Override:
2448e5dd7070Spatrick case AMK_ProtocolImplementation:
2449a0747c9fSpatrick case AMK_OptionalProtocolImplementation:
2450e5dd7070Spatrick OverrideOrImpl = true;
2451e5dd7070Spatrick break;
2452e5dd7070Spatrick }
2453e5dd7070Spatrick
2454e5dd7070Spatrick if (D->hasAttrs()) {
2455e5dd7070Spatrick AttrVec &Attrs = D->getAttrs();
2456e5dd7070Spatrick for (unsigned i = 0, e = Attrs.size(); i != e;) {
2457e5dd7070Spatrick const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]);
2458e5dd7070Spatrick if (!OldAA) {
2459e5dd7070Spatrick ++i;
2460e5dd7070Spatrick continue;
2461e5dd7070Spatrick }
2462e5dd7070Spatrick
2463e5dd7070Spatrick IdentifierInfo *OldPlatform = OldAA->getPlatform();
2464e5dd7070Spatrick if (OldPlatform != Platform) {
2465e5dd7070Spatrick ++i;
2466e5dd7070Spatrick continue;
2467e5dd7070Spatrick }
2468e5dd7070Spatrick
2469e5dd7070Spatrick // If there is an existing availability attribute for this platform that
2470e5dd7070Spatrick // has a lower priority use the existing one and discard the new
2471e5dd7070Spatrick // attribute.
2472e5dd7070Spatrick if (OldAA->getPriority() < Priority)
2473e5dd7070Spatrick return nullptr;
2474e5dd7070Spatrick
2475e5dd7070Spatrick // If there is an existing attribute for this platform that has a higher
2476e5dd7070Spatrick // priority than the new attribute then erase the old one and continue
2477e5dd7070Spatrick // processing the attributes.
2478e5dd7070Spatrick if (OldAA->getPriority() > Priority) {
2479e5dd7070Spatrick Attrs.erase(Attrs.begin() + i);
2480e5dd7070Spatrick --e;
2481e5dd7070Spatrick continue;
2482e5dd7070Spatrick }
2483e5dd7070Spatrick
2484e5dd7070Spatrick FoundAny = true;
2485e5dd7070Spatrick VersionTuple OldIntroduced = OldAA->getIntroduced();
2486e5dd7070Spatrick VersionTuple OldDeprecated = OldAA->getDeprecated();
2487e5dd7070Spatrick VersionTuple OldObsoleted = OldAA->getObsoleted();
2488e5dd7070Spatrick bool OldIsUnavailable = OldAA->getUnavailable();
2489e5dd7070Spatrick
2490e5dd7070Spatrick if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl) ||
2491e5dd7070Spatrick !versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl) ||
2492e5dd7070Spatrick !versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl) ||
2493e5dd7070Spatrick !(OldIsUnavailable == IsUnavailable ||
2494e5dd7070Spatrick (OverrideOrImpl && !OldIsUnavailable && IsUnavailable))) {
2495e5dd7070Spatrick if (OverrideOrImpl) {
2496e5dd7070Spatrick int Which = -1;
2497e5dd7070Spatrick VersionTuple FirstVersion;
2498e5dd7070Spatrick VersionTuple SecondVersion;
2499e5dd7070Spatrick if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl)) {
2500e5dd7070Spatrick Which = 0;
2501e5dd7070Spatrick FirstVersion = OldIntroduced;
2502e5dd7070Spatrick SecondVersion = Introduced;
2503e5dd7070Spatrick } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) {
2504e5dd7070Spatrick Which = 1;
2505e5dd7070Spatrick FirstVersion = Deprecated;
2506e5dd7070Spatrick SecondVersion = OldDeprecated;
2507e5dd7070Spatrick } else if (!versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl)) {
2508e5dd7070Spatrick Which = 2;
2509e5dd7070Spatrick FirstVersion = Obsoleted;
2510e5dd7070Spatrick SecondVersion = OldObsoleted;
2511e5dd7070Spatrick }
2512e5dd7070Spatrick
2513e5dd7070Spatrick if (Which == -1) {
2514e5dd7070Spatrick Diag(OldAA->getLocation(),
2515e5dd7070Spatrick diag::warn_mismatched_availability_override_unavail)
2516e5dd7070Spatrick << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
2517e5dd7070Spatrick << (AMK == AMK_Override);
2518a0747c9fSpatrick } else if (Which != 1 && AMK == AMK_OptionalProtocolImplementation) {
2519a0747c9fSpatrick // Allow different 'introduced' / 'obsoleted' availability versions
2520a0747c9fSpatrick // on a method that implements an optional protocol requirement. It
2521a0747c9fSpatrick // makes less sense to allow this for 'deprecated' as the user can't
2522a0747c9fSpatrick // see if the method is 'deprecated' as 'respondsToSelector' will
2523a0747c9fSpatrick // still return true when the method is deprecated.
2524a0747c9fSpatrick ++i;
2525a0747c9fSpatrick continue;
2526e5dd7070Spatrick } else {
2527e5dd7070Spatrick Diag(OldAA->getLocation(),
2528e5dd7070Spatrick diag::warn_mismatched_availability_override)
2529e5dd7070Spatrick << Which
2530e5dd7070Spatrick << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
2531e5dd7070Spatrick << FirstVersion.getAsString() << SecondVersion.getAsString()
2532e5dd7070Spatrick << (AMK == AMK_Override);
2533e5dd7070Spatrick }
2534e5dd7070Spatrick if (AMK == AMK_Override)
2535e5dd7070Spatrick Diag(CI.getLoc(), diag::note_overridden_method);
2536e5dd7070Spatrick else
2537e5dd7070Spatrick Diag(CI.getLoc(), diag::note_protocol_method);
2538e5dd7070Spatrick } else {
2539e5dd7070Spatrick Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
2540e5dd7070Spatrick Diag(CI.getLoc(), diag::note_previous_attribute);
2541e5dd7070Spatrick }
2542e5dd7070Spatrick
2543e5dd7070Spatrick Attrs.erase(Attrs.begin() + i);
2544e5dd7070Spatrick --e;
2545e5dd7070Spatrick continue;
2546e5dd7070Spatrick }
2547e5dd7070Spatrick
2548e5dd7070Spatrick VersionTuple MergedIntroduced2 = MergedIntroduced;
2549e5dd7070Spatrick VersionTuple MergedDeprecated2 = MergedDeprecated;
2550e5dd7070Spatrick VersionTuple MergedObsoleted2 = MergedObsoleted;
2551e5dd7070Spatrick
2552e5dd7070Spatrick if (MergedIntroduced2.empty())
2553e5dd7070Spatrick MergedIntroduced2 = OldIntroduced;
2554e5dd7070Spatrick if (MergedDeprecated2.empty())
2555e5dd7070Spatrick MergedDeprecated2 = OldDeprecated;
2556e5dd7070Spatrick if (MergedObsoleted2.empty())
2557e5dd7070Spatrick MergedObsoleted2 = OldObsoleted;
2558e5dd7070Spatrick
2559e5dd7070Spatrick if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform,
2560e5dd7070Spatrick MergedIntroduced2, MergedDeprecated2,
2561e5dd7070Spatrick MergedObsoleted2)) {
2562e5dd7070Spatrick Attrs.erase(Attrs.begin() + i);
2563e5dd7070Spatrick --e;
2564e5dd7070Spatrick continue;
2565e5dd7070Spatrick }
2566e5dd7070Spatrick
2567e5dd7070Spatrick MergedIntroduced = MergedIntroduced2;
2568e5dd7070Spatrick MergedDeprecated = MergedDeprecated2;
2569e5dd7070Spatrick MergedObsoleted = MergedObsoleted2;
2570e5dd7070Spatrick ++i;
2571e5dd7070Spatrick }
2572e5dd7070Spatrick }
2573e5dd7070Spatrick
2574e5dd7070Spatrick if (FoundAny &&
2575e5dd7070Spatrick MergedIntroduced == Introduced &&
2576e5dd7070Spatrick MergedDeprecated == Deprecated &&
2577e5dd7070Spatrick MergedObsoleted == Obsoleted)
2578e5dd7070Spatrick return nullptr;
2579e5dd7070Spatrick
2580e5dd7070Spatrick // Only create a new attribute if !OverrideOrImpl, but we want to do
2581e5dd7070Spatrick // the checking.
2582e5dd7070Spatrick if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced,
2583e5dd7070Spatrick MergedDeprecated, MergedObsoleted) &&
2584e5dd7070Spatrick !OverrideOrImpl) {
2585e5dd7070Spatrick auto *Avail = ::new (Context) AvailabilityAttr(
2586e5dd7070Spatrick Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable,
2587e5dd7070Spatrick Message, IsStrict, Replacement, Priority);
2588e5dd7070Spatrick Avail->setImplicit(Implicit);
2589e5dd7070Spatrick return Avail;
2590e5dd7070Spatrick }
2591e5dd7070Spatrick return nullptr;
2592e5dd7070Spatrick }
2593e5dd7070Spatrick
handleAvailabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)2594e5dd7070Spatrick static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2595a0747c9fSpatrick if (isa<UsingDecl, UnresolvedUsingTypenameDecl, UnresolvedUsingValueDecl>(
2596a0747c9fSpatrick D)) {
2597a0747c9fSpatrick S.Diag(AL.getRange().getBegin(), diag::warn_deprecated_ignored_on_using)
2598a0747c9fSpatrick << AL;
2599a0747c9fSpatrick return;
2600a0747c9fSpatrick }
2601a0747c9fSpatrick
2602a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
2603e5dd7070Spatrick return;
2604e5dd7070Spatrick IdentifierLoc *Platform = AL.getArgAsIdent(0);
2605e5dd7070Spatrick
2606e5dd7070Spatrick IdentifierInfo *II = Platform->Ident;
2607e5dd7070Spatrick if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
2608e5dd7070Spatrick S.Diag(Platform->Loc, diag::warn_availability_unknown_platform)
2609e5dd7070Spatrick << Platform->Ident;
2610e5dd7070Spatrick
2611e5dd7070Spatrick auto *ND = dyn_cast<NamedDecl>(D);
2612e5dd7070Spatrick if (!ND) // We warned about this already, so just return.
2613e5dd7070Spatrick return;
2614e5dd7070Spatrick
2615e5dd7070Spatrick AvailabilityChange Introduced = AL.getAvailabilityIntroduced();
2616e5dd7070Spatrick AvailabilityChange Deprecated = AL.getAvailabilityDeprecated();
2617e5dd7070Spatrick AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted();
2618e5dd7070Spatrick bool IsUnavailable = AL.getUnavailableLoc().isValid();
2619e5dd7070Spatrick bool IsStrict = AL.getStrictLoc().isValid();
2620e5dd7070Spatrick StringRef Str;
2621e5dd7070Spatrick if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr()))
2622e5dd7070Spatrick Str = SE->getString();
2623e5dd7070Spatrick StringRef Replacement;
2624e5dd7070Spatrick if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr()))
2625e5dd7070Spatrick Replacement = SE->getString();
2626e5dd7070Spatrick
2627e5dd7070Spatrick if (II->isStr("swift")) {
2628e5dd7070Spatrick if (Introduced.isValid() || Obsoleted.isValid() ||
2629e5dd7070Spatrick (!IsUnavailable && !Deprecated.isValid())) {
2630e5dd7070Spatrick S.Diag(AL.getLoc(),
2631e5dd7070Spatrick diag::warn_availability_swift_unavailable_deprecated_only);
2632e5dd7070Spatrick return;
2633e5dd7070Spatrick }
2634e5dd7070Spatrick }
2635e5dd7070Spatrick
2636*7a9b00ceSrobert if (II->isStr("fuchsia")) {
2637*7a9b00ceSrobert std::optional<unsigned> Min, Sub;
2638*7a9b00ceSrobert if ((Min = Introduced.Version.getMinor()) ||
2639*7a9b00ceSrobert (Sub = Introduced.Version.getSubminor())) {
2640*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor);
2641*7a9b00ceSrobert return;
2642*7a9b00ceSrobert }
2643*7a9b00ceSrobert }
2644*7a9b00ceSrobert
2645e5dd7070Spatrick int PriorityModifier = AL.isPragmaClangAttribute()
2646e5dd7070Spatrick ? Sema::AP_PragmaClangAttribute
2647e5dd7070Spatrick : Sema::AP_Explicit;
2648e5dd7070Spatrick AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
2649e5dd7070Spatrick ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version,
2650e5dd7070Spatrick Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement,
2651e5dd7070Spatrick Sema::AMK_None, PriorityModifier);
2652e5dd7070Spatrick if (NewAttr)
2653e5dd7070Spatrick D->addAttr(NewAttr);
2654e5dd7070Spatrick
2655e5dd7070Spatrick // Transcribe "ios" to "watchos" (and add a new attribute) if the versioning
2656e5dd7070Spatrick // matches before the start of the watchOS platform.
2657e5dd7070Spatrick if (S.Context.getTargetInfo().getTriple().isWatchOS()) {
2658e5dd7070Spatrick IdentifierInfo *NewII = nullptr;
2659e5dd7070Spatrick if (II->getName() == "ios")
2660e5dd7070Spatrick NewII = &S.Context.Idents.get("watchos");
2661e5dd7070Spatrick else if (II->getName() == "ios_app_extension")
2662e5dd7070Spatrick NewII = &S.Context.Idents.get("watchos_app_extension");
2663e5dd7070Spatrick
2664e5dd7070Spatrick if (NewII) {
2665*7a9b00ceSrobert const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking();
2666*7a9b00ceSrobert const auto *IOSToWatchOSMapping =
2667*7a9b00ceSrobert SDKInfo ? SDKInfo->getVersionMapping(
2668*7a9b00ceSrobert DarwinSDKInfo::OSEnvPair::iOStoWatchOSPair())
2669*7a9b00ceSrobert : nullptr;
2670*7a9b00ceSrobert
2671*7a9b00ceSrobert auto adjustWatchOSVersion =
2672*7a9b00ceSrobert [IOSToWatchOSMapping](VersionTuple Version) -> VersionTuple {
2673e5dd7070Spatrick if (Version.empty())
2674e5dd7070Spatrick return Version;
2675*7a9b00ceSrobert auto MinimumWatchOSVersion = VersionTuple(2, 0);
2676*7a9b00ceSrobert
2677*7a9b00ceSrobert if (IOSToWatchOSMapping) {
2678*7a9b00ceSrobert if (auto MappedVersion = IOSToWatchOSMapping->map(
2679*7a9b00ceSrobert Version, MinimumWatchOSVersion, std::nullopt)) {
2680*7a9b00ceSrobert return *MappedVersion;
2681*7a9b00ceSrobert }
2682*7a9b00ceSrobert }
2683*7a9b00ceSrobert
2684e5dd7070Spatrick auto Major = Version.getMajor();
2685e5dd7070Spatrick auto NewMajor = Major >= 9 ? Major - 7 : 0;
2686e5dd7070Spatrick if (NewMajor >= 2) {
2687*7a9b00ceSrobert if (Version.getMinor()) {
2688*7a9b00ceSrobert if (Version.getSubminor())
2689*7a9b00ceSrobert return VersionTuple(NewMajor, *Version.getMinor(),
2690*7a9b00ceSrobert *Version.getSubminor());
2691e5dd7070Spatrick else
2692*7a9b00ceSrobert return VersionTuple(NewMajor, *Version.getMinor());
2693e5dd7070Spatrick }
2694e5dd7070Spatrick return VersionTuple(NewMajor);
2695e5dd7070Spatrick }
2696e5dd7070Spatrick
2697*7a9b00ceSrobert return MinimumWatchOSVersion;
2698e5dd7070Spatrick };
2699e5dd7070Spatrick
2700e5dd7070Spatrick auto NewIntroduced = adjustWatchOSVersion(Introduced.Version);
2701e5dd7070Spatrick auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version);
2702e5dd7070Spatrick auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
2703e5dd7070Spatrick
2704e5dd7070Spatrick AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
2705e5dd7070Spatrick ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
2706e5dd7070Spatrick NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
2707e5dd7070Spatrick Sema::AMK_None,
2708e5dd7070Spatrick PriorityModifier + Sema::AP_InferredFromOtherPlatform);
2709e5dd7070Spatrick if (NewAttr)
2710e5dd7070Spatrick D->addAttr(NewAttr);
2711e5dd7070Spatrick }
2712e5dd7070Spatrick } else if (S.Context.getTargetInfo().getTriple().isTvOS()) {
2713e5dd7070Spatrick // Transcribe "ios" to "tvos" (and add a new attribute) if the versioning
2714e5dd7070Spatrick // matches before the start of the tvOS platform.
2715e5dd7070Spatrick IdentifierInfo *NewII = nullptr;
2716e5dd7070Spatrick if (II->getName() == "ios")
2717e5dd7070Spatrick NewII = &S.Context.Idents.get("tvos");
2718e5dd7070Spatrick else if (II->getName() == "ios_app_extension")
2719e5dd7070Spatrick NewII = &S.Context.Idents.get("tvos_app_extension");
2720e5dd7070Spatrick
2721e5dd7070Spatrick if (NewII) {
2722*7a9b00ceSrobert const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking();
2723*7a9b00ceSrobert const auto *IOSToTvOSMapping =
2724*7a9b00ceSrobert SDKInfo ? SDKInfo->getVersionMapping(
2725*7a9b00ceSrobert DarwinSDKInfo::OSEnvPair::iOStoTvOSPair())
2726*7a9b00ceSrobert : nullptr;
2727*7a9b00ceSrobert
2728*7a9b00ceSrobert auto AdjustTvOSVersion =
2729*7a9b00ceSrobert [IOSToTvOSMapping](VersionTuple Version) -> VersionTuple {
2730*7a9b00ceSrobert if (Version.empty())
2731*7a9b00ceSrobert return Version;
2732*7a9b00ceSrobert
2733*7a9b00ceSrobert if (IOSToTvOSMapping) {
2734*7a9b00ceSrobert if (auto MappedVersion = IOSToTvOSMapping->map(
2735*7a9b00ceSrobert Version, VersionTuple(0, 0), std::nullopt)) {
2736*7a9b00ceSrobert return *MappedVersion;
2737*7a9b00ceSrobert }
2738*7a9b00ceSrobert }
2739*7a9b00ceSrobert return Version;
2740*7a9b00ceSrobert };
2741*7a9b00ceSrobert
2742*7a9b00ceSrobert auto NewIntroduced = AdjustTvOSVersion(Introduced.Version);
2743*7a9b00ceSrobert auto NewDeprecated = AdjustTvOSVersion(Deprecated.Version);
2744*7a9b00ceSrobert auto NewObsoleted = AdjustTvOSVersion(Obsoleted.Version);
2745*7a9b00ceSrobert
2746e5dd7070Spatrick AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
2747*7a9b00ceSrobert ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
2748*7a9b00ceSrobert NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
2749*7a9b00ceSrobert Sema::AMK_None,
2750e5dd7070Spatrick PriorityModifier + Sema::AP_InferredFromOtherPlatform);
2751e5dd7070Spatrick if (NewAttr)
2752e5dd7070Spatrick D->addAttr(NewAttr);
2753e5dd7070Spatrick }
2754a0747c9fSpatrick } else if (S.Context.getTargetInfo().getTriple().getOS() ==
2755a0747c9fSpatrick llvm::Triple::IOS &&
2756a0747c9fSpatrick S.Context.getTargetInfo().getTriple().isMacCatalystEnvironment()) {
2757a0747c9fSpatrick auto GetSDKInfo = [&]() {
2758a0747c9fSpatrick return S.getDarwinSDKInfoForAvailabilityChecking(AL.getRange().getBegin(),
2759a0747c9fSpatrick "macOS");
2760a0747c9fSpatrick };
2761a0747c9fSpatrick
2762a0747c9fSpatrick // Transcribe "ios" to "maccatalyst" (and add a new attribute).
2763a0747c9fSpatrick IdentifierInfo *NewII = nullptr;
2764a0747c9fSpatrick if (II->getName() == "ios")
2765a0747c9fSpatrick NewII = &S.Context.Idents.get("maccatalyst");
2766a0747c9fSpatrick else if (II->getName() == "ios_app_extension")
2767a0747c9fSpatrick NewII = &S.Context.Idents.get("maccatalyst_app_extension");
2768a0747c9fSpatrick if (NewII) {
2769a0747c9fSpatrick auto MinMacCatalystVersion = [](const VersionTuple &V) {
2770a0747c9fSpatrick if (V.empty())
2771a0747c9fSpatrick return V;
2772a0747c9fSpatrick if (V.getMajor() < 13 ||
2773a0747c9fSpatrick (V.getMajor() == 13 && V.getMinor() && *V.getMinor() < 1))
2774a0747c9fSpatrick return VersionTuple(13, 1); // The min Mac Catalyst version is 13.1.
2775a0747c9fSpatrick return V;
2776a0747c9fSpatrick };
2777a0747c9fSpatrick AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
2778a0747c9fSpatrick ND, AL.getRange(), NewII, true /*Implicit*/,
2779a0747c9fSpatrick MinMacCatalystVersion(Introduced.Version),
2780a0747c9fSpatrick MinMacCatalystVersion(Deprecated.Version),
2781a0747c9fSpatrick MinMacCatalystVersion(Obsoleted.Version), IsUnavailable, Str,
2782a0747c9fSpatrick IsStrict, Replacement, Sema::AMK_None,
2783a0747c9fSpatrick PriorityModifier + Sema::AP_InferredFromOtherPlatform);
2784a0747c9fSpatrick if (NewAttr)
2785a0747c9fSpatrick D->addAttr(NewAttr);
2786a0747c9fSpatrick } else if (II->getName() == "macos" && GetSDKInfo() &&
2787a0747c9fSpatrick (!Introduced.Version.empty() || !Deprecated.Version.empty() ||
2788a0747c9fSpatrick !Obsoleted.Version.empty())) {
2789a0747c9fSpatrick if (const auto *MacOStoMacCatalystMapping =
2790a0747c9fSpatrick GetSDKInfo()->getVersionMapping(
2791a0747c9fSpatrick DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
2792a0747c9fSpatrick // Infer Mac Catalyst availability from the macOS availability attribute
2793a0747c9fSpatrick // if it has versioned availability. Don't infer 'unavailable'. This
2794a0747c9fSpatrick // inferred availability has lower priority than the other availability
2795a0747c9fSpatrick // attributes that are inferred from 'ios'.
2796a0747c9fSpatrick NewII = &S.Context.Idents.get("maccatalyst");
2797a0747c9fSpatrick auto RemapMacOSVersion =
2798*7a9b00ceSrobert [&](const VersionTuple &V) -> std::optional<VersionTuple> {
2799a0747c9fSpatrick if (V.empty())
2800*7a9b00ceSrobert return std::nullopt;
2801a0747c9fSpatrick // API_TO_BE_DEPRECATED is 100000.
2802a0747c9fSpatrick if (V.getMajor() == 100000)
2803a0747c9fSpatrick return VersionTuple(100000);
2804a0747c9fSpatrick // The minimum iosmac version is 13.1
2805*7a9b00ceSrobert return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1),
2806*7a9b00ceSrobert std::nullopt);
2807a0747c9fSpatrick };
2808*7a9b00ceSrobert std::optional<VersionTuple> NewIntroduced =
2809a0747c9fSpatrick RemapMacOSVersion(Introduced.Version),
2810a0747c9fSpatrick NewDeprecated =
2811a0747c9fSpatrick RemapMacOSVersion(Deprecated.Version),
2812a0747c9fSpatrick NewObsoleted =
2813a0747c9fSpatrick RemapMacOSVersion(Obsoleted.Version);
2814a0747c9fSpatrick if (NewIntroduced || NewDeprecated || NewObsoleted) {
2815a0747c9fSpatrick auto VersionOrEmptyVersion =
2816*7a9b00ceSrobert [](const std::optional<VersionTuple> &V) -> VersionTuple {
2817a0747c9fSpatrick return V ? *V : VersionTuple();
2818a0747c9fSpatrick };
2819a0747c9fSpatrick AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
2820a0747c9fSpatrick ND, AL.getRange(), NewII, true /*Implicit*/,
2821a0747c9fSpatrick VersionOrEmptyVersion(NewIntroduced),
2822a0747c9fSpatrick VersionOrEmptyVersion(NewDeprecated),
2823a0747c9fSpatrick VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str,
2824a0747c9fSpatrick IsStrict, Replacement, Sema::AMK_None,
2825a0747c9fSpatrick PriorityModifier + Sema::AP_InferredFromOtherPlatform +
2826a0747c9fSpatrick Sema::AP_InferredFromOtherPlatform);
2827a0747c9fSpatrick if (NewAttr)
2828a0747c9fSpatrick D->addAttr(NewAttr);
2829a0747c9fSpatrick }
2830a0747c9fSpatrick }
2831a0747c9fSpatrick }
2832e5dd7070Spatrick }
2833e5dd7070Spatrick }
2834e5dd7070Spatrick
handleExternalSourceSymbolAttr(Sema & S,Decl * D,const ParsedAttr & AL)2835e5dd7070Spatrick static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
2836e5dd7070Spatrick const ParsedAttr &AL) {
2837a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3))
2838e5dd7070Spatrick return;
2839e5dd7070Spatrick
2840e5dd7070Spatrick StringRef Language;
2841e5dd7070Spatrick if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0)))
2842e5dd7070Spatrick Language = SE->getString();
2843e5dd7070Spatrick StringRef DefinedIn;
2844e5dd7070Spatrick if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1)))
2845e5dd7070Spatrick DefinedIn = SE->getString();
2846e5dd7070Spatrick bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
2847e5dd7070Spatrick
2848e5dd7070Spatrick D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
2849e5dd7070Spatrick S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration));
2850e5dd7070Spatrick }
2851e5dd7070Spatrick
2852e5dd7070Spatrick template <class T>
mergeVisibilityAttr(Sema & S,Decl * D,const AttributeCommonInfo & CI,typename T::VisibilityType value)2853e5dd7070Spatrick static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
2854e5dd7070Spatrick typename T::VisibilityType value) {
2855e5dd7070Spatrick T *existingAttr = D->getAttr<T>();
2856e5dd7070Spatrick if (existingAttr) {
2857e5dd7070Spatrick typename T::VisibilityType existingValue = existingAttr->getVisibility();
2858e5dd7070Spatrick if (existingValue == value)
2859e5dd7070Spatrick return nullptr;
2860e5dd7070Spatrick S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
2861e5dd7070Spatrick S.Diag(CI.getLoc(), diag::note_previous_attribute);
2862e5dd7070Spatrick D->dropAttr<T>();
2863e5dd7070Spatrick }
2864e5dd7070Spatrick return ::new (S.Context) T(S.Context, CI, value);
2865e5dd7070Spatrick }
2866e5dd7070Spatrick
mergeVisibilityAttr(Decl * D,const AttributeCommonInfo & CI,VisibilityAttr::VisibilityType Vis)2867e5dd7070Spatrick VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D,
2868e5dd7070Spatrick const AttributeCommonInfo &CI,
2869e5dd7070Spatrick VisibilityAttr::VisibilityType Vis) {
2870e5dd7070Spatrick return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis);
2871e5dd7070Spatrick }
2872e5dd7070Spatrick
2873e5dd7070Spatrick TypeVisibilityAttr *
mergeTypeVisibilityAttr(Decl * D,const AttributeCommonInfo & CI,TypeVisibilityAttr::VisibilityType Vis)2874e5dd7070Spatrick Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
2875e5dd7070Spatrick TypeVisibilityAttr::VisibilityType Vis) {
2876e5dd7070Spatrick return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis);
2877e5dd7070Spatrick }
2878e5dd7070Spatrick
handleVisibilityAttr(Sema & S,Decl * D,const ParsedAttr & AL,bool isTypeVisibility)2879e5dd7070Spatrick static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
2880e5dd7070Spatrick bool isTypeVisibility) {
2881e5dd7070Spatrick // Visibility attributes don't mean anything on a typedef.
2882e5dd7070Spatrick if (isa<TypedefNameDecl>(D)) {
2883e5dd7070Spatrick S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
2884e5dd7070Spatrick return;
2885e5dd7070Spatrick }
2886e5dd7070Spatrick
2887e5dd7070Spatrick // 'type_visibility' can only go on a type or namespace.
2888e5dd7070Spatrick if (isTypeVisibility &&
2889e5dd7070Spatrick !(isa<TagDecl>(D) ||
2890e5dd7070Spatrick isa<ObjCInterfaceDecl>(D) ||
2891e5dd7070Spatrick isa<NamespaceDecl>(D))) {
2892e5dd7070Spatrick S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
2893e5dd7070Spatrick << AL << ExpectedTypeOrNamespace;
2894e5dd7070Spatrick return;
2895e5dd7070Spatrick }
2896e5dd7070Spatrick
2897e5dd7070Spatrick // Check that the argument is a string literal.
2898e5dd7070Spatrick StringRef TypeStr;
2899e5dd7070Spatrick SourceLocation LiteralLoc;
2900e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc))
2901e5dd7070Spatrick return;
2902e5dd7070Spatrick
2903e5dd7070Spatrick VisibilityAttr::VisibilityType type;
2904e5dd7070Spatrick if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) {
2905e5dd7070Spatrick S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << AL
2906e5dd7070Spatrick << TypeStr;
2907e5dd7070Spatrick return;
2908e5dd7070Spatrick }
2909e5dd7070Spatrick
2910e5dd7070Spatrick // Complain about attempts to use protected visibility on targets
2911e5dd7070Spatrick // (like Darwin) that don't support it.
2912e5dd7070Spatrick if (type == VisibilityAttr::Protected &&
2913e5dd7070Spatrick !S.Context.getTargetInfo().hasProtectedVisibility()) {
2914e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility);
2915e5dd7070Spatrick type = VisibilityAttr::Default;
2916e5dd7070Spatrick }
2917e5dd7070Spatrick
2918e5dd7070Spatrick Attr *newAttr;
2919e5dd7070Spatrick if (isTypeVisibility) {
2920e5dd7070Spatrick newAttr = S.mergeTypeVisibilityAttr(
2921e5dd7070Spatrick D, AL, (TypeVisibilityAttr::VisibilityType)type);
2922e5dd7070Spatrick } else {
2923e5dd7070Spatrick newAttr = S.mergeVisibilityAttr(D, AL, type);
2924e5dd7070Spatrick }
2925e5dd7070Spatrick if (newAttr)
2926e5dd7070Spatrick D->addAttr(newAttr);
2927e5dd7070Spatrick }
2928e5dd7070Spatrick
handleObjCDirectAttr(Sema & S,Decl * D,const ParsedAttr & AL)2929e5dd7070Spatrick static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2930e5dd7070Spatrick // objc_direct cannot be set on methods declared in the context of a protocol
2931e5dd7070Spatrick if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
2932e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
2933e5dd7070Spatrick return;
2934e5dd7070Spatrick }
2935e5dd7070Spatrick
2936e5dd7070Spatrick if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
2937e5dd7070Spatrick handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
2938e5dd7070Spatrick } else {
2939e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
2940e5dd7070Spatrick }
2941e5dd7070Spatrick }
2942e5dd7070Spatrick
handleObjCDirectMembersAttr(Sema & S,Decl * D,const ParsedAttr & AL)2943e5dd7070Spatrick static void handleObjCDirectMembersAttr(Sema &S, Decl *D,
2944e5dd7070Spatrick const ParsedAttr &AL) {
2945e5dd7070Spatrick if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
2946e5dd7070Spatrick handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
2947e5dd7070Spatrick } else {
2948e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
2949e5dd7070Spatrick }
2950e5dd7070Spatrick }
2951e5dd7070Spatrick
handleObjCMethodFamilyAttr(Sema & S,Decl * D,const ParsedAttr & AL)2952e5dd7070Spatrick static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2953e5dd7070Spatrick const auto *M = cast<ObjCMethodDecl>(D);
2954e5dd7070Spatrick if (!AL.isArgIdent(0)) {
2955e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
2956e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
2957e5dd7070Spatrick return;
2958e5dd7070Spatrick }
2959e5dd7070Spatrick
2960e5dd7070Spatrick IdentifierLoc *IL = AL.getArgAsIdent(0);
2961e5dd7070Spatrick ObjCMethodFamilyAttr::FamilyKind F;
2962e5dd7070Spatrick if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) {
2963e5dd7070Spatrick S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident;
2964e5dd7070Spatrick return;
2965e5dd7070Spatrick }
2966e5dd7070Spatrick
2967e5dd7070Spatrick if (F == ObjCMethodFamilyAttr::OMF_init &&
2968e5dd7070Spatrick !M->getReturnType()->isObjCObjectPointerType()) {
2969e5dd7070Spatrick S.Diag(M->getLocation(), diag::err_init_method_bad_return_type)
2970e5dd7070Spatrick << M->getReturnType();
2971e5dd7070Spatrick // Ignore the attribute.
2972e5dd7070Spatrick return;
2973e5dd7070Spatrick }
2974e5dd7070Spatrick
2975e5dd7070Spatrick D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F));
2976e5dd7070Spatrick }
2977e5dd7070Spatrick
handleObjCNSObject(Sema & S,Decl * D,const ParsedAttr & AL)2978e5dd7070Spatrick static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
2979e5dd7070Spatrick if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
2980e5dd7070Spatrick QualType T = TD->getUnderlyingType();
2981e5dd7070Spatrick if (!T->isCARCBridgableType()) {
2982e5dd7070Spatrick S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
2983e5dd7070Spatrick return;
2984e5dd7070Spatrick }
2985e5dd7070Spatrick }
2986e5dd7070Spatrick else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
2987e5dd7070Spatrick QualType T = PD->getType();
2988e5dd7070Spatrick if (!T->isCARCBridgableType()) {
2989e5dd7070Spatrick S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
2990e5dd7070Spatrick return;
2991e5dd7070Spatrick }
2992e5dd7070Spatrick }
2993e5dd7070Spatrick else {
2994e5dd7070Spatrick // It is okay to include this attribute on properties, e.g.:
2995e5dd7070Spatrick //
2996e5dd7070Spatrick // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
2997e5dd7070Spatrick //
2998e5dd7070Spatrick // In this case it follows tradition and suppresses an error in the above
2999e5dd7070Spatrick // case.
3000e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
3001e5dd7070Spatrick }
3002e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL));
3003e5dd7070Spatrick }
3004e5dd7070Spatrick
handleObjCIndependentClass(Sema & S,Decl * D,const ParsedAttr & AL)3005e5dd7070Spatrick static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
3006e5dd7070Spatrick if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
3007e5dd7070Spatrick QualType T = TD->getUnderlyingType();
3008e5dd7070Spatrick if (!T->isObjCObjectPointerType()) {
3009e5dd7070Spatrick S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute);
3010e5dd7070Spatrick return;
3011e5dd7070Spatrick }
3012e5dd7070Spatrick } else {
3013e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
3014e5dd7070Spatrick return;
3015e5dd7070Spatrick }
3016e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL));
3017e5dd7070Spatrick }
3018e5dd7070Spatrick
handleBlocksAttr(Sema & S,Decl * D,const ParsedAttr & AL)3019e5dd7070Spatrick static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3020e5dd7070Spatrick if (!AL.isArgIdent(0)) {
3021e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
3022e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
3023e5dd7070Spatrick return;
3024e5dd7070Spatrick }
3025e5dd7070Spatrick
3026e5dd7070Spatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
3027e5dd7070Spatrick BlocksAttr::BlockType type;
3028e5dd7070Spatrick if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) {
3029e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
3030e5dd7070Spatrick return;
3031e5dd7070Spatrick }
3032e5dd7070Spatrick
3033e5dd7070Spatrick D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type));
3034e5dd7070Spatrick }
3035e5dd7070Spatrick
handleSentinelAttr(Sema & S,Decl * D,const ParsedAttr & AL)3036e5dd7070Spatrick static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3037e5dd7070Spatrick unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
3038e5dd7070Spatrick if (AL.getNumArgs() > 0) {
3039e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
3040*7a9b00ceSrobert std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
3041*7a9b00ceSrobert if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
3042e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
3043e5dd7070Spatrick << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange();
3044e5dd7070Spatrick return;
3045e5dd7070Spatrick }
3046e5dd7070Spatrick
3047a0747c9fSpatrick if (Idx->isSigned() && Idx->isNegative()) {
3048e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero)
3049e5dd7070Spatrick << E->getSourceRange();
3050e5dd7070Spatrick return;
3051e5dd7070Spatrick }
3052e5dd7070Spatrick
3053a0747c9fSpatrick sentinel = Idx->getZExtValue();
3054e5dd7070Spatrick }
3055e5dd7070Spatrick
3056e5dd7070Spatrick unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos;
3057e5dd7070Spatrick if (AL.getNumArgs() > 1) {
3058e5dd7070Spatrick Expr *E = AL.getArgAsExpr(1);
3059*7a9b00ceSrobert std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
3060*7a9b00ceSrobert if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
3061e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
3062e5dd7070Spatrick << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange();
3063e5dd7070Spatrick return;
3064e5dd7070Spatrick }
3065a0747c9fSpatrick nullPos = Idx->getZExtValue();
3066e5dd7070Spatrick
3067a0747c9fSpatrick if ((Idx->isSigned() && Idx->isNegative()) || nullPos > 1) {
3068e5dd7070Spatrick // FIXME: This error message could be improved, it would be nice
3069e5dd7070Spatrick // to say what the bounds actually are.
3070e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one)
3071e5dd7070Spatrick << E->getSourceRange();
3072e5dd7070Spatrick return;
3073e5dd7070Spatrick }
3074e5dd7070Spatrick }
3075e5dd7070Spatrick
3076e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3077e5dd7070Spatrick const FunctionType *FT = FD->getType()->castAs<FunctionType>();
3078e5dd7070Spatrick if (isa<FunctionNoProtoType>(FT)) {
3079e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments);
3080e5dd7070Spatrick return;
3081e5dd7070Spatrick }
3082e5dd7070Spatrick
3083e5dd7070Spatrick if (!cast<FunctionProtoType>(FT)->isVariadic()) {
3084e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
3085e5dd7070Spatrick return;
3086e5dd7070Spatrick }
3087e5dd7070Spatrick } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
3088e5dd7070Spatrick if (!MD->isVariadic()) {
3089e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
3090e5dd7070Spatrick return;
3091e5dd7070Spatrick }
3092e5dd7070Spatrick } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
3093e5dd7070Spatrick if (!BD->isVariadic()) {
3094e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1;
3095e5dd7070Spatrick return;
3096e5dd7070Spatrick }
3097e5dd7070Spatrick } else if (const auto *V = dyn_cast<VarDecl>(D)) {
3098e5dd7070Spatrick QualType Ty = V->getType();
3099e5dd7070Spatrick if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
3100e5dd7070Spatrick const FunctionType *FT = Ty->isFunctionPointerType()
3101e5dd7070Spatrick ? D->getFunctionType()
3102a0747c9fSpatrick : Ty->castAs<BlockPointerType>()
3103a0747c9fSpatrick ->getPointeeType()
3104a0747c9fSpatrick ->castAs<FunctionType>();
3105e5dd7070Spatrick if (!cast<FunctionProtoType>(FT)->isVariadic()) {
3106e5dd7070Spatrick int m = Ty->isFunctionPointerType() ? 0 : 1;
3107e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
3108e5dd7070Spatrick return;
3109e5dd7070Spatrick }
3110e5dd7070Spatrick } else {
3111e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
3112e5dd7070Spatrick << AL << ExpectedFunctionMethodOrBlock;
3113e5dd7070Spatrick return;
3114e5dd7070Spatrick }
3115e5dd7070Spatrick } else {
3116e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
3117e5dd7070Spatrick << AL << ExpectedFunctionMethodOrBlock;
3118e5dd7070Spatrick return;
3119e5dd7070Spatrick }
3120e5dd7070Spatrick D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos));
3121e5dd7070Spatrick }
3122e5dd7070Spatrick
handleWarnUnusedResult(Sema & S,Decl * D,const ParsedAttr & AL)3123e5dd7070Spatrick static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
3124e5dd7070Spatrick if (D->getFunctionType() &&
3125e5dd7070Spatrick D->getFunctionType()->getReturnType()->isVoidType() &&
3126e5dd7070Spatrick !isa<CXXConstructorDecl>(D)) {
3127e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0;
3128e5dd7070Spatrick return;
3129e5dd7070Spatrick }
3130e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
3131e5dd7070Spatrick if (MD->getReturnType()->isVoidType()) {
3132e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 1;
3133e5dd7070Spatrick return;
3134e5dd7070Spatrick }
3135e5dd7070Spatrick
3136e5dd7070Spatrick StringRef Str;
3137a0747c9fSpatrick if (AL.isStandardAttributeSyntax() && !AL.getScopeName()) {
3138ec727ea7Spatrick // The standard attribute cannot be applied to variable declarations such
3139ec727ea7Spatrick // as a function pointer.
3140ec727ea7Spatrick if (isa<VarDecl>(D))
3141ec727ea7Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
3142ec727ea7Spatrick << AL << "functions, classes, or enumerations";
3143ec727ea7Spatrick
3144e5dd7070Spatrick // If this is spelled as the standard C++17 attribute, but not in C++17,
3145e5dd7070Spatrick // warn about using it as an extension. If there are attribute arguments,
3146e5dd7070Spatrick // then claim it's a C++2a extension instead.
3147e5dd7070Spatrick // FIXME: If WG14 does not seem likely to adopt the same feature, add an
3148e5dd7070Spatrick // extension warning for C2x mode.
3149e5dd7070Spatrick const LangOptions &LO = S.getLangOpts();
3150e5dd7070Spatrick if (AL.getNumArgs() == 1) {
3151ec727ea7Spatrick if (LO.CPlusPlus && !LO.CPlusPlus20)
3152ec727ea7Spatrick S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL;
3153e5dd7070Spatrick
3154*7a9b00ceSrobert // Since this is spelled [[nodiscard]], get the optional string
3155e5dd7070Spatrick // literal. If in C++ mode, but not in C++2a mode, diagnose as an
3156e5dd7070Spatrick // extension.
3157e5dd7070Spatrick // FIXME: C2x should support this feature as well, even as an extension.
3158e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr))
3159e5dd7070Spatrick return;
3160e5dd7070Spatrick } else if (LO.CPlusPlus && !LO.CPlusPlus17)
3161e5dd7070Spatrick S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
3162e5dd7070Spatrick }
3163e5dd7070Spatrick
3164*7a9b00ceSrobert if ((!AL.isGNUAttribute() &&
3165*7a9b00ceSrobert !(AL.isStandardAttributeSyntax() && AL.isClangScope())) &&
3166*7a9b00ceSrobert isa<TypedefNameDecl>(D)) {
3167*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_unused_result_typedef_unsupported_spelling)
3168*7a9b00ceSrobert << AL.isGNUScope();
3169*7a9b00ceSrobert return;
3170*7a9b00ceSrobert }
3171*7a9b00ceSrobert
3172e5dd7070Spatrick D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
3173e5dd7070Spatrick }
3174e5dd7070Spatrick
handleWeakImportAttr(Sema & S,Decl * D,const ParsedAttr & AL)3175e5dd7070Spatrick static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3176e5dd7070Spatrick // weak_import only applies to variable & function declarations.
3177e5dd7070Spatrick bool isDef = false;
3178e5dd7070Spatrick if (!D->canBeWeakImported(isDef)) {
3179e5dd7070Spatrick if (isDef)
3180e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition)
3181e5dd7070Spatrick << "weak_import";
3182e5dd7070Spatrick else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
3183e5dd7070Spatrick (S.Context.getTargetInfo().getTriple().isOSDarwin() &&
3184e5dd7070Spatrick (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) {
3185e5dd7070Spatrick // Nothing to warn about here.
3186e5dd7070Spatrick } else
3187e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
3188e5dd7070Spatrick << AL << ExpectedVariableOrFunction;
3189e5dd7070Spatrick
3190e5dd7070Spatrick return;
3191e5dd7070Spatrick }
3192e5dd7070Spatrick
3193e5dd7070Spatrick D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL));
3194e5dd7070Spatrick }
3195e5dd7070Spatrick
3196e5dd7070Spatrick // Handles reqd_work_group_size and work_group_size_hint.
3197e5dd7070Spatrick template <typename WorkGroupAttr>
handleWorkGroupSize(Sema & S,Decl * D,const ParsedAttr & AL)3198e5dd7070Spatrick static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
3199e5dd7070Spatrick uint32_t WGSize[3];
3200e5dd7070Spatrick for (unsigned i = 0; i < 3; ++i) {
3201e5dd7070Spatrick const Expr *E = AL.getArgAsExpr(i);
3202e5dd7070Spatrick if (!checkUInt32Argument(S, AL, E, WGSize[i], i,
3203e5dd7070Spatrick /*StrictlyUnsigned=*/true))
3204e5dd7070Spatrick return;
3205e5dd7070Spatrick if (WGSize[i] == 0) {
3206e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
3207e5dd7070Spatrick << AL << E->getSourceRange();
3208e5dd7070Spatrick return;
3209e5dd7070Spatrick }
3210e5dd7070Spatrick }
3211e5dd7070Spatrick
3212e5dd7070Spatrick WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>();
3213e5dd7070Spatrick if (Existing && !(Existing->getXDim() == WGSize[0] &&
3214e5dd7070Spatrick Existing->getYDim() == WGSize[1] &&
3215e5dd7070Spatrick Existing->getZDim() == WGSize[2]))
3216e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3217e5dd7070Spatrick
3218e5dd7070Spatrick D->addAttr(::new (S.Context)
3219e5dd7070Spatrick WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2]));
3220e5dd7070Spatrick }
3221e5dd7070Spatrick
3222e5dd7070Spatrick // Handles intel_reqd_sub_group_size.
handleSubGroupSize(Sema & S,Decl * D,const ParsedAttr & AL)3223e5dd7070Spatrick static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
3224e5dd7070Spatrick uint32_t SGSize;
3225e5dd7070Spatrick const Expr *E = AL.getArgAsExpr(0);
3226e5dd7070Spatrick if (!checkUInt32Argument(S, AL, E, SGSize))
3227e5dd7070Spatrick return;
3228e5dd7070Spatrick if (SGSize == 0) {
3229e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
3230e5dd7070Spatrick << AL << E->getSourceRange();
3231e5dd7070Spatrick return;
3232e5dd7070Spatrick }
3233e5dd7070Spatrick
3234e5dd7070Spatrick OpenCLIntelReqdSubGroupSizeAttr *Existing =
3235e5dd7070Spatrick D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
3236e5dd7070Spatrick if (Existing && Existing->getSubGroupSize() != SGSize)
3237e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3238e5dd7070Spatrick
3239e5dd7070Spatrick D->addAttr(::new (S.Context)
3240e5dd7070Spatrick OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
3241e5dd7070Spatrick }
3242e5dd7070Spatrick
handleVecTypeHint(Sema & S,Decl * D,const ParsedAttr & AL)3243e5dd7070Spatrick static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
3244e5dd7070Spatrick if (!AL.hasParsedType()) {
3245e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
3246e5dd7070Spatrick return;
3247e5dd7070Spatrick }
3248e5dd7070Spatrick
3249e5dd7070Spatrick TypeSourceInfo *ParmTSI = nullptr;
3250e5dd7070Spatrick QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI);
3251e5dd7070Spatrick assert(ParmTSI && "no type source info for attribute argument");
3252e5dd7070Spatrick
3253e5dd7070Spatrick if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
3254e5dd7070Spatrick (ParmType->isBooleanType() ||
3255e5dd7070Spatrick !ParmType->isIntegralType(S.getASTContext()))) {
3256e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 2 << AL;
3257e5dd7070Spatrick return;
3258e5dd7070Spatrick }
3259e5dd7070Spatrick
3260e5dd7070Spatrick if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) {
3261e5dd7070Spatrick if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) {
3262e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3263e5dd7070Spatrick return;
3264e5dd7070Spatrick }
3265e5dd7070Spatrick }
3266e5dd7070Spatrick
3267e5dd7070Spatrick D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI));
3268e5dd7070Spatrick }
3269e5dd7070Spatrick
mergeSectionAttr(Decl * D,const AttributeCommonInfo & CI,StringRef Name)3270e5dd7070Spatrick SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
3271e5dd7070Spatrick StringRef Name) {
3272e5dd7070Spatrick // Explicit or partial specializations do not inherit
3273e5dd7070Spatrick // the section attribute from the primary template.
3274e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3275e5dd7070Spatrick if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate &&
3276e5dd7070Spatrick FD->isFunctionTemplateSpecialization())
3277e5dd7070Spatrick return nullptr;
3278e5dd7070Spatrick }
3279e5dd7070Spatrick if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
3280e5dd7070Spatrick if (ExistingAttr->getName() == Name)
3281e5dd7070Spatrick return nullptr;
3282e5dd7070Spatrick Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
3283e5dd7070Spatrick << 1 /*section*/;
3284e5dd7070Spatrick Diag(CI.getLoc(), diag::note_previous_attribute);
3285e5dd7070Spatrick return nullptr;
3286e5dd7070Spatrick }
3287e5dd7070Spatrick return ::new (Context) SectionAttr(Context, CI, Name);
3288e5dd7070Spatrick }
3289e5dd7070Spatrick
3290a0747c9fSpatrick /// Used to implement to perform semantic checking on
3291a0747c9fSpatrick /// attribute((section("foo"))) specifiers.
3292a0747c9fSpatrick ///
3293a0747c9fSpatrick /// In this case, "foo" is passed in to be checked. If the section
3294a0747c9fSpatrick /// specifier is invalid, return an Error that indicates the problem.
3295a0747c9fSpatrick ///
3296a0747c9fSpatrick /// This is a simple quality of implementation feature to catch errors
3297a0747c9fSpatrick /// and give good diagnostics in cases when the assembler or code generator
3298a0747c9fSpatrick /// would otherwise reject the section specifier.
isValidSectionSpecifier(StringRef SecName)3299a0747c9fSpatrick llvm::Error Sema::isValidSectionSpecifier(StringRef SecName) {
3300a0747c9fSpatrick if (!Context.getTargetInfo().getTriple().isOSDarwin())
3301a0747c9fSpatrick return llvm::Error::success();
3302a0747c9fSpatrick
3303a0747c9fSpatrick // Let MCSectionMachO validate this.
3304a0747c9fSpatrick StringRef Segment, Section;
3305a0747c9fSpatrick unsigned TAA, StubSize;
3306a0747c9fSpatrick bool HasTAA;
3307a0747c9fSpatrick return llvm::MCSectionMachO::ParseSectionSpecifier(SecName, Segment, Section,
3308a0747c9fSpatrick TAA, HasTAA, StubSize);
3309a0747c9fSpatrick }
3310a0747c9fSpatrick
checkSectionName(SourceLocation LiteralLoc,StringRef SecName)3311e5dd7070Spatrick bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
3312a0747c9fSpatrick if (llvm::Error E = isValidSectionSpecifier(SecName)) {
3313a0747c9fSpatrick Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
3314a0747c9fSpatrick << toString(std::move(E)) << 1 /*'section'*/;
3315e5dd7070Spatrick return false;
3316e5dd7070Spatrick }
3317e5dd7070Spatrick return true;
3318e5dd7070Spatrick }
3319e5dd7070Spatrick
handleSectionAttr(Sema & S,Decl * D,const ParsedAttr & AL)3320e5dd7070Spatrick static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3321e5dd7070Spatrick // Make sure that there is a string literal as the sections's single
3322e5dd7070Spatrick // argument.
3323e5dd7070Spatrick StringRef Str;
3324e5dd7070Spatrick SourceLocation LiteralLoc;
3325e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
3326e5dd7070Spatrick return;
3327e5dd7070Spatrick
3328e5dd7070Spatrick if (!S.checkSectionName(LiteralLoc, Str))
3329e5dd7070Spatrick return;
3330e5dd7070Spatrick
3331e5dd7070Spatrick SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str);
3332a0747c9fSpatrick if (NewAttr) {
3333e5dd7070Spatrick D->addAttr(NewAttr);
3334a0747c9fSpatrick if (isa<FunctionDecl, FunctionTemplateDecl, ObjCMethodDecl,
3335a0747c9fSpatrick ObjCPropertyDecl>(D))
3336a0747c9fSpatrick S.UnifySection(NewAttr->getName(),
3337a0747c9fSpatrick ASTContext::PSF_Execute | ASTContext::PSF_Read,
3338a0747c9fSpatrick cast<NamedDecl>(D));
3339a0747c9fSpatrick }
3340e5dd7070Spatrick }
3341e5dd7070Spatrick
3342e5dd7070Spatrick // This is used for `__declspec(code_seg("segname"))` on a decl.
3343e5dd7070Spatrick // `#pragma code_seg("segname")` uses checkSectionName() instead.
checkCodeSegName(Sema & S,SourceLocation LiteralLoc,StringRef CodeSegName)3344e5dd7070Spatrick static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
3345e5dd7070Spatrick StringRef CodeSegName) {
3346a0747c9fSpatrick if (llvm::Error E = S.isValidSectionSpecifier(CodeSegName)) {
3347e5dd7070Spatrick S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
3348a0747c9fSpatrick << toString(std::move(E)) << 0 /*'code-seg'*/;
3349e5dd7070Spatrick return false;
3350e5dd7070Spatrick }
3351e5dd7070Spatrick
3352e5dd7070Spatrick return true;
3353e5dd7070Spatrick }
3354e5dd7070Spatrick
mergeCodeSegAttr(Decl * D,const AttributeCommonInfo & CI,StringRef Name)3355e5dd7070Spatrick CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI,
3356e5dd7070Spatrick StringRef Name) {
3357e5dd7070Spatrick // Explicit or partial specializations do not inherit
3358e5dd7070Spatrick // the code_seg attribute from the primary template.
3359e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3360e5dd7070Spatrick if (FD->isFunctionTemplateSpecialization())
3361e5dd7070Spatrick return nullptr;
3362e5dd7070Spatrick }
3363e5dd7070Spatrick if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
3364e5dd7070Spatrick if (ExistingAttr->getName() == Name)
3365e5dd7070Spatrick return nullptr;
3366e5dd7070Spatrick Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
3367e5dd7070Spatrick << 0 /*codeseg*/;
3368e5dd7070Spatrick Diag(CI.getLoc(), diag::note_previous_attribute);
3369e5dd7070Spatrick return nullptr;
3370e5dd7070Spatrick }
3371e5dd7070Spatrick return ::new (Context) CodeSegAttr(Context, CI, Name);
3372e5dd7070Spatrick }
3373e5dd7070Spatrick
handleCodeSegAttr(Sema & S,Decl * D,const ParsedAttr & AL)3374e5dd7070Spatrick static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3375e5dd7070Spatrick StringRef Str;
3376e5dd7070Spatrick SourceLocation LiteralLoc;
3377e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
3378e5dd7070Spatrick return;
3379e5dd7070Spatrick if (!checkCodeSegName(S, LiteralLoc, Str))
3380e5dd7070Spatrick return;
3381e5dd7070Spatrick if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
3382e5dd7070Spatrick if (!ExistingAttr->isImplicit()) {
3383e5dd7070Spatrick S.Diag(AL.getLoc(),
3384e5dd7070Spatrick ExistingAttr->getName() == Str
3385e5dd7070Spatrick ? diag::warn_duplicate_codeseg_attribute
3386e5dd7070Spatrick : diag::err_conflicting_codeseg_attribute);
3387e5dd7070Spatrick return;
3388e5dd7070Spatrick }
3389e5dd7070Spatrick D->dropAttr<CodeSegAttr>();
3390e5dd7070Spatrick }
3391e5dd7070Spatrick if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str))
3392e5dd7070Spatrick D->addAttr(CSA);
3393e5dd7070Spatrick }
3394e5dd7070Spatrick
3395e5dd7070Spatrick // Check for things we'd like to warn about. Multiversioning issues are
3396e5dd7070Spatrick // handled later in the process, once we know how many exist.
checkTargetAttr(SourceLocation LiteralLoc,StringRef AttrStr)3397e5dd7070Spatrick bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
3398a0747c9fSpatrick enum FirstParam { Unsupported, Duplicate, Unknown };
3399*7a9b00ceSrobert enum SecondParam { None, CPU, Tune };
3400*7a9b00ceSrobert enum ThirdParam { Target, TargetClones };
3401*7a9b00ceSrobert if (AttrStr.contains("fpmath="))
3402e5dd7070Spatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3403*7a9b00ceSrobert << Unsupported << None << "fpmath=" << Target;
3404a0747c9fSpatrick
3405a0747c9fSpatrick // Diagnose use of tune if target doesn't support it.
3406a0747c9fSpatrick if (!Context.getTargetInfo().supportsTargetAttributeTune() &&
3407*7a9b00ceSrobert AttrStr.contains("tune="))
3408a0747c9fSpatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3409*7a9b00ceSrobert << Unsupported << None << "tune=" << Target;
3410e5dd7070Spatrick
3411*7a9b00ceSrobert ParsedTargetAttr ParsedAttrs =
3412*7a9b00ceSrobert Context.getTargetInfo().parseTargetAttr(AttrStr);
3413e5dd7070Spatrick
3414*7a9b00ceSrobert if (!ParsedAttrs.CPU.empty() &&
3415*7a9b00ceSrobert !Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU))
3416e5dd7070Spatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3417*7a9b00ceSrobert << Unknown << CPU << ParsedAttrs.CPU << Target;
3418a0747c9fSpatrick
3419a0747c9fSpatrick if (!ParsedAttrs.Tune.empty() &&
3420a0747c9fSpatrick !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune))
3421a0747c9fSpatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3422*7a9b00ceSrobert << Unknown << Tune << ParsedAttrs.Tune << Target;
3423e5dd7070Spatrick
3424*7a9b00ceSrobert if (ParsedAttrs.Duplicate != "")
3425e5dd7070Spatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3426*7a9b00ceSrobert << Duplicate << None << ParsedAttrs.Duplicate << Target;
3427e5dd7070Spatrick
3428e5dd7070Spatrick for (const auto &Feature : ParsedAttrs.Features) {
3429e5dd7070Spatrick auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
3430e5dd7070Spatrick if (!Context.getTargetInfo().isValidFeatureName(CurFeature))
3431e5dd7070Spatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3432*7a9b00ceSrobert << Unsupported << None << CurFeature << Target;
3433e5dd7070Spatrick }
3434e5dd7070Spatrick
3435e5dd7070Spatrick TargetInfo::BranchProtectionInfo BPI;
3436*7a9b00ceSrobert StringRef DiagMsg;
3437*7a9b00ceSrobert if (ParsedAttrs.BranchProtection.empty())
3438*7a9b00ceSrobert return false;
3439*7a9b00ceSrobert if (!Context.getTargetInfo().validateBranchProtection(
3440*7a9b00ceSrobert ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) {
3441*7a9b00ceSrobert if (DiagMsg.empty())
3442e5dd7070Spatrick return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3443*7a9b00ceSrobert << Unsupported << None << "branch-protection" << Target;
3444e5dd7070Spatrick return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec)
3445*7a9b00ceSrobert << DiagMsg;
3446e5dd7070Spatrick }
3447*7a9b00ceSrobert if (!DiagMsg.empty())
3448*7a9b00ceSrobert Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg;
3449e5dd7070Spatrick
3450e5dd7070Spatrick return false;
3451e5dd7070Spatrick }
3452e5dd7070Spatrick
3453*7a9b00ceSrobert // Check Target Version attrs
checkTargetVersionAttr(SourceLocation LiteralLoc,StringRef & AttrStr,bool & isDefault)3454*7a9b00ceSrobert bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr,
3455*7a9b00ceSrobert bool &isDefault) {
3456*7a9b00ceSrobert enum FirstParam { Unsupported };
3457*7a9b00ceSrobert enum SecondParam { None };
3458*7a9b00ceSrobert enum ThirdParam { Target, TargetClones, TargetVersion };
3459*7a9b00ceSrobert if (AttrStr.trim() == "default")
3460*7a9b00ceSrobert isDefault = true;
3461*7a9b00ceSrobert llvm::SmallVector<StringRef, 8> Features;
3462*7a9b00ceSrobert AttrStr.split(Features, "+");
3463*7a9b00ceSrobert for (auto &CurFeature : Features) {
3464*7a9b00ceSrobert CurFeature = CurFeature.trim();
3465*7a9b00ceSrobert if (CurFeature == "default")
3466*7a9b00ceSrobert continue;
3467*7a9b00ceSrobert if (!Context.getTargetInfo().validateCpuSupports(CurFeature))
3468*7a9b00ceSrobert return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3469*7a9b00ceSrobert << Unsupported << None << CurFeature << TargetVersion;
3470*7a9b00ceSrobert }
3471*7a9b00ceSrobert return false;
3472*7a9b00ceSrobert }
3473*7a9b00ceSrobert
handleTargetVersionAttr(Sema & S,Decl * D,const ParsedAttr & AL)3474*7a9b00ceSrobert static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3475*7a9b00ceSrobert StringRef Str;
3476*7a9b00ceSrobert SourceLocation LiteralLoc;
3477*7a9b00ceSrobert bool isDefault = false;
3478*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
3479*7a9b00ceSrobert S.checkTargetVersionAttr(LiteralLoc, Str, isDefault))
3480*7a9b00ceSrobert return;
3481*7a9b00ceSrobert // Do not create default only target_version attribute
3482*7a9b00ceSrobert if (!isDefault) {
3483*7a9b00ceSrobert TargetVersionAttr *NewAttr =
3484*7a9b00ceSrobert ::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
3485*7a9b00ceSrobert D->addAttr(NewAttr);
3486*7a9b00ceSrobert }
3487*7a9b00ceSrobert }
3488*7a9b00ceSrobert
handleTargetAttr(Sema & S,Decl * D,const ParsedAttr & AL)3489e5dd7070Spatrick static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3490e5dd7070Spatrick StringRef Str;
3491e5dd7070Spatrick SourceLocation LiteralLoc;
3492e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
3493e5dd7070Spatrick S.checkTargetAttr(LiteralLoc, Str))
3494e5dd7070Spatrick return;
3495e5dd7070Spatrick
3496e5dd7070Spatrick TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str);
3497e5dd7070Spatrick D->addAttr(NewAttr);
3498e5dd7070Spatrick }
3499e5dd7070Spatrick
checkTargetClonesAttrString(SourceLocation LiteralLoc,StringRef Str,const StringLiteral * Literal,bool & HasDefault,bool & HasCommas,bool & HasNotDefault,SmallVectorImpl<SmallString<64>> & StringsBuffer)3500*7a9b00ceSrobert bool Sema::checkTargetClonesAttrString(
3501*7a9b00ceSrobert SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal,
3502*7a9b00ceSrobert bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
3503*7a9b00ceSrobert SmallVectorImpl<SmallString<64>> &StringsBuffer) {
3504*7a9b00ceSrobert enum FirstParam { Unsupported, Duplicate, Unknown };
3505*7a9b00ceSrobert enum SecondParam { None, CPU, Tune };
3506*7a9b00ceSrobert enum ThirdParam { Target, TargetClones };
3507*7a9b00ceSrobert HasCommas = HasCommas || Str.contains(',');
3508*7a9b00ceSrobert // Warn on empty at the beginning of a string.
3509*7a9b00ceSrobert if (Str.size() == 0)
3510*7a9b00ceSrobert return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3511*7a9b00ceSrobert << Unsupported << None << "" << TargetClones;
3512*7a9b00ceSrobert
3513*7a9b00ceSrobert std::pair<StringRef, StringRef> Parts = {{}, Str};
3514*7a9b00ceSrobert while (!Parts.second.empty()) {
3515*7a9b00ceSrobert Parts = Parts.second.split(',');
3516*7a9b00ceSrobert StringRef Cur = Parts.first.trim();
3517*7a9b00ceSrobert SourceLocation CurLoc = Literal->getLocationOfByte(
3518*7a9b00ceSrobert Cur.data() - Literal->getString().data(), getSourceManager(),
3519*7a9b00ceSrobert getLangOpts(), Context.getTargetInfo());
3520*7a9b00ceSrobert
3521*7a9b00ceSrobert bool DefaultIsDupe = false;
3522*7a9b00ceSrobert bool HasCodeGenImpact = false;
3523*7a9b00ceSrobert if (Cur.empty())
3524*7a9b00ceSrobert return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3525*7a9b00ceSrobert << Unsupported << None << "" << TargetClones;
3526*7a9b00ceSrobert
3527*7a9b00ceSrobert if (Context.getTargetInfo().getTriple().isAArch64()) {
3528*7a9b00ceSrobert // AArch64 target clones specific
3529*7a9b00ceSrobert if (Cur == "default") {
3530*7a9b00ceSrobert DefaultIsDupe = HasDefault;
3531*7a9b00ceSrobert HasDefault = true;
3532*7a9b00ceSrobert if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
3533*7a9b00ceSrobert Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3534*7a9b00ceSrobert else
3535*7a9b00ceSrobert StringsBuffer.push_back(Cur);
3536*7a9b00ceSrobert } else {
3537*7a9b00ceSrobert std::pair<StringRef, StringRef> CurParts = {{}, Cur};
3538*7a9b00ceSrobert llvm::SmallVector<StringRef, 8> CurFeatures;
3539*7a9b00ceSrobert while (!CurParts.second.empty()) {
3540*7a9b00ceSrobert CurParts = CurParts.second.split('+');
3541*7a9b00ceSrobert StringRef CurFeature = CurParts.first.trim();
3542*7a9b00ceSrobert if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) {
3543*7a9b00ceSrobert Diag(CurLoc, diag::warn_unsupported_target_attribute)
3544*7a9b00ceSrobert << Unsupported << None << CurFeature << TargetClones;
3545*7a9b00ceSrobert continue;
3546*7a9b00ceSrobert }
3547*7a9b00ceSrobert std::string Options;
3548*7a9b00ceSrobert if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options))
3549*7a9b00ceSrobert HasCodeGenImpact = true;
3550*7a9b00ceSrobert CurFeatures.push_back(CurFeature);
3551*7a9b00ceSrobert }
3552*7a9b00ceSrobert // Canonize TargetClones Attributes
3553*7a9b00ceSrobert llvm::sort(CurFeatures);
3554*7a9b00ceSrobert SmallString<64> Res;
3555*7a9b00ceSrobert for (auto &CurFeat : CurFeatures) {
3556*7a9b00ceSrobert if (!Res.equals(""))
3557*7a9b00ceSrobert Res.append("+");
3558*7a9b00ceSrobert Res.append(CurFeat);
3559*7a9b00ceSrobert }
3560*7a9b00ceSrobert if (llvm::is_contained(StringsBuffer, Res) || DefaultIsDupe)
3561*7a9b00ceSrobert Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3562*7a9b00ceSrobert else if (!HasCodeGenImpact)
3563*7a9b00ceSrobert // Ignore features in target_clone attribute that don't impact
3564*7a9b00ceSrobert // code generation
3565*7a9b00ceSrobert Diag(CurLoc, diag::warn_target_clone_no_impact_options);
3566*7a9b00ceSrobert else if (!Res.empty()) {
3567*7a9b00ceSrobert StringsBuffer.push_back(Res);
3568*7a9b00ceSrobert HasNotDefault = true;
3569*7a9b00ceSrobert }
3570*7a9b00ceSrobert }
3571*7a9b00ceSrobert } else {
3572*7a9b00ceSrobert // Other targets ( currently X86 )
3573*7a9b00ceSrobert if (Cur.startswith("arch=")) {
3574*7a9b00ceSrobert if (!Context.getTargetInfo().isValidCPUName(
3575*7a9b00ceSrobert Cur.drop_front(sizeof("arch=") - 1)))
3576*7a9b00ceSrobert return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3577*7a9b00ceSrobert << Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1)
3578*7a9b00ceSrobert << TargetClones;
3579*7a9b00ceSrobert } else if (Cur == "default") {
3580*7a9b00ceSrobert DefaultIsDupe = HasDefault;
3581*7a9b00ceSrobert HasDefault = true;
3582*7a9b00ceSrobert } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
3583*7a9b00ceSrobert return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3584*7a9b00ceSrobert << Unsupported << None << Cur << TargetClones;
3585*7a9b00ceSrobert if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
3586*7a9b00ceSrobert Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3587*7a9b00ceSrobert // Note: Add even if there are duplicates, since it changes name mangling.
3588*7a9b00ceSrobert StringsBuffer.push_back(Cur);
3589*7a9b00ceSrobert }
3590*7a9b00ceSrobert }
3591*7a9b00ceSrobert if (Str.rtrim().endswith(","))
3592*7a9b00ceSrobert return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3593*7a9b00ceSrobert << Unsupported << None << "" << TargetClones;
3594*7a9b00ceSrobert return false;
3595*7a9b00ceSrobert }
3596*7a9b00ceSrobert
handleTargetClonesAttr(Sema & S,Decl * D,const ParsedAttr & AL)3597*7a9b00ceSrobert static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3598*7a9b00ceSrobert if (S.Context.getTargetInfo().getTriple().isAArch64() &&
3599*7a9b00ceSrobert !S.Context.getTargetInfo().hasFeature("fmv"))
3600*7a9b00ceSrobert return;
3601*7a9b00ceSrobert
3602*7a9b00ceSrobert // Ensure we don't combine these with themselves, since that causes some
3603*7a9b00ceSrobert // confusing behavior.
3604*7a9b00ceSrobert if (const auto *Other = D->getAttr<TargetClonesAttr>()) {
3605*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
3606*7a9b00ceSrobert S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
3607*7a9b00ceSrobert return;
3608*7a9b00ceSrobert }
3609*7a9b00ceSrobert if (checkAttrMutualExclusion<TargetClonesAttr>(S, D, AL))
3610*7a9b00ceSrobert return;
3611*7a9b00ceSrobert
3612*7a9b00ceSrobert SmallVector<StringRef, 2> Strings;
3613*7a9b00ceSrobert SmallVector<SmallString<64>, 2> StringsBuffer;
3614*7a9b00ceSrobert bool HasCommas = false, HasDefault = false, HasNotDefault = false;
3615*7a9b00ceSrobert
3616*7a9b00ceSrobert for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
3617*7a9b00ceSrobert StringRef CurStr;
3618*7a9b00ceSrobert SourceLocation LiteralLoc;
3619*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) ||
3620*7a9b00ceSrobert S.checkTargetClonesAttrString(
3621*7a9b00ceSrobert LiteralLoc, CurStr,
3622*7a9b00ceSrobert cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()),
3623*7a9b00ceSrobert HasDefault, HasCommas, HasNotDefault, StringsBuffer))
3624*7a9b00ceSrobert return;
3625*7a9b00ceSrobert }
3626*7a9b00ceSrobert for (auto &SmallStr : StringsBuffer)
3627*7a9b00ceSrobert Strings.push_back(SmallStr.str());
3628*7a9b00ceSrobert
3629*7a9b00ceSrobert if (HasCommas && AL.getNumArgs() > 1)
3630*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values);
3631*7a9b00ceSrobert
3632*7a9b00ceSrobert if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) {
3633*7a9b00ceSrobert // Add default attribute if there is no one
3634*7a9b00ceSrobert HasDefault = true;
3635*7a9b00ceSrobert Strings.push_back("default");
3636*7a9b00ceSrobert }
3637*7a9b00ceSrobert
3638*7a9b00ceSrobert if (!HasDefault) {
3639*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default);
3640*7a9b00ceSrobert return;
3641*7a9b00ceSrobert }
3642*7a9b00ceSrobert
3643*7a9b00ceSrobert // FIXME: We could probably figure out how to get this to work for lambdas
3644*7a9b00ceSrobert // someday.
3645*7a9b00ceSrobert if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3646*7a9b00ceSrobert if (MD->getParent()->isLambda()) {
3647*7a9b00ceSrobert S.Diag(D->getLocation(), diag::err_multiversion_doesnt_support)
3648*7a9b00ceSrobert << static_cast<unsigned>(MultiVersionKind::TargetClones)
3649*7a9b00ceSrobert << /*Lambda*/ 9;
3650*7a9b00ceSrobert return;
3651*7a9b00ceSrobert }
3652*7a9b00ceSrobert }
3653*7a9b00ceSrobert
3654*7a9b00ceSrobert // No multiversion if we have default version only.
3655*7a9b00ceSrobert if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasNotDefault)
3656*7a9b00ceSrobert return;
3657*7a9b00ceSrobert
3658*7a9b00ceSrobert cast<FunctionDecl>(D)->setIsMultiVersion();
3659*7a9b00ceSrobert TargetClonesAttr *NewAttr = ::new (S.Context)
3660*7a9b00ceSrobert TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size());
3661*7a9b00ceSrobert D->addAttr(NewAttr);
3662*7a9b00ceSrobert }
3663*7a9b00ceSrobert
handleMinVectorWidthAttr(Sema & S,Decl * D,const ParsedAttr & AL)3664e5dd7070Spatrick static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3665e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
3666e5dd7070Spatrick uint32_t VecWidth;
3667e5dd7070Spatrick if (!checkUInt32Argument(S, AL, E, VecWidth)) {
3668e5dd7070Spatrick AL.setInvalid();
3669e5dd7070Spatrick return;
3670e5dd7070Spatrick }
3671e5dd7070Spatrick
3672e5dd7070Spatrick MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>();
3673e5dd7070Spatrick if (Existing && Existing->getVectorWidth() != VecWidth) {
3674e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3675e5dd7070Spatrick return;
3676e5dd7070Spatrick }
3677e5dd7070Spatrick
3678e5dd7070Spatrick D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth));
3679e5dd7070Spatrick }
3680e5dd7070Spatrick
handleCleanupAttr(Sema & S,Decl * D,const ParsedAttr & AL)3681e5dd7070Spatrick static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3682e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
3683e5dd7070Spatrick SourceLocation Loc = E->getExprLoc();
3684e5dd7070Spatrick FunctionDecl *FD = nullptr;
3685e5dd7070Spatrick DeclarationNameInfo NI;
3686e5dd7070Spatrick
3687e5dd7070Spatrick // gcc only allows for simple identifiers. Since we support more than gcc, we
3688e5dd7070Spatrick // will warn the user.
3689e5dd7070Spatrick if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
3690e5dd7070Spatrick if (DRE->hasQualifier())
3691e5dd7070Spatrick S.Diag(Loc, diag::warn_cleanup_ext);
3692e5dd7070Spatrick FD = dyn_cast<FunctionDecl>(DRE->getDecl());
3693e5dd7070Spatrick NI = DRE->getNameInfo();
3694e5dd7070Spatrick if (!FD) {
3695e5dd7070Spatrick S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1
3696e5dd7070Spatrick << NI.getName();
3697e5dd7070Spatrick return;
3698e5dd7070Spatrick }
3699e5dd7070Spatrick } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
3700e5dd7070Spatrick if (ULE->hasExplicitTemplateArgs())
3701e5dd7070Spatrick S.Diag(Loc, diag::warn_cleanup_ext);
3702e5dd7070Spatrick FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
3703e5dd7070Spatrick NI = ULE->getNameInfo();
3704e5dd7070Spatrick if (!FD) {
3705e5dd7070Spatrick S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2
3706e5dd7070Spatrick << NI.getName();
3707e5dd7070Spatrick if (ULE->getType() == S.Context.OverloadTy)
3708e5dd7070Spatrick S.NoteAllOverloadCandidates(ULE);
3709e5dd7070Spatrick return;
3710e5dd7070Spatrick }
3711e5dd7070Spatrick } else {
3712e5dd7070Spatrick S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 0;
3713e5dd7070Spatrick return;
3714e5dd7070Spatrick }
3715e5dd7070Spatrick
3716e5dd7070Spatrick if (FD->getNumParams() != 1) {
3717e5dd7070Spatrick S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg)
3718e5dd7070Spatrick << NI.getName();
3719e5dd7070Spatrick return;
3720e5dd7070Spatrick }
3721e5dd7070Spatrick
3722e5dd7070Spatrick // We're currently more strict than GCC about what function types we accept.
3723e5dd7070Spatrick // If this ever proves to be a problem it should be easy to fix.
3724e5dd7070Spatrick QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
3725e5dd7070Spatrick QualType ParamTy = FD->getParamDecl(0)->getType();
3726e5dd7070Spatrick if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
3727e5dd7070Spatrick ParamTy, Ty) != Sema::Compatible) {
3728e5dd7070Spatrick S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type)
3729e5dd7070Spatrick << NI.getName() << ParamTy << Ty;
3730e5dd7070Spatrick return;
3731e5dd7070Spatrick }
3732e5dd7070Spatrick
3733e5dd7070Spatrick D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
3734e5dd7070Spatrick }
3735e5dd7070Spatrick
handleEnumExtensibilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)3736e5dd7070Spatrick static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
3737e5dd7070Spatrick const ParsedAttr &AL) {
3738e5dd7070Spatrick if (!AL.isArgIdent(0)) {
3739e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
3740e5dd7070Spatrick << AL << 0 << AANT_ArgumentIdentifier;
3741e5dd7070Spatrick return;
3742e5dd7070Spatrick }
3743e5dd7070Spatrick
3744e5dd7070Spatrick EnumExtensibilityAttr::Kind ExtensibilityKind;
3745e5dd7070Spatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
3746e5dd7070Spatrick if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(),
3747e5dd7070Spatrick ExtensibilityKind)) {
3748e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
3749e5dd7070Spatrick return;
3750e5dd7070Spatrick }
3751e5dd7070Spatrick
3752e5dd7070Spatrick D->addAttr(::new (S.Context)
3753e5dd7070Spatrick EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind));
3754e5dd7070Spatrick }
3755e5dd7070Spatrick
3756e5dd7070Spatrick /// Handle __attribute__((format_arg((idx)))) attribute based on
3757e5dd7070Spatrick /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
handleFormatArgAttr(Sema & S,Decl * D,const ParsedAttr & AL)3758e5dd7070Spatrick static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3759e5dd7070Spatrick Expr *IdxExpr = AL.getArgAsExpr(0);
3760e5dd7070Spatrick ParamIdx Idx;
3761e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx))
3762e5dd7070Spatrick return;
3763e5dd7070Spatrick
3764e5dd7070Spatrick // Make sure the format string is really a string.
3765e5dd7070Spatrick QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
3766e5dd7070Spatrick
3767e5dd7070Spatrick bool NotNSStringTy = !isNSStringType(Ty, S.Context);
3768e5dd7070Spatrick if (NotNSStringTy &&
3769e5dd7070Spatrick !isCFStringType(Ty, S.Context) &&
3770e5dd7070Spatrick (!Ty->isPointerType() ||
3771e5dd7070Spatrick !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
3772e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_format_attribute_not)
3773*7a9b00ceSrobert << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
3774e5dd7070Spatrick return;
3775e5dd7070Spatrick }
3776e5dd7070Spatrick Ty = getFunctionOrMethodResultType(D);
3777*7a9b00ceSrobert // replace instancetype with the class type
3778*7a9b00ceSrobert auto Instancetype = S.Context.getObjCInstanceTypeDecl()->getTypeForDecl();
3779*7a9b00ceSrobert if (Ty->getAs<TypedefType>() == Instancetype)
3780*7a9b00ceSrobert if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
3781*7a9b00ceSrobert if (auto *Interface = OMD->getClassInterface())
3782*7a9b00ceSrobert Ty = S.Context.getObjCObjectPointerType(
3783*7a9b00ceSrobert QualType(Interface->getTypeForDecl(), 0));
3784a0747c9fSpatrick if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) &&
3785e5dd7070Spatrick !isCFStringType(Ty, S.Context) &&
3786e5dd7070Spatrick (!Ty->isPointerType() ||
3787e5dd7070Spatrick !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
3788e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
3789e5dd7070Spatrick << (NotNSStringTy ? "string type" : "NSString")
3790e5dd7070Spatrick << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
3791e5dd7070Spatrick return;
3792e5dd7070Spatrick }
3793e5dd7070Spatrick
3794e5dd7070Spatrick D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx));
3795e5dd7070Spatrick }
3796e5dd7070Spatrick
3797e5dd7070Spatrick enum FormatAttrKind {
3798e5dd7070Spatrick CFStringFormat,
3799e5dd7070Spatrick NSStringFormat,
3800e5dd7070Spatrick StrftimeFormat,
3801e5dd7070Spatrick SupportedFormat,
3802e5dd7070Spatrick IgnoredFormat,
3803e5dd7070Spatrick InvalidFormat
3804e5dd7070Spatrick };
3805e5dd7070Spatrick
3806e5dd7070Spatrick /// getFormatAttrKind - Map from format attribute names to supported format
3807e5dd7070Spatrick /// types.
getFormatAttrKind(StringRef Format)3808e5dd7070Spatrick static FormatAttrKind getFormatAttrKind(StringRef Format) {
3809e5dd7070Spatrick return llvm::StringSwitch<FormatAttrKind>(Format)
3810e5dd7070Spatrick // Check for formats that get handled specially.
3811e5dd7070Spatrick .Case("NSString", NSStringFormat)
3812e5dd7070Spatrick .Case("CFString", CFStringFormat)
3813e5dd7070Spatrick .Case("strftime", StrftimeFormat)
3814e5dd7070Spatrick
3815e5dd7070Spatrick // Otherwise, check for supported formats.
3816e5dd7070Spatrick .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
3817e5dd7070Spatrick .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
3818e5dd7070Spatrick .Case("kprintf", SupportedFormat) // OpenBSD.
3819e5dd7070Spatrick .Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
3820e5dd7070Spatrick .Case("os_trace", SupportedFormat)
3821e5dd7070Spatrick .Case("os_log", SupportedFormat)
3822adae0cfdSpatrick .Case("syslog", SupportedFormat)
3823e5dd7070Spatrick
3824e5dd7070Spatrick .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
3825e5dd7070Spatrick .Default(InvalidFormat);
3826e5dd7070Spatrick }
3827e5dd7070Spatrick
3828e5dd7070Spatrick /// Handle __attribute__((init_priority(priority))) attributes based on
3829e5dd7070Spatrick /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html
handleInitPriorityAttr(Sema & S,Decl * D,const ParsedAttr & AL)3830e5dd7070Spatrick static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3831e5dd7070Spatrick if (!S.getLangOpts().CPlusPlus) {
3832e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
3833e5dd7070Spatrick return;
3834e5dd7070Spatrick }
3835e5dd7070Spatrick
3836*7a9b00ceSrobert if (S.getLangOpts().HLSL) {
3837*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
3838*7a9b00ceSrobert return;
3839*7a9b00ceSrobert }
3840*7a9b00ceSrobert
3841e5dd7070Spatrick if (S.getCurFunctionOrMethodDecl()) {
3842e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
3843e5dd7070Spatrick AL.setInvalid();
3844e5dd7070Spatrick return;
3845e5dd7070Spatrick }
3846e5dd7070Spatrick QualType T = cast<VarDecl>(D)->getType();
3847e5dd7070Spatrick if (S.Context.getAsArrayType(T))
3848e5dd7070Spatrick T = S.Context.getBaseElementType(T);
3849e5dd7070Spatrick if (!T->getAs<RecordType>()) {
3850e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
3851e5dd7070Spatrick AL.setInvalid();
3852e5dd7070Spatrick return;
3853e5dd7070Spatrick }
3854e5dd7070Spatrick
3855e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
3856e5dd7070Spatrick uint32_t prioritynum;
3857e5dd7070Spatrick if (!checkUInt32Argument(S, AL, E, prioritynum)) {
3858e5dd7070Spatrick AL.setInvalid();
3859e5dd7070Spatrick return;
3860e5dd7070Spatrick }
3861e5dd7070Spatrick
3862ec727ea7Spatrick // Only perform the priority check if the attribute is outside of a system
3863ec727ea7Spatrick // header. Values <= 100 are reserved for the implementation, and libc++
3864ec727ea7Spatrick // benefits from being able to specify values in that range.
3865ec727ea7Spatrick if ((prioritynum < 101 || prioritynum > 65535) &&
3866ec727ea7Spatrick !S.getSourceManager().isInSystemHeader(AL.getLoc())) {
3867e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
3868e5dd7070Spatrick << E->getSourceRange() << AL << 101 << 65535;
3869e5dd7070Spatrick AL.setInvalid();
3870e5dd7070Spatrick return;
3871e5dd7070Spatrick }
3872e5dd7070Spatrick D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
3873e5dd7070Spatrick }
3874e5dd7070Spatrick
mergeErrorAttr(Decl * D,const AttributeCommonInfo & CI,StringRef NewUserDiagnostic)3875*7a9b00ceSrobert ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI,
3876*7a9b00ceSrobert StringRef NewUserDiagnostic) {
3877*7a9b00ceSrobert if (const auto *EA = D->getAttr<ErrorAttr>()) {
3878*7a9b00ceSrobert std::string NewAttr = CI.getNormalizedFullName();
3879*7a9b00ceSrobert assert((NewAttr == "error" || NewAttr == "warning") &&
3880*7a9b00ceSrobert "unexpected normalized full name");
3881*7a9b00ceSrobert bool Match = (EA->isError() && NewAttr == "error") ||
3882*7a9b00ceSrobert (EA->isWarning() && NewAttr == "warning");
3883*7a9b00ceSrobert if (!Match) {
3884*7a9b00ceSrobert Diag(EA->getLocation(), diag::err_attributes_are_not_compatible)
3885*7a9b00ceSrobert << CI << EA;
3886*7a9b00ceSrobert Diag(CI.getLoc(), diag::note_conflicting_attribute);
3887*7a9b00ceSrobert return nullptr;
3888*7a9b00ceSrobert }
3889*7a9b00ceSrobert if (EA->getUserDiagnostic() != NewUserDiagnostic) {
3890*7a9b00ceSrobert Diag(CI.getLoc(), diag::warn_duplicate_attribute) << EA;
3891*7a9b00ceSrobert Diag(EA->getLoc(), diag::note_previous_attribute);
3892*7a9b00ceSrobert }
3893*7a9b00ceSrobert D->dropAttr<ErrorAttr>();
3894*7a9b00ceSrobert }
3895*7a9b00ceSrobert return ::new (Context) ErrorAttr(Context, CI, NewUserDiagnostic);
3896*7a9b00ceSrobert }
3897*7a9b00ceSrobert
mergeFormatAttr(Decl * D,const AttributeCommonInfo & CI,IdentifierInfo * Format,int FormatIdx,int FirstArg)3898e5dd7070Spatrick FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
3899e5dd7070Spatrick IdentifierInfo *Format, int FormatIdx,
3900e5dd7070Spatrick int FirstArg) {
3901e5dd7070Spatrick // Check whether we already have an equivalent format attribute.
3902e5dd7070Spatrick for (auto *F : D->specific_attrs<FormatAttr>()) {
3903e5dd7070Spatrick if (F->getType() == Format &&
3904e5dd7070Spatrick F->getFormatIdx() == FormatIdx &&
3905e5dd7070Spatrick F->getFirstArg() == FirstArg) {
3906e5dd7070Spatrick // If we don't have a valid location for this attribute, adopt the
3907e5dd7070Spatrick // location.
3908e5dd7070Spatrick if (F->getLocation().isInvalid())
3909e5dd7070Spatrick F->setRange(CI.getRange());
3910e5dd7070Spatrick return nullptr;
3911e5dd7070Spatrick }
3912e5dd7070Spatrick }
3913e5dd7070Spatrick
3914e5dd7070Spatrick return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg);
3915e5dd7070Spatrick }
3916e5dd7070Spatrick
3917e5dd7070Spatrick /// Handle __attribute__((format(type,idx,firstarg))) attributes based on
3918e5dd7070Spatrick /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
handleFormatAttr(Sema & S,Decl * D,const ParsedAttr & AL)3919e5dd7070Spatrick static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3920e5dd7070Spatrick if (!AL.isArgIdent(0)) {
3921e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
3922e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
3923e5dd7070Spatrick return;
3924e5dd7070Spatrick }
3925e5dd7070Spatrick
3926e5dd7070Spatrick // In C++ the implicit 'this' function parameter also counts, and they are
3927e5dd7070Spatrick // counted from one.
3928e5dd7070Spatrick bool HasImplicitThisParam = isInstanceMethod(D);
3929e5dd7070Spatrick unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam;
3930e5dd7070Spatrick
3931e5dd7070Spatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
3932e5dd7070Spatrick StringRef Format = II->getName();
3933e5dd7070Spatrick
3934e5dd7070Spatrick if (normalizeName(Format)) {
3935e5dd7070Spatrick // If we've modified the string name, we need a new identifier for it.
3936e5dd7070Spatrick II = &S.Context.Idents.get(Format);
3937e5dd7070Spatrick }
3938e5dd7070Spatrick
3939e5dd7070Spatrick // Check for supported formats.
3940e5dd7070Spatrick FormatAttrKind Kind = getFormatAttrKind(Format);
3941e5dd7070Spatrick
3942e5dd7070Spatrick if (Kind == IgnoredFormat)
3943e5dd7070Spatrick return;
3944e5dd7070Spatrick
3945e5dd7070Spatrick if (Kind == InvalidFormat) {
3946e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
3947e5dd7070Spatrick << AL << II->getName();
3948e5dd7070Spatrick return;
3949e5dd7070Spatrick }
3950e5dd7070Spatrick
3951e5dd7070Spatrick // checks for the 2nd argument
3952e5dd7070Spatrick Expr *IdxExpr = AL.getArgAsExpr(1);
3953e5dd7070Spatrick uint32_t Idx;
3954e5dd7070Spatrick if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2))
3955e5dd7070Spatrick return;
3956e5dd7070Spatrick
3957e5dd7070Spatrick if (Idx < 1 || Idx > NumArgs) {
3958e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
3959e5dd7070Spatrick << AL << 2 << IdxExpr->getSourceRange();
3960e5dd7070Spatrick return;
3961e5dd7070Spatrick }
3962e5dd7070Spatrick
3963e5dd7070Spatrick // FIXME: Do we need to bounds check?
3964e5dd7070Spatrick unsigned ArgIdx = Idx - 1;
3965e5dd7070Spatrick
3966e5dd7070Spatrick if (HasImplicitThisParam) {
3967e5dd7070Spatrick if (ArgIdx == 0) {
3968e5dd7070Spatrick S.Diag(AL.getLoc(),
3969e5dd7070Spatrick diag::err_format_attribute_implicit_this_format_string)
3970e5dd7070Spatrick << IdxExpr->getSourceRange();
3971e5dd7070Spatrick return;
3972e5dd7070Spatrick }
3973e5dd7070Spatrick ArgIdx--;
3974e5dd7070Spatrick }
3975e5dd7070Spatrick
3976e5dd7070Spatrick // make sure the format string is really a string
3977e5dd7070Spatrick QualType Ty = getFunctionOrMethodParamType(D, ArgIdx);
3978e5dd7070Spatrick
3979*7a9b00ceSrobert if (!isNSStringType(Ty, S.Context, true) &&
3980*7a9b00ceSrobert !isCFStringType(Ty, S.Context) &&
3981*7a9b00ceSrobert (!Ty->isPointerType() ||
3982*7a9b00ceSrobert !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
3983e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_format_attribute_not)
3984*7a9b00ceSrobert << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx);
3985e5dd7070Spatrick return;
3986e5dd7070Spatrick }
3987e5dd7070Spatrick
3988e5dd7070Spatrick // check the 3rd argument
3989e5dd7070Spatrick Expr *FirstArgExpr = AL.getArgAsExpr(2);
3990e5dd7070Spatrick uint32_t FirstArg;
3991e5dd7070Spatrick if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3))
3992e5dd7070Spatrick return;
3993e5dd7070Spatrick
3994*7a9b00ceSrobert // FirstArg == 0 is is always valid.
3995e5dd7070Spatrick if (FirstArg != 0) {
3996e5dd7070Spatrick if (Kind == StrftimeFormat) {
3997*7a9b00ceSrobert // If the kind is strftime, FirstArg must be 0 because strftime does not
3998*7a9b00ceSrobert // use any variadic arguments.
3999e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter)
4000*7a9b00ceSrobert << FirstArgExpr->getSourceRange()
4001*7a9b00ceSrobert << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), "0");
4002*7a9b00ceSrobert return;
4003*7a9b00ceSrobert } else if (isFunctionOrMethodVariadic(D)) {
4004*7a9b00ceSrobert // Else, if the function is variadic, then FirstArg must be 0 or the
4005*7a9b00ceSrobert // "position" of the ... parameter. It's unusual to use 0 with variadic
4006*7a9b00ceSrobert // functions, so the fixit proposes the latter.
4007*7a9b00ceSrobert if (FirstArg != NumArgs + 1) {
4008*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
4009*7a9b00ceSrobert << AL << 3 << FirstArgExpr->getSourceRange()
4010*7a9b00ceSrobert << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(),
4011*7a9b00ceSrobert std::to_string(NumArgs + 1));
4012e5dd7070Spatrick return;
4013e5dd7070Spatrick }
4014*7a9b00ceSrobert } else {
4015*7a9b00ceSrobert // Inescapable GCC compatibility diagnostic.
4016*7a9b00ceSrobert S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
4017*7a9b00ceSrobert if (FirstArg <= Idx) {
4018*7a9b00ceSrobert // Else, the function is not variadic, and FirstArg must be 0 or any
4019*7a9b00ceSrobert // parameter after the format parameter. We don't offer a fixit because
4020*7a9b00ceSrobert // there are too many possible good values.
4021e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
4022e5dd7070Spatrick << AL << 3 << FirstArgExpr->getSourceRange();
4023e5dd7070Spatrick return;
4024e5dd7070Spatrick }
4025*7a9b00ceSrobert }
4026*7a9b00ceSrobert }
4027e5dd7070Spatrick
4028e5dd7070Spatrick FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
4029e5dd7070Spatrick if (NewAttr)
4030e5dd7070Spatrick D->addAttr(NewAttr);
4031e5dd7070Spatrick }
4032e5dd7070Spatrick
4033e5dd7070Spatrick /// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes.
handleCallbackAttr(Sema & S,Decl * D,const ParsedAttr & AL)4034e5dd7070Spatrick static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4035e5dd7070Spatrick // The index that identifies the callback callee is mandatory.
4036e5dd7070Spatrick if (AL.getNumArgs() == 0) {
4037e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)
4038e5dd7070Spatrick << AL.getRange();
4039e5dd7070Spatrick return;
4040e5dd7070Spatrick }
4041e5dd7070Spatrick
4042e5dd7070Spatrick bool HasImplicitThisParam = isInstanceMethod(D);
4043e5dd7070Spatrick int32_t NumArgs = getFunctionOrMethodNumParams(D);
4044e5dd7070Spatrick
4045e5dd7070Spatrick FunctionDecl *FD = D->getAsFunction();
4046e5dd7070Spatrick assert(FD && "Expected a function declaration!");
4047e5dd7070Spatrick
4048e5dd7070Spatrick llvm::StringMap<int> NameIdxMapping;
4049e5dd7070Spatrick NameIdxMapping["__"] = -1;
4050e5dd7070Spatrick
4051e5dd7070Spatrick NameIdxMapping["this"] = 0;
4052e5dd7070Spatrick
4053e5dd7070Spatrick int Idx = 1;
4054e5dd7070Spatrick for (const ParmVarDecl *PVD : FD->parameters())
4055e5dd7070Spatrick NameIdxMapping[PVD->getName()] = Idx++;
4056e5dd7070Spatrick
4057e5dd7070Spatrick auto UnknownName = NameIdxMapping.end();
4058e5dd7070Spatrick
4059e5dd7070Spatrick SmallVector<int, 8> EncodingIndices;
4060e5dd7070Spatrick for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) {
4061e5dd7070Spatrick SourceRange SR;
4062e5dd7070Spatrick int32_t ArgIdx;
4063e5dd7070Spatrick
4064e5dd7070Spatrick if (AL.isArgIdent(I)) {
4065e5dd7070Spatrick IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
4066e5dd7070Spatrick auto It = NameIdxMapping.find(IdLoc->Ident->getName());
4067e5dd7070Spatrick if (It == UnknownName) {
4068e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
4069e5dd7070Spatrick << IdLoc->Ident << IdLoc->Loc;
4070e5dd7070Spatrick return;
4071e5dd7070Spatrick }
4072e5dd7070Spatrick
4073e5dd7070Spatrick SR = SourceRange(IdLoc->Loc);
4074e5dd7070Spatrick ArgIdx = It->second;
4075e5dd7070Spatrick } else if (AL.isArgExpr(I)) {
4076e5dd7070Spatrick Expr *IdxExpr = AL.getArgAsExpr(I);
4077e5dd7070Spatrick
4078e5dd7070Spatrick // If the expression is not parseable as an int32_t we have a problem.
4079e5dd7070Spatrick if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
4080e5dd7070Spatrick false)) {
4081e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
4082e5dd7070Spatrick << AL << (I + 1) << IdxExpr->getSourceRange();
4083e5dd7070Spatrick return;
4084e5dd7070Spatrick }
4085e5dd7070Spatrick
4086e5dd7070Spatrick // Check oob, excluding the special values, 0 and -1.
4087e5dd7070Spatrick if (ArgIdx < -1 || ArgIdx > NumArgs) {
4088e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
4089e5dd7070Spatrick << AL << (I + 1) << IdxExpr->getSourceRange();
4090e5dd7070Spatrick return;
4091e5dd7070Spatrick }
4092e5dd7070Spatrick
4093e5dd7070Spatrick SR = IdxExpr->getSourceRange();
4094e5dd7070Spatrick } else {
4095e5dd7070Spatrick llvm_unreachable("Unexpected ParsedAttr argument type!");
4096e5dd7070Spatrick }
4097e5dd7070Spatrick
4098e5dd7070Spatrick if (ArgIdx == 0 && !HasImplicitThisParam) {
4099e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)
4100e5dd7070Spatrick << (I + 1) << SR;
4101e5dd7070Spatrick return;
4102e5dd7070Spatrick }
4103e5dd7070Spatrick
4104e5dd7070Spatrick // Adjust for the case we do not have an implicit "this" parameter. In this
4105e5dd7070Spatrick // case we decrease all positive values by 1 to get LLVM argument indices.
4106e5dd7070Spatrick if (!HasImplicitThisParam && ArgIdx > 0)
4107e5dd7070Spatrick ArgIdx -= 1;
4108e5dd7070Spatrick
4109e5dd7070Spatrick EncodingIndices.push_back(ArgIdx);
4110e5dd7070Spatrick }
4111e5dd7070Spatrick
4112e5dd7070Spatrick int CalleeIdx = EncodingIndices.front();
4113e5dd7070Spatrick // Check if the callee index is proper, thus not "this" and not "unknown".
4114e5dd7070Spatrick // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam"
4115e5dd7070Spatrick // is false and positive if "HasImplicitThisParam" is true.
4116e5dd7070Spatrick if (CalleeIdx < (int)HasImplicitThisParam) {
4117e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)
4118e5dd7070Spatrick << AL.getRange();
4119e5dd7070Spatrick return;
4120e5dd7070Spatrick }
4121e5dd7070Spatrick
4122e5dd7070Spatrick // Get the callee type, note the index adjustment as the AST doesn't contain
4123e5dd7070Spatrick // the this type (which the callee cannot reference anyway!).
4124e5dd7070Spatrick const Type *CalleeType =
4125e5dd7070Spatrick getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)
4126e5dd7070Spatrick .getTypePtr();
4127e5dd7070Spatrick if (!CalleeType || !CalleeType->isFunctionPointerType()) {
4128e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
4129e5dd7070Spatrick << AL.getRange();
4130e5dd7070Spatrick return;
4131e5dd7070Spatrick }
4132e5dd7070Spatrick
4133e5dd7070Spatrick const Type *CalleeFnType =
4134e5dd7070Spatrick CalleeType->getPointeeType()->getUnqualifiedDesugaredType();
4135e5dd7070Spatrick
4136e5dd7070Spatrick // TODO: Check the type of the callee arguments.
4137e5dd7070Spatrick
4138e5dd7070Spatrick const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType);
4139e5dd7070Spatrick if (!CalleeFnProtoType) {
4140e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
4141e5dd7070Spatrick << AL.getRange();
4142e5dd7070Spatrick return;
4143e5dd7070Spatrick }
4144e5dd7070Spatrick
4145e5dd7070Spatrick if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {
4146e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
4147e5dd7070Spatrick << AL << (unsigned)(EncodingIndices.size() - 1);
4148e5dd7070Spatrick return;
4149e5dd7070Spatrick }
4150e5dd7070Spatrick
4151e5dd7070Spatrick if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
4152e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
4153e5dd7070Spatrick << AL << (unsigned)(EncodingIndices.size() - 1);
4154e5dd7070Spatrick return;
4155e5dd7070Spatrick }
4156e5dd7070Spatrick
4157e5dd7070Spatrick if (CalleeFnProtoType->isVariadic()) {
4158e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange();
4159e5dd7070Spatrick return;
4160e5dd7070Spatrick }
4161e5dd7070Spatrick
4162e5dd7070Spatrick // Do not allow multiple callback attributes.
4163e5dd7070Spatrick if (D->hasAttr<CallbackAttr>()) {
4164e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange();
4165e5dd7070Spatrick return;
4166e5dd7070Spatrick }
4167e5dd7070Spatrick
4168e5dd7070Spatrick D->addAttr(::new (S.Context) CallbackAttr(
4169e5dd7070Spatrick S.Context, AL, EncodingIndices.data(), EncodingIndices.size()));
4170e5dd7070Spatrick }
4171e5dd7070Spatrick
isFunctionLike(const Type & T)4172a0747c9fSpatrick static bool isFunctionLike(const Type &T) {
4173a0747c9fSpatrick // Check for explicit function types.
4174a0747c9fSpatrick // 'called_once' is only supported in Objective-C and it has
4175a0747c9fSpatrick // function pointers and block pointers.
4176a0747c9fSpatrick return T.isFunctionPointerType() || T.isBlockPointerType();
4177a0747c9fSpatrick }
4178a0747c9fSpatrick
4179a0747c9fSpatrick /// Handle 'called_once' attribute.
handleCalledOnceAttr(Sema & S,Decl * D,const ParsedAttr & AL)4180a0747c9fSpatrick static void handleCalledOnceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4181a0747c9fSpatrick // 'called_once' only applies to parameters representing functions.
4182a0747c9fSpatrick QualType T = cast<ParmVarDecl>(D)->getType();
4183a0747c9fSpatrick
4184a0747c9fSpatrick if (!isFunctionLike(*T)) {
4185a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_called_once_attribute_wrong_type);
4186a0747c9fSpatrick return;
4187a0747c9fSpatrick }
4188a0747c9fSpatrick
4189a0747c9fSpatrick D->addAttr(::new (S.Context) CalledOnceAttr(S.Context, AL));
4190a0747c9fSpatrick }
4191a0747c9fSpatrick
handleTransparentUnionAttr(Sema & S,Decl * D,const ParsedAttr & AL)4192e5dd7070Spatrick static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4193e5dd7070Spatrick // Try to find the underlying union declaration.
4194e5dd7070Spatrick RecordDecl *RD = nullptr;
4195e5dd7070Spatrick const auto *TD = dyn_cast<TypedefNameDecl>(D);
4196e5dd7070Spatrick if (TD && TD->getUnderlyingType()->isUnionType())
4197e5dd7070Spatrick RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
4198e5dd7070Spatrick else
4199e5dd7070Spatrick RD = dyn_cast<RecordDecl>(D);
4200e5dd7070Spatrick
4201e5dd7070Spatrick if (!RD || !RD->isUnion()) {
4202e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL
4203e5dd7070Spatrick << ExpectedUnion;
4204e5dd7070Spatrick return;
4205e5dd7070Spatrick }
4206e5dd7070Spatrick
4207e5dd7070Spatrick if (!RD->isCompleteDefinition()) {
4208e5dd7070Spatrick if (!RD->isBeingDefined())
4209e5dd7070Spatrick S.Diag(AL.getLoc(),
4210e5dd7070Spatrick diag::warn_transparent_union_attribute_not_definition);
4211e5dd7070Spatrick return;
4212e5dd7070Spatrick }
4213e5dd7070Spatrick
4214e5dd7070Spatrick RecordDecl::field_iterator Field = RD->field_begin(),
4215e5dd7070Spatrick FieldEnd = RD->field_end();
4216e5dd7070Spatrick if (Field == FieldEnd) {
4217e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
4218e5dd7070Spatrick return;
4219e5dd7070Spatrick }
4220e5dd7070Spatrick
4221e5dd7070Spatrick FieldDecl *FirstField = *Field;
4222e5dd7070Spatrick QualType FirstType = FirstField->getType();
4223e5dd7070Spatrick if (FirstType->hasFloatingRepresentation() || FirstType->isVectorType()) {
4224e5dd7070Spatrick S.Diag(FirstField->getLocation(),
4225e5dd7070Spatrick diag::warn_transparent_union_attribute_floating)
4226e5dd7070Spatrick << FirstType->isVectorType() << FirstType;
4227e5dd7070Spatrick return;
4228e5dd7070Spatrick }
4229e5dd7070Spatrick
4230e5dd7070Spatrick if (FirstType->isIncompleteType())
4231e5dd7070Spatrick return;
4232e5dd7070Spatrick uint64_t FirstSize = S.Context.getTypeSize(FirstType);
4233e5dd7070Spatrick uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
4234e5dd7070Spatrick for (; Field != FieldEnd; ++Field) {
4235e5dd7070Spatrick QualType FieldType = Field->getType();
4236e5dd7070Spatrick if (FieldType->isIncompleteType())
4237e5dd7070Spatrick return;
4238e5dd7070Spatrick // FIXME: this isn't fully correct; we also need to test whether the
4239e5dd7070Spatrick // members of the union would all have the same calling convention as the
4240e5dd7070Spatrick // first member of the union. Checking just the size and alignment isn't
4241e5dd7070Spatrick // sufficient (consider structs passed on the stack instead of in registers
4242e5dd7070Spatrick // as an example).
4243e5dd7070Spatrick if (S.Context.getTypeSize(FieldType) != FirstSize ||
4244e5dd7070Spatrick S.Context.getTypeAlign(FieldType) > FirstAlign) {
4245e5dd7070Spatrick // Warn if we drop the attribute.
4246e5dd7070Spatrick bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
4247e5dd7070Spatrick unsigned FieldBits = isSize ? S.Context.getTypeSize(FieldType)
4248e5dd7070Spatrick : S.Context.getTypeAlign(FieldType);
4249e5dd7070Spatrick S.Diag(Field->getLocation(),
4250e5dd7070Spatrick diag::warn_transparent_union_attribute_field_size_align)
4251a0747c9fSpatrick << isSize << *Field << FieldBits;
4252e5dd7070Spatrick unsigned FirstBits = isSize ? FirstSize : FirstAlign;
4253e5dd7070Spatrick S.Diag(FirstField->getLocation(),
4254e5dd7070Spatrick diag::note_transparent_union_first_field_size_align)
4255e5dd7070Spatrick << isSize << FirstBits;
4256e5dd7070Spatrick return;
4257e5dd7070Spatrick }
4258e5dd7070Spatrick }
4259e5dd7070Spatrick
4260e5dd7070Spatrick RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
4261e5dd7070Spatrick }
4262e5dd7070Spatrick
AddAnnotationAttr(Decl * D,const AttributeCommonInfo & CI,StringRef Str,MutableArrayRef<Expr * > Args)4263a0747c9fSpatrick void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
4264a0747c9fSpatrick StringRef Str, MutableArrayRef<Expr *> Args) {
4265a0747c9fSpatrick auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
4266*7a9b00ceSrobert if (ConstantFoldAttrArgs(
4267*7a9b00ceSrobert CI, MutableArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()))) {
4268a0747c9fSpatrick D->addAttr(Attr);
4269a0747c9fSpatrick }
4270*7a9b00ceSrobert }
4271a0747c9fSpatrick
handleAnnotateAttr(Sema & S,Decl * D,const ParsedAttr & AL)4272e5dd7070Spatrick static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4273a0747c9fSpatrick // Make sure that there is a string literal as the annotation's first
4274e5dd7070Spatrick // argument.
4275e5dd7070Spatrick StringRef Str;
4276e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
4277e5dd7070Spatrick return;
4278e5dd7070Spatrick
4279a0747c9fSpatrick llvm::SmallVector<Expr *, 4> Args;
4280a0747c9fSpatrick Args.reserve(AL.getNumArgs() - 1);
4281a0747c9fSpatrick for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
4282a0747c9fSpatrick assert(!AL.isArgIdent(Idx));
4283a0747c9fSpatrick Args.push_back(AL.getArgAsExpr(Idx));
4284e5dd7070Spatrick }
4285e5dd7070Spatrick
4286a0747c9fSpatrick S.AddAnnotationAttr(D, AL, Str, Args);
4287e5dd7070Spatrick }
4288e5dd7070Spatrick
handleAlignValueAttr(Sema & S,Decl * D,const ParsedAttr & AL)4289e5dd7070Spatrick static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4290e5dd7070Spatrick S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0));
4291e5dd7070Spatrick }
4292e5dd7070Spatrick
AddAlignValueAttr(Decl * D,const AttributeCommonInfo & CI,Expr * E)4293e5dd7070Spatrick void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) {
4294e5dd7070Spatrick AlignValueAttr TmpAttr(Context, CI, E);
4295e5dd7070Spatrick SourceLocation AttrLoc = CI.getLoc();
4296e5dd7070Spatrick
4297e5dd7070Spatrick QualType T;
4298e5dd7070Spatrick if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
4299e5dd7070Spatrick T = TD->getUnderlyingType();
4300e5dd7070Spatrick else if (const auto *VD = dyn_cast<ValueDecl>(D))
4301e5dd7070Spatrick T = VD->getType();
4302e5dd7070Spatrick else
4303e5dd7070Spatrick llvm_unreachable("Unknown decl type for align_value");
4304e5dd7070Spatrick
4305e5dd7070Spatrick if (!T->isDependentType() && !T->isAnyPointerType() &&
4306e5dd7070Spatrick !T->isReferenceType() && !T->isMemberPointerType()) {
4307e5dd7070Spatrick Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only)
4308ec727ea7Spatrick << &TmpAttr << T << D->getSourceRange();
4309e5dd7070Spatrick return;
4310e5dd7070Spatrick }
4311e5dd7070Spatrick
4312e5dd7070Spatrick if (!E->isValueDependent()) {
4313e5dd7070Spatrick llvm::APSInt Alignment;
4314a0747c9fSpatrick ExprResult ICE = VerifyIntegerConstantExpression(
4315a0747c9fSpatrick E, &Alignment, diag::err_align_value_attribute_argument_not_int);
4316e5dd7070Spatrick if (ICE.isInvalid())
4317e5dd7070Spatrick return;
4318e5dd7070Spatrick
4319e5dd7070Spatrick if (!Alignment.isPowerOf2()) {
4320e5dd7070Spatrick Diag(AttrLoc, diag::err_alignment_not_power_of_two)
4321e5dd7070Spatrick << E->getSourceRange();
4322e5dd7070Spatrick return;
4323e5dd7070Spatrick }
4324e5dd7070Spatrick
4325e5dd7070Spatrick D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get()));
4326e5dd7070Spatrick return;
4327e5dd7070Spatrick }
4328e5dd7070Spatrick
4329e5dd7070Spatrick // Save dependent expressions in the AST to be instantiated.
4330e5dd7070Spatrick D->addAttr(::new (Context) AlignValueAttr(Context, CI, E));
4331e5dd7070Spatrick }
4332e5dd7070Spatrick
handleAlignedAttr(Sema & S,Decl * D,const ParsedAttr & AL)4333e5dd7070Spatrick static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4334e5dd7070Spatrick // check the attribute arguments.
4335e5dd7070Spatrick if (AL.getNumArgs() > 1) {
4336e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
4337e5dd7070Spatrick return;
4338e5dd7070Spatrick }
4339e5dd7070Spatrick
4340e5dd7070Spatrick if (AL.getNumArgs() == 0) {
4341e5dd7070Spatrick D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr));
4342e5dd7070Spatrick return;
4343e5dd7070Spatrick }
4344e5dd7070Spatrick
4345e5dd7070Spatrick Expr *E = AL.getArgAsExpr(0);
4346e5dd7070Spatrick if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
4347e5dd7070Spatrick S.Diag(AL.getEllipsisLoc(),
4348e5dd7070Spatrick diag::err_pack_expansion_without_parameter_packs);
4349e5dd7070Spatrick return;
4350e5dd7070Spatrick }
4351e5dd7070Spatrick
4352e5dd7070Spatrick if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
4353e5dd7070Spatrick return;
4354e5dd7070Spatrick
4355e5dd7070Spatrick S.AddAlignedAttr(D, AL, E, AL.isPackExpansion());
4356e5dd7070Spatrick }
4357e5dd7070Spatrick
AddAlignedAttr(Decl * D,const AttributeCommonInfo & CI,Expr * E,bool IsPackExpansion)4358e5dd7070Spatrick void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
4359e5dd7070Spatrick bool IsPackExpansion) {
4360e5dd7070Spatrick AlignedAttr TmpAttr(Context, CI, true, E);
4361e5dd7070Spatrick SourceLocation AttrLoc = CI.getLoc();
4362e5dd7070Spatrick
4363e5dd7070Spatrick // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
4364e5dd7070Spatrick if (TmpAttr.isAlignas()) {
4365e5dd7070Spatrick // C++11 [dcl.align]p1:
4366e5dd7070Spatrick // An alignment-specifier may be applied to a variable or to a class
4367e5dd7070Spatrick // data member, but it shall not be applied to a bit-field, a function
4368e5dd7070Spatrick // parameter, the formal parameter of a catch clause, or a variable
4369e5dd7070Spatrick // declared with the register storage class specifier. An
4370e5dd7070Spatrick // alignment-specifier may also be applied to the declaration of a class
4371e5dd7070Spatrick // or enumeration type.
4372*7a9b00ceSrobert // CWG 2354:
4373*7a9b00ceSrobert // CWG agreed to remove permission for alignas to be applied to
4374*7a9b00ceSrobert // enumerations.
4375e5dd7070Spatrick // C11 6.7.5/2:
4376e5dd7070Spatrick // An alignment attribute shall not be specified in a declaration of
4377e5dd7070Spatrick // a typedef, or a bit-field, or a function, or a parameter, or an
4378e5dd7070Spatrick // object declared with the register storage-class specifier.
4379e5dd7070Spatrick int DiagKind = -1;
4380e5dd7070Spatrick if (isa<ParmVarDecl>(D)) {
4381e5dd7070Spatrick DiagKind = 0;
4382e5dd7070Spatrick } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
4383e5dd7070Spatrick if (VD->getStorageClass() == SC_Register)
4384e5dd7070Spatrick DiagKind = 1;
4385e5dd7070Spatrick if (VD->isExceptionVariable())
4386e5dd7070Spatrick DiagKind = 2;
4387e5dd7070Spatrick } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
4388e5dd7070Spatrick if (FD->isBitField())
4389e5dd7070Spatrick DiagKind = 3;
4390*7a9b00ceSrobert } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
4391*7a9b00ceSrobert if (ED->getLangOpts().CPlusPlus)
4392*7a9b00ceSrobert DiagKind = 4;
4393e5dd7070Spatrick } else if (!isa<TagDecl>(D)) {
4394e5dd7070Spatrick Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr
4395e5dd7070Spatrick << (TmpAttr.isC11() ? ExpectedVariableOrField
4396e5dd7070Spatrick : ExpectedVariableFieldOrTag);
4397e5dd7070Spatrick return;
4398e5dd7070Spatrick }
4399e5dd7070Spatrick if (DiagKind != -1) {
4400e5dd7070Spatrick Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
4401e5dd7070Spatrick << &TmpAttr << DiagKind;
4402e5dd7070Spatrick return;
4403e5dd7070Spatrick }
4404e5dd7070Spatrick }
4405e5dd7070Spatrick
4406e5dd7070Spatrick if (E->isValueDependent()) {
4407e5dd7070Spatrick // We can't support a dependent alignment on a non-dependent type,
4408e5dd7070Spatrick // because we have no way to model that a type is "alignment-dependent"
4409e5dd7070Spatrick // but not dependent in any other way.
4410e5dd7070Spatrick if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) {
4411e5dd7070Spatrick if (!TND->getUnderlyingType()->isDependentType()) {
4412e5dd7070Spatrick Diag(AttrLoc, diag::err_alignment_dependent_typedef_name)
4413e5dd7070Spatrick << E->getSourceRange();
4414e5dd7070Spatrick return;
4415e5dd7070Spatrick }
4416e5dd7070Spatrick }
4417e5dd7070Spatrick
4418e5dd7070Spatrick // Save dependent expressions in the AST to be instantiated.
4419e5dd7070Spatrick AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E);
4420e5dd7070Spatrick AA->setPackExpansion(IsPackExpansion);
4421e5dd7070Spatrick D->addAttr(AA);
4422e5dd7070Spatrick return;
4423e5dd7070Spatrick }
4424e5dd7070Spatrick
4425e5dd7070Spatrick // FIXME: Cache the number on the AL object?
4426e5dd7070Spatrick llvm::APSInt Alignment;
4427a0747c9fSpatrick ExprResult ICE = VerifyIntegerConstantExpression(
4428a0747c9fSpatrick E, &Alignment, diag::err_aligned_attribute_argument_not_int);
4429e5dd7070Spatrick if (ICE.isInvalid())
4430e5dd7070Spatrick return;
4431e5dd7070Spatrick
4432e5dd7070Spatrick uint64_t AlignVal = Alignment.getZExtValue();
4433e5dd7070Spatrick // C++11 [dcl.align]p2:
4434e5dd7070Spatrick // -- if the constant expression evaluates to zero, the alignment
4435e5dd7070Spatrick // specifier shall have no effect
4436e5dd7070Spatrick // C11 6.7.5p6:
4437e5dd7070Spatrick // An alignment specification of zero has no effect.
4438e5dd7070Spatrick if (!(TmpAttr.isAlignas() && !Alignment)) {
4439e5dd7070Spatrick if (!llvm::isPowerOf2_64(AlignVal)) {
4440e5dd7070Spatrick Diag(AttrLoc, diag::err_alignment_not_power_of_two)
4441e5dd7070Spatrick << E->getSourceRange();
4442e5dd7070Spatrick return;
4443e5dd7070Spatrick }
4444e5dd7070Spatrick }
4445e5dd7070Spatrick
4446*7a9b00ceSrobert uint64_t MaximumAlignment = Sema::MaximumAlignment;
4447ec727ea7Spatrick if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF())
4448*7a9b00ceSrobert MaximumAlignment = std::min(MaximumAlignment, uint64_t(8192));
4449ec727ea7Spatrick if (AlignVal > MaximumAlignment) {
4450ec727ea7Spatrick Diag(AttrLoc, diag::err_attribute_aligned_too_great)
4451ec727ea7Spatrick << MaximumAlignment << E->getSourceRange();
4452e5dd7070Spatrick return;
4453e5dd7070Spatrick }
4454e5dd7070Spatrick
4455*7a9b00ceSrobert const auto *VD = dyn_cast<VarDecl>(D);
4456*7a9b00ceSrobert if (VD) {
4457e5dd7070Spatrick unsigned MaxTLSAlign =
4458e5dd7070Spatrick Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign())
4459e5dd7070Spatrick .getQuantity();
4460*7a9b00ceSrobert if (MaxTLSAlign && AlignVal > MaxTLSAlign &&
4461e5dd7070Spatrick VD->getTLSKind() != VarDecl::TLS_None) {
4462e5dd7070Spatrick Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
4463e5dd7070Spatrick << (unsigned)AlignVal << VD << MaxTLSAlign;
4464e5dd7070Spatrick return;
4465e5dd7070Spatrick }
4466e5dd7070Spatrick }
4467e5dd7070Spatrick
4468*7a9b00ceSrobert // On AIX, an aligned attribute can not decrease the alignment when applied
4469*7a9b00ceSrobert // to a variable declaration with vector type.
4470*7a9b00ceSrobert if (VD && Context.getTargetInfo().getTriple().isOSAIX()) {
4471*7a9b00ceSrobert const Type *Ty = VD->getType().getTypePtr();
4472*7a9b00ceSrobert if (Ty->isVectorType() && AlignVal < 16) {
4473*7a9b00ceSrobert Diag(VD->getLocation(), diag::warn_aligned_attr_underaligned)
4474*7a9b00ceSrobert << VD->getType() << 16;
4475*7a9b00ceSrobert return;
4476*7a9b00ceSrobert }
4477*7a9b00ceSrobert }
4478*7a9b00ceSrobert
4479e5dd7070Spatrick AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get());
4480e5dd7070Spatrick AA->setPackExpansion(IsPackExpansion);
4481e5dd7070Spatrick D->addAttr(AA);
4482e5dd7070Spatrick }
4483e5dd7070Spatrick
AddAlignedAttr(Decl * D,const AttributeCommonInfo & CI,TypeSourceInfo * TS,bool IsPackExpansion)4484e5dd7070Spatrick void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI,
4485e5dd7070Spatrick TypeSourceInfo *TS, bool IsPackExpansion) {
4486e5dd7070Spatrick // FIXME: Cache the number on the AL object if non-dependent?
4487e5dd7070Spatrick // FIXME: Perform checking of type validity
4488e5dd7070Spatrick AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS);
4489e5dd7070Spatrick AA->setPackExpansion(IsPackExpansion);
4490e5dd7070Spatrick D->addAttr(AA);
4491e5dd7070Spatrick }
4492e5dd7070Spatrick
CheckAlignasUnderalignment(Decl * D)4493e5dd7070Spatrick void Sema::CheckAlignasUnderalignment(Decl *D) {
4494e5dd7070Spatrick assert(D->hasAttrs() && "no attributes on decl");
4495e5dd7070Spatrick
4496e5dd7070Spatrick QualType UnderlyingTy, DiagTy;
4497e5dd7070Spatrick if (const auto *VD = dyn_cast<ValueDecl>(D)) {
4498e5dd7070Spatrick UnderlyingTy = DiagTy = VD->getType();
4499e5dd7070Spatrick } else {
4500e5dd7070Spatrick UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D));
4501e5dd7070Spatrick if (const auto *ED = dyn_cast<EnumDecl>(D))
4502e5dd7070Spatrick UnderlyingTy = ED->getIntegerType();
4503e5dd7070Spatrick }
4504e5dd7070Spatrick if (DiagTy->isDependentType() || DiagTy->isIncompleteType())
4505e5dd7070Spatrick return;
4506e5dd7070Spatrick
4507e5dd7070Spatrick // C++11 [dcl.align]p5, C11 6.7.5/4:
4508e5dd7070Spatrick // The combined effect of all alignment attributes in a declaration shall
4509e5dd7070Spatrick // not specify an alignment that is less strict than the alignment that
4510e5dd7070Spatrick // would otherwise be required for the entity being declared.
4511e5dd7070Spatrick AlignedAttr *AlignasAttr = nullptr;
4512ec727ea7Spatrick AlignedAttr *LastAlignedAttr = nullptr;
4513e5dd7070Spatrick unsigned Align = 0;
4514e5dd7070Spatrick for (auto *I : D->specific_attrs<AlignedAttr>()) {
4515e5dd7070Spatrick if (I->isAlignmentDependent())
4516e5dd7070Spatrick return;
4517e5dd7070Spatrick if (I->isAlignas())
4518e5dd7070Spatrick AlignasAttr = I;
4519e5dd7070Spatrick Align = std::max(Align, I->getAlignment(Context));
4520ec727ea7Spatrick LastAlignedAttr = I;
4521e5dd7070Spatrick }
4522e5dd7070Spatrick
4523ec727ea7Spatrick if (Align && DiagTy->isSizelessType()) {
4524ec727ea7Spatrick Diag(LastAlignedAttr->getLocation(), diag::err_attribute_sizeless_type)
4525ec727ea7Spatrick << LastAlignedAttr << DiagTy;
4526ec727ea7Spatrick } else if (AlignasAttr && Align) {
4527e5dd7070Spatrick CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
4528e5dd7070Spatrick CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy);
4529e5dd7070Spatrick if (NaturalAlign > RequestedAlign)
4530e5dd7070Spatrick Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned)
4531e5dd7070Spatrick << DiagTy << (unsigned)NaturalAlign.getQuantity();
4532e5dd7070Spatrick }
4533e5dd7070Spatrick }
4534e5dd7070Spatrick
checkMSInheritanceAttrOnDefinition(CXXRecordDecl * RD,SourceRange Range,bool BestCase,MSInheritanceModel ExplicitModel)4535e5dd7070Spatrick bool Sema::checkMSInheritanceAttrOnDefinition(
4536e5dd7070Spatrick CXXRecordDecl *RD, SourceRange Range, bool BestCase,
4537e5dd7070Spatrick MSInheritanceModel ExplicitModel) {
4538e5dd7070Spatrick assert(RD->hasDefinition() && "RD has no definition!");
4539e5dd7070Spatrick
4540e5dd7070Spatrick // We may not have seen base specifiers or any virtual methods yet. We will
4541e5dd7070Spatrick // have to wait until the record is defined to catch any mismatches.
4542e5dd7070Spatrick if (!RD->getDefinition()->isCompleteDefinition())
4543e5dd7070Spatrick return false;
4544e5dd7070Spatrick
4545e5dd7070Spatrick // The unspecified model never matches what a definition could need.
4546e5dd7070Spatrick if (ExplicitModel == MSInheritanceModel::Unspecified)
4547e5dd7070Spatrick return false;
4548e5dd7070Spatrick
4549e5dd7070Spatrick if (BestCase) {
4550e5dd7070Spatrick if (RD->calculateInheritanceModel() == ExplicitModel)
4551e5dd7070Spatrick return false;
4552e5dd7070Spatrick } else {
4553e5dd7070Spatrick if (RD->calculateInheritanceModel() <= ExplicitModel)
4554e5dd7070Spatrick return false;
4555e5dd7070Spatrick }
4556e5dd7070Spatrick
4557e5dd7070Spatrick Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
4558e5dd7070Spatrick << 0 /*definition*/;
4559ec727ea7Spatrick Diag(RD->getDefinition()->getLocation(), diag::note_defined_here) << RD;
4560e5dd7070Spatrick return true;
4561e5dd7070Spatrick }
4562e5dd7070Spatrick
4563e5dd7070Spatrick /// parseModeAttrArg - Parses attribute mode string and returns parsed type
4564e5dd7070Spatrick /// attribute.
parseModeAttrArg(Sema & S,StringRef Str,unsigned & DestWidth,bool & IntegerMode,bool & ComplexMode,FloatModeKind & ExplicitType)4565e5dd7070Spatrick static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
4566ec727ea7Spatrick bool &IntegerMode, bool &ComplexMode,
4567*7a9b00ceSrobert FloatModeKind &ExplicitType) {
4568e5dd7070Spatrick IntegerMode = true;
4569e5dd7070Spatrick ComplexMode = false;
4570*7a9b00ceSrobert ExplicitType = FloatModeKind::NoFloat;
4571e5dd7070Spatrick switch (Str.size()) {
4572e5dd7070Spatrick case 2:
4573e5dd7070Spatrick switch (Str[0]) {
4574e5dd7070Spatrick case 'Q':
4575e5dd7070Spatrick DestWidth = 8;
4576e5dd7070Spatrick break;
4577e5dd7070Spatrick case 'H':
4578e5dd7070Spatrick DestWidth = 16;
4579e5dd7070Spatrick break;
4580e5dd7070Spatrick case 'S':
4581e5dd7070Spatrick DestWidth = 32;
4582e5dd7070Spatrick break;
4583e5dd7070Spatrick case 'D':
4584e5dd7070Spatrick DestWidth = 64;
4585e5dd7070Spatrick break;
4586e5dd7070Spatrick case 'X':
4587e5dd7070Spatrick DestWidth = 96;
4588e5dd7070Spatrick break;
4589ec727ea7Spatrick case 'K': // KFmode - IEEE quad precision (__float128)
4590*7a9b00ceSrobert ExplicitType = FloatModeKind::Float128;
4591ec727ea7Spatrick DestWidth = Str[1] == 'I' ? 0 : 128;
4592ec727ea7Spatrick break;
4593e5dd7070Spatrick case 'T':
4594*7a9b00ceSrobert ExplicitType = FloatModeKind::LongDouble;
4595e5dd7070Spatrick DestWidth = 128;
4596e5dd7070Spatrick break;
4597*7a9b00ceSrobert case 'I':
4598*7a9b00ceSrobert ExplicitType = FloatModeKind::Ibm128;
4599*7a9b00ceSrobert DestWidth = Str[1] == 'I' ? 0 : 128;
4600*7a9b00ceSrobert break;
4601e5dd7070Spatrick }
4602e5dd7070Spatrick if (Str[1] == 'F') {
4603e5dd7070Spatrick IntegerMode = false;
4604e5dd7070Spatrick } else if (Str[1] == 'C') {
4605e5dd7070Spatrick IntegerMode = false;
4606e5dd7070Spatrick ComplexMode = true;
4607e5dd7070Spatrick } else if (Str[1] != 'I') {
4608e5dd7070Spatrick DestWidth = 0;
4609e5dd7070Spatrick }
4610e5dd7070Spatrick break;
4611e5dd7070Spatrick case 4:
4612e5dd7070Spatrick // FIXME: glibc uses 'word' to define register_t; this is narrower than a
4613e5dd7070Spatrick // pointer on PIC16 and other embedded platforms.
4614e5dd7070Spatrick if (Str == "word")
4615e5dd7070Spatrick DestWidth = S.Context.getTargetInfo().getRegisterWidth();
4616e5dd7070Spatrick else if (Str == "byte")
4617e5dd7070Spatrick DestWidth = S.Context.getTargetInfo().getCharWidth();
4618e5dd7070Spatrick break;
4619e5dd7070Spatrick case 7:
4620e5dd7070Spatrick if (Str == "pointer")
4621*7a9b00ceSrobert DestWidth = S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
4622e5dd7070Spatrick break;
4623e5dd7070Spatrick case 11:
4624e5dd7070Spatrick if (Str == "unwind_word")
4625e5dd7070Spatrick DestWidth = S.Context.getTargetInfo().getUnwindWordWidth();
4626e5dd7070Spatrick break;
4627e5dd7070Spatrick }
4628e5dd7070Spatrick }
4629e5dd7070Spatrick
4630e5dd7070Spatrick /// handleModeAttr - This attribute modifies the width of a decl with primitive
4631e5dd7070Spatrick /// type.
4632e5dd7070Spatrick ///
4633e5dd7070Spatrick /// Despite what would be logical, the mode attribute is a decl attribute, not a
4634e5dd7070Spatrick /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
4635e5dd7070Spatrick /// HImode, not an intermediate pointer.
handleModeAttr(Sema & S,Decl * D,const ParsedAttr & AL)4636e5dd7070Spatrick static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4637e5dd7070Spatrick // This attribute isn't documented, but glibc uses it. It changes
4638e5dd7070Spatrick // the width of an int or unsigned int to the specified size.
4639e5dd7070Spatrick if (!AL.isArgIdent(0)) {
4640e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
4641e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
4642e5dd7070Spatrick return;
4643e5dd7070Spatrick }
4644e5dd7070Spatrick
4645e5dd7070Spatrick IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident;
4646e5dd7070Spatrick
4647e5dd7070Spatrick S.AddModeAttr(D, AL, Name);
4648e5dd7070Spatrick }
4649e5dd7070Spatrick
AddModeAttr(Decl * D,const AttributeCommonInfo & CI,IdentifierInfo * Name,bool InInstantiation)4650e5dd7070Spatrick void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
4651e5dd7070Spatrick IdentifierInfo *Name, bool InInstantiation) {
4652e5dd7070Spatrick StringRef Str = Name->getName();
4653e5dd7070Spatrick normalizeName(Str);
4654e5dd7070Spatrick SourceLocation AttrLoc = CI.getLoc();
4655e5dd7070Spatrick
4656e5dd7070Spatrick unsigned DestWidth = 0;
4657e5dd7070Spatrick bool IntegerMode = true;
4658e5dd7070Spatrick bool ComplexMode = false;
4659*7a9b00ceSrobert FloatModeKind ExplicitType = FloatModeKind::NoFloat;
4660e5dd7070Spatrick llvm::APInt VectorSize(64, 0);
4661e5dd7070Spatrick if (Str.size() >= 4 && Str[0] == 'V') {
4662e5dd7070Spatrick // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2).
4663e5dd7070Spatrick size_t StrSize = Str.size();
4664e5dd7070Spatrick size_t VectorStringLength = 0;
4665e5dd7070Spatrick while ((VectorStringLength + 1) < StrSize &&
4666e5dd7070Spatrick isdigit(Str[VectorStringLength + 1]))
4667e5dd7070Spatrick ++VectorStringLength;
4668e5dd7070Spatrick if (VectorStringLength &&
4669e5dd7070Spatrick !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) &&
4670e5dd7070Spatrick VectorSize.isPowerOf2()) {
4671e5dd7070Spatrick parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth,
4672*7a9b00ceSrobert IntegerMode, ComplexMode, ExplicitType);
4673e5dd7070Spatrick // Avoid duplicate warning from template instantiation.
4674e5dd7070Spatrick if (!InInstantiation)
4675e5dd7070Spatrick Diag(AttrLoc, diag::warn_vector_mode_deprecated);
4676e5dd7070Spatrick } else {
4677e5dd7070Spatrick VectorSize = 0;
4678e5dd7070Spatrick }
4679e5dd7070Spatrick }
4680e5dd7070Spatrick
4681e5dd7070Spatrick if (!VectorSize)
4682ec727ea7Spatrick parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode,
4683*7a9b00ceSrobert ExplicitType);
4684e5dd7070Spatrick
4685e5dd7070Spatrick // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
4686e5dd7070Spatrick // and friends, at least with glibc.
4687e5dd7070Spatrick // FIXME: Make sure floating-point mappings are accurate
4688e5dd7070Spatrick // FIXME: Support XF and TF types
4689e5dd7070Spatrick if (!DestWidth) {
4690e5dd7070Spatrick Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name;
4691e5dd7070Spatrick return;
4692e5dd7070Spatrick }
4693e5dd7070Spatrick
4694e5dd7070Spatrick QualType OldTy;
4695e5dd7070Spatrick if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
4696e5dd7070Spatrick OldTy = TD->getUnderlyingType();
4697e5dd7070Spatrick else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
4698e5dd7070Spatrick // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'.
4699e5dd7070Spatrick // Try to get type from enum declaration, default to int.
4700e5dd7070Spatrick OldTy = ED->getIntegerType();
4701e5dd7070Spatrick if (OldTy.isNull())
4702e5dd7070Spatrick OldTy = Context.IntTy;
4703e5dd7070Spatrick } else
4704e5dd7070Spatrick OldTy = cast<ValueDecl>(D)->getType();
4705e5dd7070Spatrick
4706e5dd7070Spatrick if (OldTy->isDependentType()) {
4707e5dd7070Spatrick D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
4708e5dd7070Spatrick return;
4709e5dd7070Spatrick }
4710e5dd7070Spatrick
4711e5dd7070Spatrick // Base type can also be a vector type (see PR17453).
4712e5dd7070Spatrick // Distinguish between base type and base element type.
4713e5dd7070Spatrick QualType OldElemTy = OldTy;
4714e5dd7070Spatrick if (const auto *VT = OldTy->getAs<VectorType>())
4715e5dd7070Spatrick OldElemTy = VT->getElementType();
4716e5dd7070Spatrick
4717e5dd7070Spatrick // GCC allows 'mode' attribute on enumeration types (even incomplete), except
4718e5dd7070Spatrick // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete
4719e5dd7070Spatrick // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
4720e5dd7070Spatrick if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
4721e5dd7070Spatrick VectorSize.getBoolValue()) {
4722e5dd7070Spatrick Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
4723e5dd7070Spatrick return;
4724e5dd7070Spatrick }
4725ec727ea7Spatrick bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() &&
4726*7a9b00ceSrobert !OldElemTy->isBitIntType()) ||
4727ec727ea7Spatrick OldElemTy->getAs<EnumType>();
4728e5dd7070Spatrick
4729e5dd7070Spatrick if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
4730e5dd7070Spatrick !IntegralOrAnyEnumType)
4731e5dd7070Spatrick Diag(AttrLoc, diag::err_mode_not_primitive);
4732e5dd7070Spatrick else if (IntegerMode) {
4733e5dd7070Spatrick if (!IntegralOrAnyEnumType)
4734e5dd7070Spatrick Diag(AttrLoc, diag::err_mode_wrong_type);
4735e5dd7070Spatrick } else if (ComplexMode) {
4736e5dd7070Spatrick if (!OldElemTy->isComplexType())
4737e5dd7070Spatrick Diag(AttrLoc, diag::err_mode_wrong_type);
4738e5dd7070Spatrick } else {
4739e5dd7070Spatrick if (!OldElemTy->isFloatingType())
4740e5dd7070Spatrick Diag(AttrLoc, diag::err_mode_wrong_type);
4741e5dd7070Spatrick }
4742e5dd7070Spatrick
4743e5dd7070Spatrick QualType NewElemTy;
4744e5dd7070Spatrick
4745e5dd7070Spatrick if (IntegerMode)
4746e5dd7070Spatrick NewElemTy = Context.getIntTypeForBitwidth(DestWidth,
4747e5dd7070Spatrick OldElemTy->isSignedIntegerType());
4748e5dd7070Spatrick else
4749*7a9b00ceSrobert NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitType);
4750e5dd7070Spatrick
4751e5dd7070Spatrick if (NewElemTy.isNull()) {
4752e5dd7070Spatrick Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
4753e5dd7070Spatrick return;
4754e5dd7070Spatrick }
4755e5dd7070Spatrick
4756e5dd7070Spatrick if (ComplexMode) {
4757e5dd7070Spatrick NewElemTy = Context.getComplexType(NewElemTy);
4758e5dd7070Spatrick }
4759e5dd7070Spatrick
4760e5dd7070Spatrick QualType NewTy = NewElemTy;
4761e5dd7070Spatrick if (VectorSize.getBoolValue()) {
4762e5dd7070Spatrick NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(),
4763e5dd7070Spatrick VectorType::GenericVector);
4764e5dd7070Spatrick } else if (const auto *OldVT = OldTy->getAs<VectorType>()) {
4765e5dd7070Spatrick // Complex machine mode does not support base vector types.
4766e5dd7070Spatrick if (ComplexMode) {
4767e5dd7070Spatrick Diag(AttrLoc, diag::err_complex_mode_vector_type);
4768e5dd7070Spatrick return;
4769e5dd7070Spatrick }
4770e5dd7070Spatrick unsigned NumElements = Context.getTypeSize(OldElemTy) *
4771e5dd7070Spatrick OldVT->getNumElements() /
4772e5dd7070Spatrick Context.getTypeSize(NewElemTy);
4773e5dd7070Spatrick NewTy =
4774e5dd7070Spatrick Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind());
4775e5dd7070Spatrick }
4776e5dd7070Spatrick
4777e5dd7070Spatrick if (NewTy.isNull()) {
4778e5dd7070Spatrick Diag(AttrLoc, diag::err_mode_wrong_type);
4779e5dd7070Spatrick return;
4780e5dd7070Spatrick }
4781e5dd7070Spatrick
4782e5dd7070Spatrick // Install the new type.
4783e5dd7070Spatrick if (auto *TD = dyn_cast<TypedefNameDecl>(D))
4784e5dd7070Spatrick TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy);
4785e5dd7070Spatrick else if (auto *ED = dyn_cast<EnumDecl>(D))
4786e5dd7070Spatrick ED->setIntegerType(NewTy);
4787e5dd7070Spatrick else
4788e5dd7070Spatrick cast<ValueDecl>(D)->setType(NewTy);
4789e5dd7070Spatrick
4790e5dd7070Spatrick D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
4791e5dd7070Spatrick }
4792e5dd7070Spatrick
handleNoDebugAttr(Sema & S,Decl * D,const ParsedAttr & AL)4793e5dd7070Spatrick static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4794e5dd7070Spatrick D->addAttr(::new (S.Context) NoDebugAttr(S.Context, AL));
4795e5dd7070Spatrick }
4796e5dd7070Spatrick
mergeAlwaysInlineAttr(Decl * D,const AttributeCommonInfo & CI,const IdentifierInfo * Ident)4797e5dd7070Spatrick AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D,
4798e5dd7070Spatrick const AttributeCommonInfo &CI,
4799e5dd7070Spatrick const IdentifierInfo *Ident) {
4800e5dd7070Spatrick if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
4801e5dd7070Spatrick Diag(CI.getLoc(), diag::warn_attribute_ignored) << Ident;
4802e5dd7070Spatrick Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
4803e5dd7070Spatrick return nullptr;
4804e5dd7070Spatrick }
4805e5dd7070Spatrick
4806e5dd7070Spatrick if (D->hasAttr<AlwaysInlineAttr>())
4807e5dd7070Spatrick return nullptr;
4808e5dd7070Spatrick
4809e5dd7070Spatrick return ::new (Context) AlwaysInlineAttr(Context, CI);
4810e5dd7070Spatrick }
4811e5dd7070Spatrick
mergeInternalLinkageAttr(Decl * D,const ParsedAttr & AL)4812e5dd7070Spatrick InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
4813e5dd7070Spatrick const ParsedAttr &AL) {
4814e5dd7070Spatrick if (const auto *VD = dyn_cast<VarDecl>(D)) {
4815e5dd7070Spatrick // Attribute applies to Var but not any subclass of it (like ParmVar,
4816e5dd7070Spatrick // ImplicitParm or VarTemplateSpecialization).
4817e5dd7070Spatrick if (VD->getKind() != Decl::Var) {
4818e5dd7070Spatrick Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
4819e5dd7070Spatrick << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
4820e5dd7070Spatrick : ExpectedVariableOrFunction);
4821e5dd7070Spatrick return nullptr;
4822e5dd7070Spatrick }
4823e5dd7070Spatrick // Attribute does not apply to non-static local variables.
4824e5dd7070Spatrick if (VD->hasLocalStorage()) {
4825e5dd7070Spatrick Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
4826e5dd7070Spatrick return nullptr;
4827e5dd7070Spatrick }
4828e5dd7070Spatrick }
4829e5dd7070Spatrick
4830e5dd7070Spatrick return ::new (Context) InternalLinkageAttr(Context, AL);
4831e5dd7070Spatrick }
4832e5dd7070Spatrick InternalLinkageAttr *
mergeInternalLinkageAttr(Decl * D,const InternalLinkageAttr & AL)4833e5dd7070Spatrick Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
4834e5dd7070Spatrick if (const auto *VD = dyn_cast<VarDecl>(D)) {
4835e5dd7070Spatrick // Attribute applies to Var but not any subclass of it (like ParmVar,
4836e5dd7070Spatrick // ImplicitParm or VarTemplateSpecialization).
4837e5dd7070Spatrick if (VD->getKind() != Decl::Var) {
4838e5dd7070Spatrick Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type)
4839e5dd7070Spatrick << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
4840e5dd7070Spatrick : ExpectedVariableOrFunction);
4841e5dd7070Spatrick return nullptr;
4842e5dd7070Spatrick }
4843e5dd7070Spatrick // Attribute does not apply to non-static local variables.
4844e5dd7070Spatrick if (VD->hasLocalStorage()) {
4845e5dd7070Spatrick Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
4846e5dd7070Spatrick return nullptr;
4847e5dd7070Spatrick }
4848e5dd7070Spatrick }
4849e5dd7070Spatrick
4850e5dd7070Spatrick return ::new (Context) InternalLinkageAttr(Context, AL);
4851e5dd7070Spatrick }
4852e5dd7070Spatrick
mergeMinSizeAttr(Decl * D,const AttributeCommonInfo & CI)4853e5dd7070Spatrick MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
4854e5dd7070Spatrick if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
4855e5dd7070Spatrick Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'minsize'";
4856e5dd7070Spatrick Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
4857e5dd7070Spatrick return nullptr;
4858e5dd7070Spatrick }
4859e5dd7070Spatrick
4860e5dd7070Spatrick if (D->hasAttr<MinSizeAttr>())
4861e5dd7070Spatrick return nullptr;
4862e5dd7070Spatrick
4863e5dd7070Spatrick return ::new (Context) MinSizeAttr(Context, CI);
4864e5dd7070Spatrick }
4865e5dd7070Spatrick
mergeSwiftNameAttr(Decl * D,const SwiftNameAttr & SNA,StringRef Name)4866a0747c9fSpatrick SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
4867a0747c9fSpatrick StringRef Name) {
4868a0747c9fSpatrick if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) {
4869a0747c9fSpatrick if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) {
4870a0747c9fSpatrick Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible)
4871a0747c9fSpatrick << PrevSNA << &SNA;
4872a0747c9fSpatrick Diag(SNA.getLoc(), diag::note_conflicting_attribute);
4873a0747c9fSpatrick }
4874e5dd7070Spatrick
4875a0747c9fSpatrick D->dropAttr<SwiftNameAttr>();
4876a0747c9fSpatrick }
4877a0747c9fSpatrick return ::new (Context) SwiftNameAttr(Context, SNA, Name);
4878e5dd7070Spatrick }
4879e5dd7070Spatrick
mergeOptimizeNoneAttr(Decl * D,const AttributeCommonInfo & CI)4880e5dd7070Spatrick OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
4881e5dd7070Spatrick const AttributeCommonInfo &CI) {
4882e5dd7070Spatrick if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
4883e5dd7070Spatrick Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
4884e5dd7070Spatrick Diag(CI.getLoc(), diag::note_conflicting_attribute);
4885e5dd7070Spatrick D->dropAttr<AlwaysInlineAttr>();
4886e5dd7070Spatrick }
4887e5dd7070Spatrick if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) {
4888e5dd7070Spatrick Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize;
4889e5dd7070Spatrick Diag(CI.getLoc(), diag::note_conflicting_attribute);
4890e5dd7070Spatrick D->dropAttr<MinSizeAttr>();
4891e5dd7070Spatrick }
4892e5dd7070Spatrick
4893e5dd7070Spatrick if (D->hasAttr<OptimizeNoneAttr>())
4894e5dd7070Spatrick return nullptr;
4895e5dd7070Spatrick
4896e5dd7070Spatrick return ::new (Context) OptimizeNoneAttr(Context, CI);
4897e5dd7070Spatrick }
4898e5dd7070Spatrick
handleAlwaysInlineAttr(Sema & S,Decl * D,const ParsedAttr & AL)4899e5dd7070Spatrick static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4900e5dd7070Spatrick if (AlwaysInlineAttr *Inline =
4901e5dd7070Spatrick S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName()))
4902e5dd7070Spatrick D->addAttr(Inline);
4903e5dd7070Spatrick }
4904e5dd7070Spatrick
handleMinSizeAttr(Sema & S,Decl * D,const ParsedAttr & AL)4905e5dd7070Spatrick static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4906e5dd7070Spatrick if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(D, AL))
4907e5dd7070Spatrick D->addAttr(MinSize);
4908e5dd7070Spatrick }
4909e5dd7070Spatrick
handleOptimizeNoneAttr(Sema & S,Decl * D,const ParsedAttr & AL)4910e5dd7070Spatrick static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4911e5dd7070Spatrick if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL))
4912e5dd7070Spatrick D->addAttr(Optnone);
4913e5dd7070Spatrick }
4914e5dd7070Spatrick
handleConstantAttr(Sema & S,Decl * D,const ParsedAttr & AL)4915e5dd7070Spatrick static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4916e5dd7070Spatrick const auto *VD = cast<VarDecl>(D);
4917a0747c9fSpatrick if (VD->hasLocalStorage()) {
4918a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
4919e5dd7070Spatrick return;
4920e5dd7070Spatrick }
4921a0747c9fSpatrick // constexpr variable may already get an implicit constant attr, which should
4922a0747c9fSpatrick // be replaced by the explicit constant attr.
4923a0747c9fSpatrick if (auto *A = D->getAttr<CUDAConstantAttr>()) {
4924a0747c9fSpatrick if (!A->isImplicit())
4925a0747c9fSpatrick return;
4926a0747c9fSpatrick D->dropAttr<CUDAConstantAttr>();
4927a0747c9fSpatrick }
4928e5dd7070Spatrick D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL));
4929e5dd7070Spatrick }
4930e5dd7070Spatrick
handleSharedAttr(Sema & S,Decl * D,const ParsedAttr & AL)4931e5dd7070Spatrick static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4932e5dd7070Spatrick const auto *VD = cast<VarDecl>(D);
4933e5dd7070Spatrick // extern __shared__ is only allowed on arrays with no length (e.g.
4934e5dd7070Spatrick // "int x[]").
4935e5dd7070Spatrick if (!S.getLangOpts().GPURelocatableDeviceCode && VD->hasExternalStorage() &&
4936e5dd7070Spatrick !isa<IncompleteArrayType>(VD->getType())) {
4937e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD;
4938e5dd7070Spatrick return;
4939e5dd7070Spatrick }
4940e5dd7070Spatrick if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
4941e5dd7070Spatrick S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
4942e5dd7070Spatrick << S.CurrentCUDATarget())
4943e5dd7070Spatrick return;
4944e5dd7070Spatrick D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
4945e5dd7070Spatrick }
4946e5dd7070Spatrick
handleGlobalAttr(Sema & S,Decl * D,const ParsedAttr & AL)4947e5dd7070Spatrick static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4948e5dd7070Spatrick const auto *FD = cast<FunctionDecl>(D);
4949e5dd7070Spatrick if (!FD->getReturnType()->isVoidType() &&
4950e5dd7070Spatrick !FD->getReturnType()->getAs<AutoType>() &&
4951e5dd7070Spatrick !FD->getReturnType()->isInstantiationDependentType()) {
4952e5dd7070Spatrick SourceRange RTRange = FD->getReturnTypeSourceRange();
4953e5dd7070Spatrick S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
4954e5dd7070Spatrick << FD->getType()
4955e5dd7070Spatrick << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void")
4956e5dd7070Spatrick : FixItHint());
4957e5dd7070Spatrick return;
4958e5dd7070Spatrick }
4959e5dd7070Spatrick if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
4960e5dd7070Spatrick if (Method->isInstance()) {
4961e5dd7070Spatrick S.Diag(Method->getBeginLoc(), diag::err_kern_is_nonstatic_method)
4962e5dd7070Spatrick << Method;
4963e5dd7070Spatrick return;
4964e5dd7070Spatrick }
4965e5dd7070Spatrick S.Diag(Method->getBeginLoc(), diag::warn_kern_is_method) << Method;
4966e5dd7070Spatrick }
4967e5dd7070Spatrick // Only warn for "inline" when compiling for host, to cut down on noise.
4968e5dd7070Spatrick if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice)
4969e5dd7070Spatrick S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD;
4970e5dd7070Spatrick
4971e5dd7070Spatrick D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL));
4972ec727ea7Spatrick // In host compilation the kernel is emitted as a stub function, which is
4973ec727ea7Spatrick // a helper function for launching the kernel. The instructions in the helper
4974ec727ea7Spatrick // function has nothing to do with the source code of the kernel. Do not emit
4975ec727ea7Spatrick // debug info for the stub function to avoid confusing the debugger.
4976ec727ea7Spatrick if (S.LangOpts.HIP && !S.LangOpts.CUDAIsDevice)
4977ec727ea7Spatrick D->addAttr(NoDebugAttr::CreateImplicit(S.Context));
4978e5dd7070Spatrick }
4979e5dd7070Spatrick
handleDeviceAttr(Sema & S,Decl * D,const ParsedAttr & AL)4980a0747c9fSpatrick static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4981a0747c9fSpatrick if (const auto *VD = dyn_cast<VarDecl>(D)) {
4982a0747c9fSpatrick if (VD->hasLocalStorage()) {
4983a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
4984a0747c9fSpatrick return;
4985a0747c9fSpatrick }
4986a0747c9fSpatrick }
4987a0747c9fSpatrick
4988a0747c9fSpatrick if (auto *A = D->getAttr<CUDADeviceAttr>()) {
4989a0747c9fSpatrick if (!A->isImplicit())
4990a0747c9fSpatrick return;
4991a0747c9fSpatrick D->dropAttr<CUDADeviceAttr>();
4992a0747c9fSpatrick }
4993a0747c9fSpatrick D->addAttr(::new (S.Context) CUDADeviceAttr(S.Context, AL));
4994a0747c9fSpatrick }
4995a0747c9fSpatrick
handleManagedAttr(Sema & S,Decl * D,const ParsedAttr & AL)4996a0747c9fSpatrick static void handleManagedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4997a0747c9fSpatrick if (const auto *VD = dyn_cast<VarDecl>(D)) {
4998a0747c9fSpatrick if (VD->hasLocalStorage()) {
4999a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
5000a0747c9fSpatrick return;
5001a0747c9fSpatrick }
5002a0747c9fSpatrick }
5003a0747c9fSpatrick if (!D->hasAttr<HIPManagedAttr>())
5004a0747c9fSpatrick D->addAttr(::new (S.Context) HIPManagedAttr(S.Context, AL));
5005a0747c9fSpatrick if (!D->hasAttr<CUDADeviceAttr>())
5006a0747c9fSpatrick D->addAttr(CUDADeviceAttr::CreateImplicit(S.Context));
5007a0747c9fSpatrick }
5008a0747c9fSpatrick
handleGNUInlineAttr(Sema & S,Decl * D,const ParsedAttr & AL)5009e5dd7070Spatrick static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5010e5dd7070Spatrick const auto *Fn = cast<FunctionDecl>(D);
5011e5dd7070Spatrick if (!Fn->isInlineSpecified()) {
5012e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
5013e5dd7070Spatrick return;
5014e5dd7070Spatrick }
5015e5dd7070Spatrick
5016e5dd7070Spatrick if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern)
5017e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern);
5018e5dd7070Spatrick
5019e5dd7070Spatrick D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL));
5020e5dd7070Spatrick }
5021e5dd7070Spatrick
handleCallConvAttr(Sema & S,Decl * D,const ParsedAttr & AL)5022e5dd7070Spatrick static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5023e5dd7070Spatrick if (hasDeclarator(D)) return;
5024e5dd7070Spatrick
5025e5dd7070Spatrick // Diagnostic is emitted elsewhere: here we store the (valid) AL
5026e5dd7070Spatrick // in the Decl node for syntactic reasoning, e.g., pretty-printing.
5027e5dd7070Spatrick CallingConv CC;
5028e5dd7070Spatrick if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr))
5029e5dd7070Spatrick return;
5030e5dd7070Spatrick
5031e5dd7070Spatrick if (!isa<ObjCMethodDecl>(D)) {
5032e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
5033e5dd7070Spatrick << AL << ExpectedFunctionOrMethod;
5034e5dd7070Spatrick return;
5035e5dd7070Spatrick }
5036e5dd7070Spatrick
5037e5dd7070Spatrick switch (AL.getKind()) {
5038e5dd7070Spatrick case ParsedAttr::AT_FastCall:
5039e5dd7070Spatrick D->addAttr(::new (S.Context) FastCallAttr(S.Context, AL));
5040e5dd7070Spatrick return;
5041e5dd7070Spatrick case ParsedAttr::AT_StdCall:
5042e5dd7070Spatrick D->addAttr(::new (S.Context) StdCallAttr(S.Context, AL));
5043e5dd7070Spatrick return;
5044e5dd7070Spatrick case ParsedAttr::AT_ThisCall:
5045e5dd7070Spatrick D->addAttr(::new (S.Context) ThisCallAttr(S.Context, AL));
5046e5dd7070Spatrick return;
5047e5dd7070Spatrick case ParsedAttr::AT_CDecl:
5048e5dd7070Spatrick D->addAttr(::new (S.Context) CDeclAttr(S.Context, AL));
5049e5dd7070Spatrick return;
5050e5dd7070Spatrick case ParsedAttr::AT_Pascal:
5051e5dd7070Spatrick D->addAttr(::new (S.Context) PascalAttr(S.Context, AL));
5052e5dd7070Spatrick return;
5053e5dd7070Spatrick case ParsedAttr::AT_SwiftCall:
5054e5dd7070Spatrick D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL));
5055e5dd7070Spatrick return;
5056a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncCall:
5057a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftAsyncCallAttr(S.Context, AL));
5058a0747c9fSpatrick return;
5059e5dd7070Spatrick case ParsedAttr::AT_VectorCall:
5060e5dd7070Spatrick D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL));
5061e5dd7070Spatrick return;
5062e5dd7070Spatrick case ParsedAttr::AT_MSABI:
5063e5dd7070Spatrick D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL));
5064e5dd7070Spatrick return;
5065e5dd7070Spatrick case ParsedAttr::AT_SysVABI:
5066e5dd7070Spatrick D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL));
5067e5dd7070Spatrick return;
5068e5dd7070Spatrick case ParsedAttr::AT_RegCall:
5069e5dd7070Spatrick D->addAttr(::new (S.Context) RegCallAttr(S.Context, AL));
5070e5dd7070Spatrick return;
5071e5dd7070Spatrick case ParsedAttr::AT_Pcs: {
5072e5dd7070Spatrick PcsAttr::PCSType PCS;
5073e5dd7070Spatrick switch (CC) {
5074e5dd7070Spatrick case CC_AAPCS:
5075e5dd7070Spatrick PCS = PcsAttr::AAPCS;
5076e5dd7070Spatrick break;
5077e5dd7070Spatrick case CC_AAPCS_VFP:
5078e5dd7070Spatrick PCS = PcsAttr::AAPCS_VFP;
5079e5dd7070Spatrick break;
5080e5dd7070Spatrick default:
5081e5dd7070Spatrick llvm_unreachable("unexpected calling convention in pcs attribute");
5082e5dd7070Spatrick }
5083e5dd7070Spatrick
5084e5dd7070Spatrick D->addAttr(::new (S.Context) PcsAttr(S.Context, AL, PCS));
5085e5dd7070Spatrick return;
5086e5dd7070Spatrick }
5087e5dd7070Spatrick case ParsedAttr::AT_AArch64VectorPcs:
5088e5dd7070Spatrick D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL));
5089e5dd7070Spatrick return;
5090*7a9b00ceSrobert case ParsedAttr::AT_AArch64SVEPcs:
5091*7a9b00ceSrobert D->addAttr(::new (S.Context) AArch64SVEPcsAttr(S.Context, AL));
5092*7a9b00ceSrobert return;
5093*7a9b00ceSrobert case ParsedAttr::AT_AMDGPUKernelCall:
5094*7a9b00ceSrobert D->addAttr(::new (S.Context) AMDGPUKernelCallAttr(S.Context, AL));
5095*7a9b00ceSrobert return;
5096e5dd7070Spatrick case ParsedAttr::AT_IntelOclBicc:
5097e5dd7070Spatrick D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL));
5098e5dd7070Spatrick return;
5099e5dd7070Spatrick case ParsedAttr::AT_PreserveMost:
5100e5dd7070Spatrick D->addAttr(::new (S.Context) PreserveMostAttr(S.Context, AL));
5101e5dd7070Spatrick return;
5102e5dd7070Spatrick case ParsedAttr::AT_PreserveAll:
5103e5dd7070Spatrick D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL));
5104e5dd7070Spatrick return;
5105e5dd7070Spatrick default:
5106e5dd7070Spatrick llvm_unreachable("unexpected attribute kind");
5107e5dd7070Spatrick }
5108e5dd7070Spatrick }
5109e5dd7070Spatrick
handleSuppressAttr(Sema & S,Decl * D,const ParsedAttr & AL)5110e5dd7070Spatrick static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5111a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
5112e5dd7070Spatrick return;
5113e5dd7070Spatrick
5114e5dd7070Spatrick std::vector<StringRef> DiagnosticIdentifiers;
5115e5dd7070Spatrick for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
5116e5dd7070Spatrick StringRef RuleName;
5117e5dd7070Spatrick
5118e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr))
5119e5dd7070Spatrick return;
5120e5dd7070Spatrick
5121e5dd7070Spatrick // FIXME: Warn if the rule name is unknown. This is tricky because only
5122e5dd7070Spatrick // clang-tidy knows about available rules.
5123e5dd7070Spatrick DiagnosticIdentifiers.push_back(RuleName);
5124e5dd7070Spatrick }
5125e5dd7070Spatrick D->addAttr(::new (S.Context)
5126e5dd7070Spatrick SuppressAttr(S.Context, AL, DiagnosticIdentifiers.data(),
5127e5dd7070Spatrick DiagnosticIdentifiers.size()));
5128e5dd7070Spatrick }
5129e5dd7070Spatrick
handleLifetimeCategoryAttr(Sema & S,Decl * D,const ParsedAttr & AL)5130e5dd7070Spatrick static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5131e5dd7070Spatrick TypeSourceInfo *DerefTypeLoc = nullptr;
5132e5dd7070Spatrick QualType ParmType;
5133e5dd7070Spatrick if (AL.hasParsedType()) {
5134e5dd7070Spatrick ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
5135e5dd7070Spatrick
5136e5dd7070Spatrick unsigned SelectIdx = ~0U;
5137e5dd7070Spatrick if (ParmType->isReferenceType())
5138e5dd7070Spatrick SelectIdx = 0;
5139e5dd7070Spatrick else if (ParmType->isArrayType())
5140e5dd7070Spatrick SelectIdx = 1;
5141e5dd7070Spatrick
5142e5dd7070Spatrick if (SelectIdx != ~0U) {
5143e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
5144e5dd7070Spatrick << SelectIdx << AL;
5145e5dd7070Spatrick return;
5146e5dd7070Spatrick }
5147e5dd7070Spatrick }
5148e5dd7070Spatrick
5149e5dd7070Spatrick // To check if earlier decl attributes do not conflict the newly parsed ones
5150*7a9b00ceSrobert // we always add (and check) the attribute to the canonical decl. We need
5151a0747c9fSpatrick // to repeat the check for attribute mutual exclusion because we're attaching
5152a0747c9fSpatrick // all of the attributes to the canonical declaration rather than the current
5153a0747c9fSpatrick // declaration.
5154e5dd7070Spatrick D = D->getCanonicalDecl();
5155e5dd7070Spatrick if (AL.getKind() == ParsedAttr::AT_Owner) {
5156e5dd7070Spatrick if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
5157e5dd7070Spatrick return;
5158e5dd7070Spatrick if (const auto *OAttr = D->getAttr<OwnerAttr>()) {
5159e5dd7070Spatrick const Type *ExistingDerefType = OAttr->getDerefTypeLoc()
5160e5dd7070Spatrick ? OAttr->getDerefType().getTypePtr()
5161e5dd7070Spatrick : nullptr;
5162e5dd7070Spatrick if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
5163e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
5164e5dd7070Spatrick << AL << OAttr;
5165e5dd7070Spatrick S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
5166e5dd7070Spatrick }
5167e5dd7070Spatrick return;
5168e5dd7070Spatrick }
5169e5dd7070Spatrick for (Decl *Redecl : D->redecls()) {
5170e5dd7070Spatrick Redecl->addAttr(::new (S.Context) OwnerAttr(S.Context, AL, DerefTypeLoc));
5171e5dd7070Spatrick }
5172e5dd7070Spatrick } else {
5173e5dd7070Spatrick if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
5174e5dd7070Spatrick return;
5175e5dd7070Spatrick if (const auto *PAttr = D->getAttr<PointerAttr>()) {
5176e5dd7070Spatrick const Type *ExistingDerefType = PAttr->getDerefTypeLoc()
5177e5dd7070Spatrick ? PAttr->getDerefType().getTypePtr()
5178e5dd7070Spatrick : nullptr;
5179e5dd7070Spatrick if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
5180e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
5181e5dd7070Spatrick << AL << PAttr;
5182e5dd7070Spatrick S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
5183e5dd7070Spatrick }
5184e5dd7070Spatrick return;
5185e5dd7070Spatrick }
5186e5dd7070Spatrick for (Decl *Redecl : D->redecls()) {
5187e5dd7070Spatrick Redecl->addAttr(::new (S.Context)
5188e5dd7070Spatrick PointerAttr(S.Context, AL, DerefTypeLoc));
5189e5dd7070Spatrick }
5190e5dd7070Spatrick }
5191e5dd7070Spatrick }
5192e5dd7070Spatrick
handleRandomizeLayoutAttr(Sema & S,Decl * D,const ParsedAttr & AL)5193*7a9b00ceSrobert static void handleRandomizeLayoutAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5194*7a9b00ceSrobert if (checkAttrMutualExclusion<NoRandomizeLayoutAttr>(S, D, AL))
5195*7a9b00ceSrobert return;
5196*7a9b00ceSrobert if (!D->hasAttr<RandomizeLayoutAttr>())
5197*7a9b00ceSrobert D->addAttr(::new (S.Context) RandomizeLayoutAttr(S.Context, AL));
5198*7a9b00ceSrobert }
5199*7a9b00ceSrobert
handleNoRandomizeLayoutAttr(Sema & S,Decl * D,const ParsedAttr & AL)5200*7a9b00ceSrobert static void handleNoRandomizeLayoutAttr(Sema &S, Decl *D,
5201*7a9b00ceSrobert const ParsedAttr &AL) {
5202*7a9b00ceSrobert if (checkAttrMutualExclusion<RandomizeLayoutAttr>(S, D, AL))
5203*7a9b00ceSrobert return;
5204*7a9b00ceSrobert if (!D->hasAttr<NoRandomizeLayoutAttr>())
5205*7a9b00ceSrobert D->addAttr(::new (S.Context) NoRandomizeLayoutAttr(S.Context, AL));
5206*7a9b00ceSrobert }
5207*7a9b00ceSrobert
CheckCallingConvAttr(const ParsedAttr & Attrs,CallingConv & CC,const FunctionDecl * FD)5208e5dd7070Spatrick bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
5209e5dd7070Spatrick const FunctionDecl *FD) {
5210e5dd7070Spatrick if (Attrs.isInvalid())
5211e5dd7070Spatrick return true;
5212e5dd7070Spatrick
5213e5dd7070Spatrick if (Attrs.hasProcessingCache()) {
5214e5dd7070Spatrick CC = (CallingConv) Attrs.getProcessingCache();
5215e5dd7070Spatrick return false;
5216e5dd7070Spatrick }
5217e5dd7070Spatrick
5218e5dd7070Spatrick unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0;
5219a0747c9fSpatrick if (!Attrs.checkExactlyNumArgs(*this, ReqArgs)) {
5220e5dd7070Spatrick Attrs.setInvalid();
5221e5dd7070Spatrick return true;
5222e5dd7070Spatrick }
5223e5dd7070Spatrick
5224e5dd7070Spatrick // TODO: diagnose uses of these conventions on the wrong target.
5225e5dd7070Spatrick switch (Attrs.getKind()) {
5226e5dd7070Spatrick case ParsedAttr::AT_CDecl:
5227e5dd7070Spatrick CC = CC_C;
5228e5dd7070Spatrick break;
5229e5dd7070Spatrick case ParsedAttr::AT_FastCall:
5230e5dd7070Spatrick CC = CC_X86FastCall;
5231e5dd7070Spatrick break;
5232e5dd7070Spatrick case ParsedAttr::AT_StdCall:
5233e5dd7070Spatrick CC = CC_X86StdCall;
5234e5dd7070Spatrick break;
5235e5dd7070Spatrick case ParsedAttr::AT_ThisCall:
5236e5dd7070Spatrick CC = CC_X86ThisCall;
5237e5dd7070Spatrick break;
5238e5dd7070Spatrick case ParsedAttr::AT_Pascal:
5239e5dd7070Spatrick CC = CC_X86Pascal;
5240e5dd7070Spatrick break;
5241e5dd7070Spatrick case ParsedAttr::AT_SwiftCall:
5242e5dd7070Spatrick CC = CC_Swift;
5243e5dd7070Spatrick break;
5244a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncCall:
5245a0747c9fSpatrick CC = CC_SwiftAsync;
5246a0747c9fSpatrick break;
5247e5dd7070Spatrick case ParsedAttr::AT_VectorCall:
5248e5dd7070Spatrick CC = CC_X86VectorCall;
5249e5dd7070Spatrick break;
5250e5dd7070Spatrick case ParsedAttr::AT_AArch64VectorPcs:
5251e5dd7070Spatrick CC = CC_AArch64VectorCall;
5252e5dd7070Spatrick break;
5253*7a9b00ceSrobert case ParsedAttr::AT_AArch64SVEPcs:
5254*7a9b00ceSrobert CC = CC_AArch64SVEPCS;
5255*7a9b00ceSrobert break;
5256*7a9b00ceSrobert case ParsedAttr::AT_AMDGPUKernelCall:
5257*7a9b00ceSrobert CC = CC_AMDGPUKernelCall;
5258*7a9b00ceSrobert break;
5259e5dd7070Spatrick case ParsedAttr::AT_RegCall:
5260e5dd7070Spatrick CC = CC_X86RegCall;
5261e5dd7070Spatrick break;
5262e5dd7070Spatrick case ParsedAttr::AT_MSABI:
5263e5dd7070Spatrick CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
5264e5dd7070Spatrick CC_Win64;
5265e5dd7070Spatrick break;
5266e5dd7070Spatrick case ParsedAttr::AT_SysVABI:
5267e5dd7070Spatrick CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
5268e5dd7070Spatrick CC_C;
5269e5dd7070Spatrick break;
5270e5dd7070Spatrick case ParsedAttr::AT_Pcs: {
5271e5dd7070Spatrick StringRef StrRef;
5272e5dd7070Spatrick if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) {
5273e5dd7070Spatrick Attrs.setInvalid();
5274e5dd7070Spatrick return true;
5275e5dd7070Spatrick }
5276e5dd7070Spatrick if (StrRef == "aapcs") {
5277e5dd7070Spatrick CC = CC_AAPCS;
5278e5dd7070Spatrick break;
5279e5dd7070Spatrick } else if (StrRef == "aapcs-vfp") {
5280e5dd7070Spatrick CC = CC_AAPCS_VFP;
5281e5dd7070Spatrick break;
5282e5dd7070Spatrick }
5283e5dd7070Spatrick
5284e5dd7070Spatrick Attrs.setInvalid();
5285e5dd7070Spatrick Diag(Attrs.getLoc(), diag::err_invalid_pcs);
5286e5dd7070Spatrick return true;
5287e5dd7070Spatrick }
5288e5dd7070Spatrick case ParsedAttr::AT_IntelOclBicc:
5289e5dd7070Spatrick CC = CC_IntelOclBicc;
5290e5dd7070Spatrick break;
5291e5dd7070Spatrick case ParsedAttr::AT_PreserveMost:
5292e5dd7070Spatrick CC = CC_PreserveMost;
5293e5dd7070Spatrick break;
5294e5dd7070Spatrick case ParsedAttr::AT_PreserveAll:
5295e5dd7070Spatrick CC = CC_PreserveAll;
5296e5dd7070Spatrick break;
5297e5dd7070Spatrick default: llvm_unreachable("unexpected attribute kind");
5298e5dd7070Spatrick }
5299e5dd7070Spatrick
5300e5dd7070Spatrick TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK;
5301e5dd7070Spatrick const TargetInfo &TI = Context.getTargetInfo();
5302e5dd7070Spatrick // CUDA functions may have host and/or device attributes which indicate
5303e5dd7070Spatrick // their targeted execution environment, therefore the calling convention
5304e5dd7070Spatrick // of functions in CUDA should be checked against the target deduced based
5305e5dd7070Spatrick // on their host/device attributes.
5306e5dd7070Spatrick if (LangOpts.CUDA) {
5307e5dd7070Spatrick auto *Aux = Context.getAuxTargetInfo();
5308e5dd7070Spatrick auto CudaTarget = IdentifyCUDATarget(FD);
5309e5dd7070Spatrick bool CheckHost = false, CheckDevice = false;
5310e5dd7070Spatrick switch (CudaTarget) {
5311e5dd7070Spatrick case CFT_HostDevice:
5312e5dd7070Spatrick CheckHost = true;
5313e5dd7070Spatrick CheckDevice = true;
5314e5dd7070Spatrick break;
5315e5dd7070Spatrick case CFT_Host:
5316e5dd7070Spatrick CheckHost = true;
5317e5dd7070Spatrick break;
5318e5dd7070Spatrick case CFT_Device:
5319e5dd7070Spatrick case CFT_Global:
5320e5dd7070Spatrick CheckDevice = true;
5321e5dd7070Spatrick break;
5322e5dd7070Spatrick case CFT_InvalidTarget:
5323e5dd7070Spatrick llvm_unreachable("unexpected cuda target");
5324e5dd7070Spatrick }
5325e5dd7070Spatrick auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI;
5326e5dd7070Spatrick auto *DeviceTI = LangOpts.CUDAIsDevice ? &TI : Aux;
5327e5dd7070Spatrick if (CheckHost && HostTI)
5328e5dd7070Spatrick A = HostTI->checkCallingConvention(CC);
5329e5dd7070Spatrick if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI)
5330e5dd7070Spatrick A = DeviceTI->checkCallingConvention(CC);
5331e5dd7070Spatrick } else {
5332e5dd7070Spatrick A = TI.checkCallingConvention(CC);
5333e5dd7070Spatrick }
5334e5dd7070Spatrick
5335e5dd7070Spatrick switch (A) {
5336e5dd7070Spatrick case TargetInfo::CCCR_OK:
5337e5dd7070Spatrick break;
5338e5dd7070Spatrick
5339e5dd7070Spatrick case TargetInfo::CCCR_Ignore:
5340e5dd7070Spatrick // Treat an ignored convention as if it was an explicit C calling convention
5341e5dd7070Spatrick // attribute. For example, __stdcall on Win x64 functions as __cdecl, so
5342e5dd7070Spatrick // that command line flags that change the default convention to
5343e5dd7070Spatrick // __vectorcall don't affect declarations marked __stdcall.
5344e5dd7070Spatrick CC = CC_C;
5345e5dd7070Spatrick break;
5346e5dd7070Spatrick
5347e5dd7070Spatrick case TargetInfo::CCCR_Error:
5348e5dd7070Spatrick Diag(Attrs.getLoc(), diag::error_cconv_unsupported)
5349e5dd7070Spatrick << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
5350e5dd7070Spatrick break;
5351e5dd7070Spatrick
5352e5dd7070Spatrick case TargetInfo::CCCR_Warning: {
5353e5dd7070Spatrick Diag(Attrs.getLoc(), diag::warn_cconv_unsupported)
5354e5dd7070Spatrick << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
5355e5dd7070Spatrick
5356e5dd7070Spatrick // This convention is not valid for the target. Use the default function or
5357e5dd7070Spatrick // method calling convention.
5358e5dd7070Spatrick bool IsCXXMethod = false, IsVariadic = false;
5359e5dd7070Spatrick if (FD) {
5360e5dd7070Spatrick IsCXXMethod = FD->isCXXInstanceMember();
5361e5dd7070Spatrick IsVariadic = FD->isVariadic();
5362e5dd7070Spatrick }
5363e5dd7070Spatrick CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
5364e5dd7070Spatrick break;
5365e5dd7070Spatrick }
5366e5dd7070Spatrick }
5367e5dd7070Spatrick
5368e5dd7070Spatrick Attrs.setProcessingCache((unsigned) CC);
5369e5dd7070Spatrick return false;
5370e5dd7070Spatrick }
5371e5dd7070Spatrick
5372e5dd7070Spatrick /// Pointer-like types in the default address space.
isValidSwiftContextType(QualType Ty)5373e5dd7070Spatrick static bool isValidSwiftContextType(QualType Ty) {
5374e5dd7070Spatrick if (!Ty->hasPointerRepresentation())
5375e5dd7070Spatrick return Ty->isDependentType();
5376e5dd7070Spatrick return Ty->getPointeeType().getAddressSpace() == LangAS::Default;
5377e5dd7070Spatrick }
5378e5dd7070Spatrick
5379e5dd7070Spatrick /// Pointers and references in the default address space.
isValidSwiftIndirectResultType(QualType Ty)5380e5dd7070Spatrick static bool isValidSwiftIndirectResultType(QualType Ty) {
5381e5dd7070Spatrick if (const auto *PtrType = Ty->getAs<PointerType>()) {
5382e5dd7070Spatrick Ty = PtrType->getPointeeType();
5383e5dd7070Spatrick } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
5384e5dd7070Spatrick Ty = RefType->getPointeeType();
5385e5dd7070Spatrick } else {
5386e5dd7070Spatrick return Ty->isDependentType();
5387e5dd7070Spatrick }
5388e5dd7070Spatrick return Ty.getAddressSpace() == LangAS::Default;
5389e5dd7070Spatrick }
5390e5dd7070Spatrick
5391e5dd7070Spatrick /// Pointers and references to pointers in the default address space.
isValidSwiftErrorResultType(QualType Ty)5392e5dd7070Spatrick static bool isValidSwiftErrorResultType(QualType Ty) {
5393e5dd7070Spatrick if (const auto *PtrType = Ty->getAs<PointerType>()) {
5394e5dd7070Spatrick Ty = PtrType->getPointeeType();
5395e5dd7070Spatrick } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
5396e5dd7070Spatrick Ty = RefType->getPointeeType();
5397e5dd7070Spatrick } else {
5398e5dd7070Spatrick return Ty->isDependentType();
5399e5dd7070Spatrick }
5400e5dd7070Spatrick if (!Ty.getQualifiers().empty())
5401e5dd7070Spatrick return false;
5402e5dd7070Spatrick return isValidSwiftContextType(Ty);
5403e5dd7070Spatrick }
5404e5dd7070Spatrick
AddParameterABIAttr(Decl * D,const AttributeCommonInfo & CI,ParameterABI abi)5405e5dd7070Spatrick void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
5406e5dd7070Spatrick ParameterABI abi) {
5407e5dd7070Spatrick
5408e5dd7070Spatrick QualType type = cast<ParmVarDecl>(D)->getType();
5409e5dd7070Spatrick
5410e5dd7070Spatrick if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
5411e5dd7070Spatrick if (existingAttr->getABI() != abi) {
5412e5dd7070Spatrick Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
5413e5dd7070Spatrick << getParameterABISpelling(abi) << existingAttr;
5414e5dd7070Spatrick Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
5415e5dd7070Spatrick return;
5416e5dd7070Spatrick }
5417e5dd7070Spatrick }
5418e5dd7070Spatrick
5419e5dd7070Spatrick switch (abi) {
5420e5dd7070Spatrick case ParameterABI::Ordinary:
5421e5dd7070Spatrick llvm_unreachable("explicit attribute for ordinary parameter ABI?");
5422e5dd7070Spatrick
5423e5dd7070Spatrick case ParameterABI::SwiftContext:
5424e5dd7070Spatrick if (!isValidSwiftContextType(type)) {
5425e5dd7070Spatrick Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
5426e5dd7070Spatrick << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
5427e5dd7070Spatrick }
5428e5dd7070Spatrick D->addAttr(::new (Context) SwiftContextAttr(Context, CI));
5429e5dd7070Spatrick return;
5430e5dd7070Spatrick
5431a0747c9fSpatrick case ParameterABI::SwiftAsyncContext:
5432a0747c9fSpatrick if (!isValidSwiftContextType(type)) {
5433a0747c9fSpatrick Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
5434a0747c9fSpatrick << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
5435a0747c9fSpatrick }
5436a0747c9fSpatrick D->addAttr(::new (Context) SwiftAsyncContextAttr(Context, CI));
5437a0747c9fSpatrick return;
5438a0747c9fSpatrick
5439e5dd7070Spatrick case ParameterABI::SwiftErrorResult:
5440e5dd7070Spatrick if (!isValidSwiftErrorResultType(type)) {
5441e5dd7070Spatrick Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
5442e5dd7070Spatrick << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type;
5443e5dd7070Spatrick }
5444e5dd7070Spatrick D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI));
5445e5dd7070Spatrick return;
5446e5dd7070Spatrick
5447e5dd7070Spatrick case ParameterABI::SwiftIndirectResult:
5448e5dd7070Spatrick if (!isValidSwiftIndirectResultType(type)) {
5449e5dd7070Spatrick Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
5450e5dd7070Spatrick << getParameterABISpelling(abi) << /*pointer*/ 0 << type;
5451e5dd7070Spatrick }
5452e5dd7070Spatrick D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI));
5453e5dd7070Spatrick return;
5454e5dd7070Spatrick }
5455e5dd7070Spatrick llvm_unreachable("bad parameter ABI attribute");
5456e5dd7070Spatrick }
5457e5dd7070Spatrick
5458e5dd7070Spatrick /// Checks a regparm attribute, returning true if it is ill-formed and
5459e5dd7070Spatrick /// otherwise setting numParams to the appropriate value.
CheckRegparmAttr(const ParsedAttr & AL,unsigned & numParams)5460e5dd7070Spatrick bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
5461e5dd7070Spatrick if (AL.isInvalid())
5462e5dd7070Spatrick return true;
5463e5dd7070Spatrick
5464a0747c9fSpatrick if (!AL.checkExactlyNumArgs(*this, 1)) {
5465e5dd7070Spatrick AL.setInvalid();
5466e5dd7070Spatrick return true;
5467e5dd7070Spatrick }
5468e5dd7070Spatrick
5469e5dd7070Spatrick uint32_t NP;
5470e5dd7070Spatrick Expr *NumParamsExpr = AL.getArgAsExpr(0);
5471e5dd7070Spatrick if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) {
5472e5dd7070Spatrick AL.setInvalid();
5473e5dd7070Spatrick return true;
5474e5dd7070Spatrick }
5475e5dd7070Spatrick
5476e5dd7070Spatrick if (Context.getTargetInfo().getRegParmMax() == 0) {
5477e5dd7070Spatrick Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform)
5478e5dd7070Spatrick << NumParamsExpr->getSourceRange();
5479e5dd7070Spatrick AL.setInvalid();
5480e5dd7070Spatrick return true;
5481e5dd7070Spatrick }
5482e5dd7070Spatrick
5483e5dd7070Spatrick numParams = NP;
5484e5dd7070Spatrick if (numParams > Context.getTargetInfo().getRegParmMax()) {
5485e5dd7070Spatrick Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number)
5486e5dd7070Spatrick << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange();
5487e5dd7070Spatrick AL.setInvalid();
5488e5dd7070Spatrick return true;
5489e5dd7070Spatrick }
5490e5dd7070Spatrick
5491e5dd7070Spatrick return false;
5492e5dd7070Spatrick }
5493e5dd7070Spatrick
5494e5dd7070Spatrick // Checks whether an argument of launch_bounds attribute is
5495e5dd7070Spatrick // acceptable, performs implicit conversion to Rvalue, and returns
5496e5dd7070Spatrick // non-nullptr Expr result on success. Otherwise, it returns nullptr
5497e5dd7070Spatrick // and may output an error.
makeLaunchBoundsArgExpr(Sema & S,Expr * E,const CUDALaunchBoundsAttr & AL,const unsigned Idx)5498e5dd7070Spatrick static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
5499e5dd7070Spatrick const CUDALaunchBoundsAttr &AL,
5500e5dd7070Spatrick const unsigned Idx) {
5501e5dd7070Spatrick if (S.DiagnoseUnexpandedParameterPack(E))
5502e5dd7070Spatrick return nullptr;
5503e5dd7070Spatrick
5504e5dd7070Spatrick // Accept template arguments for now as they depend on something else.
5505e5dd7070Spatrick // We'll get to check them when they eventually get instantiated.
5506e5dd7070Spatrick if (E->isValueDependent())
5507e5dd7070Spatrick return E;
5508e5dd7070Spatrick
5509*7a9b00ceSrobert std::optional<llvm::APSInt> I = llvm::APSInt(64);
5510a0747c9fSpatrick if (!(I = E->getIntegerConstantExpr(S.Context))) {
5511e5dd7070Spatrick S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type)
5512e5dd7070Spatrick << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange();
5513e5dd7070Spatrick return nullptr;
5514e5dd7070Spatrick }
5515e5dd7070Spatrick // Make sure we can fit it in 32 bits.
5516a0747c9fSpatrick if (!I->isIntN(32)) {
5517a0747c9fSpatrick S.Diag(E->getExprLoc(), diag::err_ice_too_large)
5518a0747c9fSpatrick << toString(*I, 10, false) << 32 << /* Unsigned */ 1;
5519e5dd7070Spatrick return nullptr;
5520e5dd7070Spatrick }
5521a0747c9fSpatrick if (*I < 0)
5522e5dd7070Spatrick S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative)
5523e5dd7070Spatrick << &AL << Idx << E->getSourceRange();
5524e5dd7070Spatrick
5525e5dd7070Spatrick // We may need to perform implicit conversion of the argument.
5526e5dd7070Spatrick InitializedEntity Entity = InitializedEntity::InitializeParameter(
5527e5dd7070Spatrick S.Context, S.Context.getConstType(S.Context.IntTy), /*consume*/ false);
5528e5dd7070Spatrick ExprResult ValArg = S.PerformCopyInitialization(Entity, SourceLocation(), E);
5529e5dd7070Spatrick assert(!ValArg.isInvalid() &&
5530e5dd7070Spatrick "Unexpected PerformCopyInitialization() failure.");
5531e5dd7070Spatrick
5532e5dd7070Spatrick return ValArg.getAs<Expr>();
5533e5dd7070Spatrick }
5534e5dd7070Spatrick
AddLaunchBoundsAttr(Decl * D,const AttributeCommonInfo & CI,Expr * MaxThreads,Expr * MinBlocks)5535e5dd7070Spatrick void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,
5536e5dd7070Spatrick Expr *MaxThreads, Expr *MinBlocks) {
5537e5dd7070Spatrick CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks);
5538e5dd7070Spatrick MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0);
5539e5dd7070Spatrick if (MaxThreads == nullptr)
5540e5dd7070Spatrick return;
5541e5dd7070Spatrick
5542e5dd7070Spatrick if (MinBlocks) {
5543e5dd7070Spatrick MinBlocks = makeLaunchBoundsArgExpr(*this, MinBlocks, TmpAttr, 1);
5544e5dd7070Spatrick if (MinBlocks == nullptr)
5545e5dd7070Spatrick return;
5546e5dd7070Spatrick }
5547e5dd7070Spatrick
5548e5dd7070Spatrick D->addAttr(::new (Context)
5549e5dd7070Spatrick CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks));
5550e5dd7070Spatrick }
5551e5dd7070Spatrick
handleLaunchBoundsAttr(Sema & S,Decl * D,const ParsedAttr & AL)5552e5dd7070Spatrick static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5553a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
5554e5dd7070Spatrick return;
5555e5dd7070Spatrick
5556e5dd7070Spatrick S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0),
5557e5dd7070Spatrick AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr);
5558e5dd7070Spatrick }
5559e5dd7070Spatrick
handleArgumentWithTypeTagAttr(Sema & S,Decl * D,const ParsedAttr & AL)5560e5dd7070Spatrick static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
5561e5dd7070Spatrick const ParsedAttr &AL) {
5562e5dd7070Spatrick if (!AL.isArgIdent(0)) {
5563e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
5564e5dd7070Spatrick << AL << /* arg num = */ 1 << AANT_ArgumentIdentifier;
5565e5dd7070Spatrick return;
5566e5dd7070Spatrick }
5567e5dd7070Spatrick
5568e5dd7070Spatrick ParamIdx ArgumentIdx;
5569e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1),
5570e5dd7070Spatrick ArgumentIdx))
5571e5dd7070Spatrick return;
5572e5dd7070Spatrick
5573e5dd7070Spatrick ParamIdx TypeTagIdx;
5574e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2),
5575e5dd7070Spatrick TypeTagIdx))
5576e5dd7070Spatrick return;
5577e5dd7070Spatrick
5578e5dd7070Spatrick bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag";
5579e5dd7070Spatrick if (IsPointer) {
5580e5dd7070Spatrick // Ensure that buffer has a pointer type.
5581e5dd7070Spatrick unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex();
5582e5dd7070Spatrick if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) ||
5583e5dd7070Spatrick !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType())
5584e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) << AL << 0;
5585e5dd7070Spatrick }
5586e5dd7070Spatrick
5587e5dd7070Spatrick D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(
5588e5dd7070Spatrick S.Context, AL, AL.getArgAsIdent(0)->Ident, ArgumentIdx, TypeTagIdx,
5589e5dd7070Spatrick IsPointer));
5590e5dd7070Spatrick }
5591e5dd7070Spatrick
handleTypeTagForDatatypeAttr(Sema & S,Decl * D,const ParsedAttr & AL)5592e5dd7070Spatrick static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
5593e5dd7070Spatrick const ParsedAttr &AL) {
5594e5dd7070Spatrick if (!AL.isArgIdent(0)) {
5595e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
5596e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
5597e5dd7070Spatrick return;
5598e5dd7070Spatrick }
5599e5dd7070Spatrick
5600a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
5601e5dd7070Spatrick return;
5602e5dd7070Spatrick
5603e5dd7070Spatrick if (!isa<VarDecl>(D)) {
5604e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type)
5605e5dd7070Spatrick << AL << ExpectedVariable;
5606e5dd7070Spatrick return;
5607e5dd7070Spatrick }
5608e5dd7070Spatrick
5609e5dd7070Spatrick IdentifierInfo *PointerKind = AL.getArgAsIdent(0)->Ident;
5610e5dd7070Spatrick TypeSourceInfo *MatchingCTypeLoc = nullptr;
5611e5dd7070Spatrick S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc);
5612e5dd7070Spatrick assert(MatchingCTypeLoc && "no type source info for attribute argument");
5613e5dd7070Spatrick
5614e5dd7070Spatrick D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
5615e5dd7070Spatrick S.Context, AL, PointerKind, MatchingCTypeLoc, AL.getLayoutCompatible(),
5616e5dd7070Spatrick AL.getMustBeNull()));
5617e5dd7070Spatrick }
5618e5dd7070Spatrick
handleXRayLogArgsAttr(Sema & S,Decl * D,const ParsedAttr & AL)5619e5dd7070Spatrick static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5620e5dd7070Spatrick ParamIdx ArgCount;
5621e5dd7070Spatrick
5622e5dd7070Spatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0),
5623e5dd7070Spatrick ArgCount,
5624e5dd7070Spatrick true /* CanIndexImplicitThis */))
5625e5dd7070Spatrick return;
5626e5dd7070Spatrick
5627e5dd7070Spatrick // ArgCount isn't a parameter index [0;n), it's a count [1;n]
5628e5dd7070Spatrick D->addAttr(::new (S.Context)
5629e5dd7070Spatrick XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
5630e5dd7070Spatrick }
5631e5dd7070Spatrick
handlePatchableFunctionEntryAttr(Sema & S,Decl * D,const ParsedAttr & AL)5632e5dd7070Spatrick static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
5633e5dd7070Spatrick const ParsedAttr &AL) {
5634e5dd7070Spatrick uint32_t Count = 0, Offset = 0;
5635e5dd7070Spatrick if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true))
5636e5dd7070Spatrick return;
5637e5dd7070Spatrick if (AL.getNumArgs() == 2) {
5638e5dd7070Spatrick Expr *Arg = AL.getArgAsExpr(1);
5639e5dd7070Spatrick if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
5640e5dd7070Spatrick return;
5641e5dd7070Spatrick if (Count < Offset) {
5642e5dd7070Spatrick S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
5643e5dd7070Spatrick << &AL << 0 << Count << Arg->getBeginLoc();
5644e5dd7070Spatrick return;
5645e5dd7070Spatrick }
5646e5dd7070Spatrick }
5647e5dd7070Spatrick D->addAttr(::new (S.Context)
5648e5dd7070Spatrick PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
5649e5dd7070Spatrick }
5650e5dd7070Spatrick
5651ec727ea7Spatrick namespace {
5652ec727ea7Spatrick struct IntrinToName {
5653ec727ea7Spatrick uint32_t Id;
5654ec727ea7Spatrick int32_t FullName;
5655ec727ea7Spatrick int32_t ShortName;
5656ec727ea7Spatrick };
5657ec727ea7Spatrick } // unnamed namespace
5658ec727ea7Spatrick
ArmBuiltinAliasValid(unsigned BuiltinID,StringRef AliasName,ArrayRef<IntrinToName> Map,const char * IntrinNames)5659ec727ea7Spatrick static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
5660ec727ea7Spatrick ArrayRef<IntrinToName> Map,
5661ec727ea7Spatrick const char *IntrinNames) {
5662e5dd7070Spatrick if (AliasName.startswith("__arm_"))
5663e5dd7070Spatrick AliasName = AliasName.substr(6);
5664*7a9b00ceSrobert const IntrinToName *It =
5665*7a9b00ceSrobert llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
5666*7a9b00ceSrobert return L.Id < Id;
5667*7a9b00ceSrobert });
5668ec727ea7Spatrick if (It == Map.end() || It->Id != BuiltinID)
5669ec727ea7Spatrick return false;
5670ec727ea7Spatrick StringRef FullName(&IntrinNames[It->FullName]);
5671ec727ea7Spatrick if (AliasName == FullName)
5672ec727ea7Spatrick return true;
5673ec727ea7Spatrick if (It->ShortName == -1)
5674ec727ea7Spatrick return false;
5675ec727ea7Spatrick StringRef ShortName(&IntrinNames[It->ShortName]);
5676ec727ea7Spatrick return AliasName == ShortName;
5677ec727ea7Spatrick }
5678ec727ea7Spatrick
ArmMveAliasValid(unsigned BuiltinID,StringRef AliasName)5679ec727ea7Spatrick static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
5680e5dd7070Spatrick #include "clang/Basic/arm_mve_builtin_aliases.inc"
5681ec727ea7Spatrick // The included file defines:
5682ec727ea7Spatrick // - ArrayRef<IntrinToName> Map
5683ec727ea7Spatrick // - const char IntrinNames[]
5684ec727ea7Spatrick return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
5685ec727ea7Spatrick }
5686ec727ea7Spatrick
ArmCdeAliasValid(unsigned BuiltinID,StringRef AliasName)5687ec727ea7Spatrick static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
5688ec727ea7Spatrick #include "clang/Basic/arm_cde_builtin_aliases.inc"
5689ec727ea7Spatrick return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
5690ec727ea7Spatrick }
5691ec727ea7Spatrick
ArmSveAliasValid(ASTContext & Context,unsigned BuiltinID,StringRef AliasName)5692a0747c9fSpatrick static bool ArmSveAliasValid(ASTContext &Context, unsigned BuiltinID,
5693a0747c9fSpatrick StringRef AliasName) {
5694a0747c9fSpatrick if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID))
5695a0747c9fSpatrick BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID);
5696a0747c9fSpatrick return BuiltinID >= AArch64::FirstSVEBuiltin &&
5697a0747c9fSpatrick BuiltinID <= AArch64::LastSVEBuiltin;
5698e5dd7070Spatrick }
5699e5dd7070Spatrick
handleArmBuiltinAliasAttr(Sema & S,Decl * D,const ParsedAttr & AL)5700ec727ea7Spatrick static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5701e5dd7070Spatrick if (!AL.isArgIdent(0)) {
5702e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
5703e5dd7070Spatrick << AL << 1 << AANT_ArgumentIdentifier;
5704e5dd7070Spatrick return;
5705e5dd7070Spatrick }
5706e5dd7070Spatrick
5707e5dd7070Spatrick IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
5708e5dd7070Spatrick unsigned BuiltinID = Ident->getBuiltinID();
5709ec727ea7Spatrick StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
5710e5dd7070Spatrick
5711ec727ea7Spatrick bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
5712a0747c9fSpatrick if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) ||
5713ec727ea7Spatrick (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) &&
5714ec727ea7Spatrick !ArmCdeAliasValid(BuiltinID, AliasName))) {
5715ec727ea7Spatrick S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
5716e5dd7070Spatrick return;
5717e5dd7070Spatrick }
5718e5dd7070Spatrick
5719ec727ea7Spatrick D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident));
5720e5dd7070Spatrick }
5721e5dd7070Spatrick
RISCVAliasValid(unsigned BuiltinID,StringRef AliasName)5722a0747c9fSpatrick static bool RISCVAliasValid(unsigned BuiltinID, StringRef AliasName) {
5723*7a9b00ceSrobert return BuiltinID >= RISCV::FirstRVVBuiltin &&
5724*7a9b00ceSrobert BuiltinID <= RISCV::LastRVVBuiltin;
5725a0747c9fSpatrick }
5726a0747c9fSpatrick
handleBuiltinAliasAttr(Sema & S,Decl * D,const ParsedAttr & AL)5727a0747c9fSpatrick static void handleBuiltinAliasAttr(Sema &S, Decl *D,
5728a0747c9fSpatrick const ParsedAttr &AL) {
5729a0747c9fSpatrick if (!AL.isArgIdent(0)) {
5730a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
5731a0747c9fSpatrick << AL << 1 << AANT_ArgumentIdentifier;
5732a0747c9fSpatrick return;
5733a0747c9fSpatrick }
5734a0747c9fSpatrick
5735a0747c9fSpatrick IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
5736a0747c9fSpatrick unsigned BuiltinID = Ident->getBuiltinID();
5737a0747c9fSpatrick StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
5738a0747c9fSpatrick
5739a0747c9fSpatrick bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
5740a0747c9fSpatrick bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
5741a0747c9fSpatrick bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
5742*7a9b00ceSrobert bool IsHLSL = S.Context.getLangOpts().HLSL;
5743a0747c9fSpatrick if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) ||
5744a0747c9fSpatrick (IsARM && !ArmMveAliasValid(BuiltinID, AliasName) &&
5745a0747c9fSpatrick !ArmCdeAliasValid(BuiltinID, AliasName)) ||
5746a0747c9fSpatrick (IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) ||
5747*7a9b00ceSrobert (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) {
5748a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
5749a0747c9fSpatrick return;
5750a0747c9fSpatrick }
5751a0747c9fSpatrick
5752a0747c9fSpatrick D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
5753a0747c9fSpatrick }
5754a0747c9fSpatrick
5755e5dd7070Spatrick //===----------------------------------------------------------------------===//
5756e5dd7070Spatrick // Checker-specific attribute handlers.
5757e5dd7070Spatrick //===----------------------------------------------------------------------===//
isValidSubjectOfNSReturnsRetainedAttribute(QualType QT)5758e5dd7070Spatrick static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) {
5759e5dd7070Spatrick return QT->isDependentType() || QT->isObjCRetainableType();
5760e5dd7070Spatrick }
5761e5dd7070Spatrick
isValidSubjectOfNSAttribute(QualType QT)5762e5dd7070Spatrick static bool isValidSubjectOfNSAttribute(QualType QT) {
5763e5dd7070Spatrick return QT->isDependentType() || QT->isObjCObjectPointerType() ||
5764e5dd7070Spatrick QT->isObjCNSObjectType();
5765e5dd7070Spatrick }
5766e5dd7070Spatrick
isValidSubjectOfCFAttribute(QualType QT)5767e5dd7070Spatrick static bool isValidSubjectOfCFAttribute(QualType QT) {
5768e5dd7070Spatrick return QT->isDependentType() || QT->isPointerType() ||
5769e5dd7070Spatrick isValidSubjectOfNSAttribute(QT);
5770e5dd7070Spatrick }
5771e5dd7070Spatrick
isValidSubjectOfOSAttribute(QualType QT)5772e5dd7070Spatrick static bool isValidSubjectOfOSAttribute(QualType QT) {
5773e5dd7070Spatrick if (QT->isDependentType())
5774e5dd7070Spatrick return true;
5775e5dd7070Spatrick QualType PT = QT->getPointeeType();
5776e5dd7070Spatrick return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr;
5777e5dd7070Spatrick }
5778e5dd7070Spatrick
AddXConsumedAttr(Decl * D,const AttributeCommonInfo & CI,RetainOwnershipKind K,bool IsTemplateInstantiation)5779e5dd7070Spatrick void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
5780e5dd7070Spatrick RetainOwnershipKind K,
5781e5dd7070Spatrick bool IsTemplateInstantiation) {
5782e5dd7070Spatrick ValueDecl *VD = cast<ValueDecl>(D);
5783e5dd7070Spatrick switch (K) {
5784e5dd7070Spatrick case RetainOwnershipKind::OS:
5785e5dd7070Spatrick handleSimpleAttributeOrDiagnose<OSConsumedAttr>(
5786e5dd7070Spatrick *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()),
5787e5dd7070Spatrick diag::warn_ns_attribute_wrong_parameter_type,
5788e5dd7070Spatrick /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1);
5789e5dd7070Spatrick return;
5790e5dd7070Spatrick case RetainOwnershipKind::NS:
5791e5dd7070Spatrick handleSimpleAttributeOrDiagnose<NSConsumedAttr>(
5792e5dd7070Spatrick *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()),
5793e5dd7070Spatrick
5794e5dd7070Spatrick // These attributes are normally just advisory, but in ARC, ns_consumed
5795e5dd7070Spatrick // is significant. Allow non-dependent code to contain inappropriate
5796e5dd7070Spatrick // attributes even in ARC, but require template instantiations to be
5797e5dd7070Spatrick // set up correctly.
5798e5dd7070Spatrick ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount)
5799e5dd7070Spatrick ? diag::err_ns_attribute_wrong_parameter_type
5800e5dd7070Spatrick : diag::warn_ns_attribute_wrong_parameter_type),
5801e5dd7070Spatrick /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0);
5802e5dd7070Spatrick return;
5803e5dd7070Spatrick case RetainOwnershipKind::CF:
5804e5dd7070Spatrick handleSimpleAttributeOrDiagnose<CFConsumedAttr>(
5805e5dd7070Spatrick *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()),
5806e5dd7070Spatrick diag::warn_ns_attribute_wrong_parameter_type,
5807e5dd7070Spatrick /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1);
5808e5dd7070Spatrick return;
5809e5dd7070Spatrick }
5810e5dd7070Spatrick }
5811e5dd7070Spatrick
5812e5dd7070Spatrick static Sema::RetainOwnershipKind
parsedAttrToRetainOwnershipKind(const ParsedAttr & AL)5813e5dd7070Spatrick parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) {
5814e5dd7070Spatrick switch (AL.getKind()) {
5815e5dd7070Spatrick case ParsedAttr::AT_CFConsumed:
5816e5dd7070Spatrick case ParsedAttr::AT_CFReturnsRetained:
5817e5dd7070Spatrick case ParsedAttr::AT_CFReturnsNotRetained:
5818e5dd7070Spatrick return Sema::RetainOwnershipKind::CF;
5819e5dd7070Spatrick case ParsedAttr::AT_OSConsumesThis:
5820e5dd7070Spatrick case ParsedAttr::AT_OSConsumed:
5821e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetained:
5822e5dd7070Spatrick case ParsedAttr::AT_OSReturnsNotRetained:
5823e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetainedOnZero:
5824e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
5825e5dd7070Spatrick return Sema::RetainOwnershipKind::OS;
5826e5dd7070Spatrick case ParsedAttr::AT_NSConsumesSelf:
5827e5dd7070Spatrick case ParsedAttr::AT_NSConsumed:
5828e5dd7070Spatrick case ParsedAttr::AT_NSReturnsRetained:
5829e5dd7070Spatrick case ParsedAttr::AT_NSReturnsNotRetained:
5830e5dd7070Spatrick case ParsedAttr::AT_NSReturnsAutoreleased:
5831e5dd7070Spatrick return Sema::RetainOwnershipKind::NS;
5832e5dd7070Spatrick default:
5833e5dd7070Spatrick llvm_unreachable("Wrong argument supplied");
5834e5dd7070Spatrick }
5835e5dd7070Spatrick }
5836e5dd7070Spatrick
checkNSReturnsRetainedReturnType(SourceLocation Loc,QualType QT)5837e5dd7070Spatrick bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) {
5838e5dd7070Spatrick if (isValidSubjectOfNSReturnsRetainedAttribute(QT))
5839e5dd7070Spatrick return false;
5840e5dd7070Spatrick
5841e5dd7070Spatrick Diag(Loc, diag::warn_ns_attribute_wrong_return_type)
5842e5dd7070Spatrick << "'ns_returns_retained'" << 0 << 0;
5843e5dd7070Spatrick return true;
5844e5dd7070Spatrick }
5845e5dd7070Spatrick
5846e5dd7070Spatrick /// \return whether the parameter is a pointer to OSObject pointer.
isValidOSObjectOutParameter(const Decl * D)5847e5dd7070Spatrick static bool isValidOSObjectOutParameter(const Decl *D) {
5848e5dd7070Spatrick const auto *PVD = dyn_cast<ParmVarDecl>(D);
5849e5dd7070Spatrick if (!PVD)
5850e5dd7070Spatrick return false;
5851e5dd7070Spatrick QualType QT = PVD->getType();
5852e5dd7070Spatrick QualType PT = QT->getPointeeType();
5853e5dd7070Spatrick return !PT.isNull() && isValidSubjectOfOSAttribute(PT);
5854e5dd7070Spatrick }
5855e5dd7070Spatrick
handleXReturnsXRetainedAttr(Sema & S,Decl * D,const ParsedAttr & AL)5856e5dd7070Spatrick static void handleXReturnsXRetainedAttr(Sema &S, Decl *D,
5857e5dd7070Spatrick const ParsedAttr &AL) {
5858e5dd7070Spatrick QualType ReturnType;
5859e5dd7070Spatrick Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL);
5860e5dd7070Spatrick
5861e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
5862e5dd7070Spatrick ReturnType = MD->getReturnType();
5863e5dd7070Spatrick } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
5864e5dd7070Spatrick (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) {
5865e5dd7070Spatrick return; // ignore: was handled as a type attribute
5866e5dd7070Spatrick } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
5867e5dd7070Spatrick ReturnType = PD->getType();
5868e5dd7070Spatrick } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
5869e5dd7070Spatrick ReturnType = FD->getReturnType();
5870e5dd7070Spatrick } else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) {
5871e5dd7070Spatrick // Attributes on parameters are used for out-parameters,
5872e5dd7070Spatrick // passed as pointers-to-pointers.
5873e5dd7070Spatrick unsigned DiagID = K == Sema::RetainOwnershipKind::CF
5874e5dd7070Spatrick ? /*pointer-to-CF-pointer*/2
5875e5dd7070Spatrick : /*pointer-to-OSObject-pointer*/3;
5876e5dd7070Spatrick ReturnType = Param->getType()->getPointeeType();
5877e5dd7070Spatrick if (ReturnType.isNull()) {
5878e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
5879e5dd7070Spatrick << AL << DiagID << AL.getRange();
5880e5dd7070Spatrick return;
5881e5dd7070Spatrick }
5882e5dd7070Spatrick } else if (AL.isUsedAsTypeAttr()) {
5883e5dd7070Spatrick return;
5884e5dd7070Spatrick } else {
5885e5dd7070Spatrick AttributeDeclKind ExpectedDeclKind;
5886e5dd7070Spatrick switch (AL.getKind()) {
5887e5dd7070Spatrick default: llvm_unreachable("invalid ownership attribute");
5888e5dd7070Spatrick case ParsedAttr::AT_NSReturnsRetained:
5889e5dd7070Spatrick case ParsedAttr::AT_NSReturnsAutoreleased:
5890e5dd7070Spatrick case ParsedAttr::AT_NSReturnsNotRetained:
5891e5dd7070Spatrick ExpectedDeclKind = ExpectedFunctionOrMethod;
5892e5dd7070Spatrick break;
5893e5dd7070Spatrick
5894e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetained:
5895e5dd7070Spatrick case ParsedAttr::AT_OSReturnsNotRetained:
5896e5dd7070Spatrick case ParsedAttr::AT_CFReturnsRetained:
5897e5dd7070Spatrick case ParsedAttr::AT_CFReturnsNotRetained:
5898e5dd7070Spatrick ExpectedDeclKind = ExpectedFunctionMethodOrParameter;
5899e5dd7070Spatrick break;
5900e5dd7070Spatrick }
5901e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type)
5902e5dd7070Spatrick << AL.getRange() << AL << ExpectedDeclKind;
5903e5dd7070Spatrick return;
5904e5dd7070Spatrick }
5905e5dd7070Spatrick
5906e5dd7070Spatrick bool TypeOK;
5907e5dd7070Spatrick bool Cf;
5908e5dd7070Spatrick unsigned ParmDiagID = 2; // Pointer-to-CF-pointer
5909e5dd7070Spatrick switch (AL.getKind()) {
5910e5dd7070Spatrick default: llvm_unreachable("invalid ownership attribute");
5911e5dd7070Spatrick case ParsedAttr::AT_NSReturnsRetained:
5912e5dd7070Spatrick TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType);
5913e5dd7070Spatrick Cf = false;
5914e5dd7070Spatrick break;
5915e5dd7070Spatrick
5916e5dd7070Spatrick case ParsedAttr::AT_NSReturnsAutoreleased:
5917e5dd7070Spatrick case ParsedAttr::AT_NSReturnsNotRetained:
5918e5dd7070Spatrick TypeOK = isValidSubjectOfNSAttribute(ReturnType);
5919e5dd7070Spatrick Cf = false;
5920e5dd7070Spatrick break;
5921e5dd7070Spatrick
5922e5dd7070Spatrick case ParsedAttr::AT_CFReturnsRetained:
5923e5dd7070Spatrick case ParsedAttr::AT_CFReturnsNotRetained:
5924e5dd7070Spatrick TypeOK = isValidSubjectOfCFAttribute(ReturnType);
5925e5dd7070Spatrick Cf = true;
5926e5dd7070Spatrick break;
5927e5dd7070Spatrick
5928e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetained:
5929e5dd7070Spatrick case ParsedAttr::AT_OSReturnsNotRetained:
5930e5dd7070Spatrick TypeOK = isValidSubjectOfOSAttribute(ReturnType);
5931e5dd7070Spatrick Cf = true;
5932e5dd7070Spatrick ParmDiagID = 3; // Pointer-to-OSObject-pointer
5933e5dd7070Spatrick break;
5934e5dd7070Spatrick }
5935e5dd7070Spatrick
5936e5dd7070Spatrick if (!TypeOK) {
5937e5dd7070Spatrick if (AL.isUsedAsTypeAttr())
5938e5dd7070Spatrick return;
5939e5dd7070Spatrick
5940e5dd7070Spatrick if (isa<ParmVarDecl>(D)) {
5941e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
5942e5dd7070Spatrick << AL << ParmDiagID << AL.getRange();
5943e5dd7070Spatrick } else {
5944e5dd7070Spatrick // Needs to be kept in sync with warn_ns_attribute_wrong_return_type.
5945e5dd7070Spatrick enum : unsigned {
5946e5dd7070Spatrick Function,
5947e5dd7070Spatrick Method,
5948e5dd7070Spatrick Property
5949e5dd7070Spatrick } SubjectKind = Function;
5950e5dd7070Spatrick if (isa<ObjCMethodDecl>(D))
5951e5dd7070Spatrick SubjectKind = Method;
5952e5dd7070Spatrick else if (isa<ObjCPropertyDecl>(D))
5953e5dd7070Spatrick SubjectKind = Property;
5954e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
5955e5dd7070Spatrick << AL << SubjectKind << Cf << AL.getRange();
5956e5dd7070Spatrick }
5957e5dd7070Spatrick return;
5958e5dd7070Spatrick }
5959e5dd7070Spatrick
5960e5dd7070Spatrick switch (AL.getKind()) {
5961e5dd7070Spatrick default:
5962e5dd7070Spatrick llvm_unreachable("invalid ownership attribute");
5963e5dd7070Spatrick case ParsedAttr::AT_NSReturnsAutoreleased:
5964e5dd7070Spatrick handleSimpleAttribute<NSReturnsAutoreleasedAttr>(S, D, AL);
5965e5dd7070Spatrick return;
5966e5dd7070Spatrick case ParsedAttr::AT_CFReturnsNotRetained:
5967e5dd7070Spatrick handleSimpleAttribute<CFReturnsNotRetainedAttr>(S, D, AL);
5968e5dd7070Spatrick return;
5969e5dd7070Spatrick case ParsedAttr::AT_NSReturnsNotRetained:
5970e5dd7070Spatrick handleSimpleAttribute<NSReturnsNotRetainedAttr>(S, D, AL);
5971e5dd7070Spatrick return;
5972e5dd7070Spatrick case ParsedAttr::AT_CFReturnsRetained:
5973e5dd7070Spatrick handleSimpleAttribute<CFReturnsRetainedAttr>(S, D, AL);
5974e5dd7070Spatrick return;
5975e5dd7070Spatrick case ParsedAttr::AT_NSReturnsRetained:
5976e5dd7070Spatrick handleSimpleAttribute<NSReturnsRetainedAttr>(S, D, AL);
5977e5dd7070Spatrick return;
5978e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetained:
5979e5dd7070Spatrick handleSimpleAttribute<OSReturnsRetainedAttr>(S, D, AL);
5980e5dd7070Spatrick return;
5981e5dd7070Spatrick case ParsedAttr::AT_OSReturnsNotRetained:
5982e5dd7070Spatrick handleSimpleAttribute<OSReturnsNotRetainedAttr>(S, D, AL);
5983e5dd7070Spatrick return;
5984e5dd7070Spatrick };
5985e5dd7070Spatrick }
5986e5dd7070Spatrick
handleObjCReturnsInnerPointerAttr(Sema & S,Decl * D,const ParsedAttr & Attrs)5987e5dd7070Spatrick static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
5988e5dd7070Spatrick const ParsedAttr &Attrs) {
5989e5dd7070Spatrick const int EP_ObjCMethod = 1;
5990e5dd7070Spatrick const int EP_ObjCProperty = 2;
5991e5dd7070Spatrick
5992e5dd7070Spatrick SourceLocation loc = Attrs.getLoc();
5993e5dd7070Spatrick QualType resultType;
5994e5dd7070Spatrick if (isa<ObjCMethodDecl>(D))
5995e5dd7070Spatrick resultType = cast<ObjCMethodDecl>(D)->getReturnType();
5996e5dd7070Spatrick else
5997e5dd7070Spatrick resultType = cast<ObjCPropertyDecl>(D)->getType();
5998e5dd7070Spatrick
5999e5dd7070Spatrick if (!resultType->isReferenceType() &&
6000e5dd7070Spatrick (!resultType->isPointerType() || resultType->isObjCRetainableType())) {
6001e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
6002e5dd7070Spatrick << SourceRange(loc) << Attrs
6003e5dd7070Spatrick << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
6004e5dd7070Spatrick << /*non-retainable pointer*/ 2;
6005e5dd7070Spatrick
6006e5dd7070Spatrick // Drop the attribute.
6007e5dd7070Spatrick return;
6008e5dd7070Spatrick }
6009e5dd7070Spatrick
6010e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs));
6011e5dd7070Spatrick }
6012e5dd7070Spatrick
handleObjCRequiresSuperAttr(Sema & S,Decl * D,const ParsedAttr & Attrs)6013e5dd7070Spatrick static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
6014e5dd7070Spatrick const ParsedAttr &Attrs) {
6015e5dd7070Spatrick const auto *Method = cast<ObjCMethodDecl>(D);
6016e5dd7070Spatrick
6017e5dd7070Spatrick const DeclContext *DC = Method->getDeclContext();
6018e5dd7070Spatrick if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
6019e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
6020e5dd7070Spatrick << 0;
6021e5dd7070Spatrick S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
6022e5dd7070Spatrick return;
6023e5dd7070Spatrick }
6024e5dd7070Spatrick if (Method->getMethodFamily() == OMF_dealloc) {
6025e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
6026e5dd7070Spatrick << 1;
6027e5dd7070Spatrick return;
6028e5dd7070Spatrick }
6029e5dd7070Spatrick
6030e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
6031e5dd7070Spatrick }
6032e5dd7070Spatrick
handleNSErrorDomain(Sema & S,Decl * D,const ParsedAttr & AL)6033a0747c9fSpatrick static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) {
6034a0747c9fSpatrick auto *E = AL.getArgAsExpr(0);
6035a0747c9fSpatrick auto Loc = E ? E->getBeginLoc() : AL.getLoc();
6036a0747c9fSpatrick
6037a0747c9fSpatrick auto *DRE = dyn_cast<DeclRefExpr>(AL.getArgAsExpr(0));
6038a0747c9fSpatrick if (!DRE) {
6039a0747c9fSpatrick S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0;
6040a0747c9fSpatrick return;
6041a0747c9fSpatrick }
6042a0747c9fSpatrick
6043a0747c9fSpatrick auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
6044a0747c9fSpatrick if (!VD) {
6045a0747c9fSpatrick S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl();
6046a0747c9fSpatrick return;
6047a0747c9fSpatrick }
6048a0747c9fSpatrick
6049a0747c9fSpatrick if (!isNSStringType(VD->getType(), S.Context) &&
6050a0747c9fSpatrick !isCFStringType(VD->getType(), S.Context)) {
6051a0747c9fSpatrick S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD;
6052a0747c9fSpatrick return;
6053a0747c9fSpatrick }
6054a0747c9fSpatrick
6055a0747c9fSpatrick D->addAttr(::new (S.Context) NSErrorDomainAttr(S.Context, AL, VD));
6056a0747c9fSpatrick }
6057a0747c9fSpatrick
handleObjCBridgeAttr(Sema & S,Decl * D,const ParsedAttr & AL)6058e5dd7070Spatrick static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6059e5dd7070Spatrick IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
6060e5dd7070Spatrick
6061e5dd7070Spatrick if (!Parm) {
6062e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
6063e5dd7070Spatrick return;
6064e5dd7070Spatrick }
6065e5dd7070Spatrick
6066e5dd7070Spatrick // Typedefs only allow objc_bridge(id) and have some additional checking.
6067e5dd7070Spatrick if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
6068e5dd7070Spatrick if (!Parm->Ident->isStr("id")) {
6069e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL;
6070e5dd7070Spatrick return;
6071e5dd7070Spatrick }
6072e5dd7070Spatrick
6073e5dd7070Spatrick // Only allow 'cv void *'.
6074e5dd7070Spatrick QualType T = TD->getUnderlyingType();
6075e5dd7070Spatrick if (!T->isVoidPointerType()) {
6076e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer);
6077e5dd7070Spatrick return;
6078e5dd7070Spatrick }
6079e5dd7070Spatrick }
6080e5dd7070Spatrick
6081e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident));
6082e5dd7070Spatrick }
6083e5dd7070Spatrick
handleObjCBridgeMutableAttr(Sema & S,Decl * D,const ParsedAttr & AL)6084e5dd7070Spatrick static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
6085e5dd7070Spatrick const ParsedAttr &AL) {
6086e5dd7070Spatrick IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
6087e5dd7070Spatrick
6088e5dd7070Spatrick if (!Parm) {
6089e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
6090e5dd7070Spatrick return;
6091e5dd7070Spatrick }
6092e5dd7070Spatrick
6093e5dd7070Spatrick D->addAttr(::new (S.Context)
6094e5dd7070Spatrick ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident));
6095e5dd7070Spatrick }
6096e5dd7070Spatrick
handleObjCBridgeRelatedAttr(Sema & S,Decl * D,const ParsedAttr & AL)6097e5dd7070Spatrick static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
6098e5dd7070Spatrick const ParsedAttr &AL) {
6099e5dd7070Spatrick IdentifierInfo *RelatedClass =
6100e5dd7070Spatrick AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr;
6101e5dd7070Spatrick if (!RelatedClass) {
6102e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
6103e5dd7070Spatrick return;
6104e5dd7070Spatrick }
6105e5dd7070Spatrick IdentifierInfo *ClassMethod =
6106e5dd7070Spatrick AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr;
6107e5dd7070Spatrick IdentifierInfo *InstanceMethod =
6108e5dd7070Spatrick AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr;
6109e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr(
6110e5dd7070Spatrick S.Context, AL, RelatedClass, ClassMethod, InstanceMethod));
6111e5dd7070Spatrick }
6112e5dd7070Spatrick
handleObjCDesignatedInitializer(Sema & S,Decl * D,const ParsedAttr & AL)6113e5dd7070Spatrick static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
6114e5dd7070Spatrick const ParsedAttr &AL) {
6115e5dd7070Spatrick DeclContext *Ctx = D->getDeclContext();
6116e5dd7070Spatrick
6117e5dd7070Spatrick // This attribute can only be applied to methods in interfaces or class
6118e5dd7070Spatrick // extensions.
6119e5dd7070Spatrick if (!isa<ObjCInterfaceDecl>(Ctx) &&
6120e5dd7070Spatrick !(isa<ObjCCategoryDecl>(Ctx) &&
6121e5dd7070Spatrick cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) {
6122e5dd7070Spatrick S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
6123e5dd7070Spatrick return;
6124e5dd7070Spatrick }
6125e5dd7070Spatrick
6126e5dd7070Spatrick ObjCInterfaceDecl *IFace;
6127e5dd7070Spatrick if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx))
6128e5dd7070Spatrick IFace = CatDecl->getClassInterface();
6129e5dd7070Spatrick else
6130e5dd7070Spatrick IFace = cast<ObjCInterfaceDecl>(Ctx);
6131e5dd7070Spatrick
6132e5dd7070Spatrick if (!IFace)
6133e5dd7070Spatrick return;
6134e5dd7070Spatrick
6135e5dd7070Spatrick IFace->setHasDesignatedInitializers();
6136e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL));
6137e5dd7070Spatrick }
6138e5dd7070Spatrick
handleObjCRuntimeName(Sema & S,Decl * D,const ParsedAttr & AL)6139e5dd7070Spatrick static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
6140e5dd7070Spatrick StringRef MetaDataName;
6141e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
6142e5dd7070Spatrick return;
6143e5dd7070Spatrick D->addAttr(::new (S.Context)
6144e5dd7070Spatrick ObjCRuntimeNameAttr(S.Context, AL, MetaDataName));
6145e5dd7070Spatrick }
6146e5dd7070Spatrick
6147e5dd7070Spatrick // When a user wants to use objc_boxable with a union or struct
6148e5dd7070Spatrick // but they don't have access to the declaration (legacy/third-party code)
6149e5dd7070Spatrick // then they can 'enable' this feature with a typedef:
6150e5dd7070Spatrick // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct;
handleObjCBoxable(Sema & S,Decl * D,const ParsedAttr & AL)6151e5dd7070Spatrick static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) {
6152e5dd7070Spatrick bool notify = false;
6153e5dd7070Spatrick
6154e5dd7070Spatrick auto *RD = dyn_cast<RecordDecl>(D);
6155e5dd7070Spatrick if (RD && RD->getDefinition()) {
6156e5dd7070Spatrick RD = RD->getDefinition();
6157e5dd7070Spatrick notify = true;
6158e5dd7070Spatrick }
6159e5dd7070Spatrick
6160e5dd7070Spatrick if (RD) {
6161e5dd7070Spatrick ObjCBoxableAttr *BoxableAttr =
6162e5dd7070Spatrick ::new (S.Context) ObjCBoxableAttr(S.Context, AL);
6163e5dd7070Spatrick RD->addAttr(BoxableAttr);
6164e5dd7070Spatrick if (notify) {
6165e5dd7070Spatrick // we need to notify ASTReader/ASTWriter about
6166e5dd7070Spatrick // modification of existing declaration
6167e5dd7070Spatrick if (ASTMutationListener *L = S.getASTMutationListener())
6168e5dd7070Spatrick L->AddedAttributeToRecord(BoxableAttr, RD);
6169e5dd7070Spatrick }
6170e5dd7070Spatrick }
6171e5dd7070Spatrick }
6172e5dd7070Spatrick
handleObjCOwnershipAttr(Sema & S,Decl * D,const ParsedAttr & AL)6173e5dd7070Spatrick static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6174e5dd7070Spatrick if (hasDeclarator(D)) return;
6175e5dd7070Spatrick
6176e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type)
6177e5dd7070Spatrick << AL.getRange() << AL << ExpectedVariable;
6178e5dd7070Spatrick }
6179e5dd7070Spatrick
handleObjCPreciseLifetimeAttr(Sema & S,Decl * D,const ParsedAttr & AL)6180e5dd7070Spatrick static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
6181e5dd7070Spatrick const ParsedAttr &AL) {
6182e5dd7070Spatrick const auto *VD = cast<ValueDecl>(D);
6183e5dd7070Spatrick QualType QT = VD->getType();
6184e5dd7070Spatrick
6185e5dd7070Spatrick if (!QT->isDependentType() &&
6186e5dd7070Spatrick !QT->isObjCLifetimeType()) {
6187e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type)
6188e5dd7070Spatrick << QT;
6189e5dd7070Spatrick return;
6190e5dd7070Spatrick }
6191e5dd7070Spatrick
6192e5dd7070Spatrick Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime();
6193e5dd7070Spatrick
6194e5dd7070Spatrick // If we have no lifetime yet, check the lifetime we're presumably
6195e5dd7070Spatrick // going to infer.
6196e5dd7070Spatrick if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType())
6197e5dd7070Spatrick Lifetime = QT->getObjCARCImplicitLifetime();
6198e5dd7070Spatrick
6199e5dd7070Spatrick switch (Lifetime) {
6200e5dd7070Spatrick case Qualifiers::OCL_None:
6201e5dd7070Spatrick assert(QT->isDependentType() &&
6202e5dd7070Spatrick "didn't infer lifetime for non-dependent type?");
6203e5dd7070Spatrick break;
6204e5dd7070Spatrick
6205e5dd7070Spatrick case Qualifiers::OCL_Weak: // meaningful
6206e5dd7070Spatrick case Qualifiers::OCL_Strong: // meaningful
6207e5dd7070Spatrick break;
6208e5dd7070Spatrick
6209e5dd7070Spatrick case Qualifiers::OCL_ExplicitNone:
6210e5dd7070Spatrick case Qualifiers::OCL_Autoreleasing:
6211e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
6212e5dd7070Spatrick << (Lifetime == Qualifiers::OCL_Autoreleasing);
6213e5dd7070Spatrick break;
6214e5dd7070Spatrick }
6215e5dd7070Spatrick
6216e5dd7070Spatrick D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL));
6217e5dd7070Spatrick }
6218e5dd7070Spatrick
handleSwiftAttrAttr(Sema & S,Decl * D,const ParsedAttr & AL)6219a0747c9fSpatrick static void handleSwiftAttrAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6220a0747c9fSpatrick // Make sure that there is a string literal as the annotation's single
6221a0747c9fSpatrick // argument.
6222a0747c9fSpatrick StringRef Str;
6223a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
6224a0747c9fSpatrick return;
6225a0747c9fSpatrick
6226a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftAttrAttr(S.Context, AL, Str));
6227a0747c9fSpatrick }
6228a0747c9fSpatrick
handleSwiftBridge(Sema & S,Decl * D,const ParsedAttr & AL)6229a0747c9fSpatrick static void handleSwiftBridge(Sema &S, Decl *D, const ParsedAttr &AL) {
6230a0747c9fSpatrick // Make sure that there is a string literal as the annotation's single
6231a0747c9fSpatrick // argument.
6232a0747c9fSpatrick StringRef BT;
6233a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, BT))
6234a0747c9fSpatrick return;
6235a0747c9fSpatrick
6236a0747c9fSpatrick // Warn about duplicate attributes if they have different arguments, but drop
6237a0747c9fSpatrick // any duplicate attributes regardless.
6238a0747c9fSpatrick if (const auto *Other = D->getAttr<SwiftBridgeAttr>()) {
6239a0747c9fSpatrick if (Other->getSwiftType() != BT)
6240a0747c9fSpatrick S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
6241a0747c9fSpatrick return;
6242a0747c9fSpatrick }
6243a0747c9fSpatrick
6244a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftBridgeAttr(S.Context, AL, BT));
6245a0747c9fSpatrick }
6246a0747c9fSpatrick
isErrorParameter(Sema & S,QualType QT)6247a0747c9fSpatrick static bool isErrorParameter(Sema &S, QualType QT) {
6248a0747c9fSpatrick const auto *PT = QT->getAs<PointerType>();
6249a0747c9fSpatrick if (!PT)
6250a0747c9fSpatrick return false;
6251a0747c9fSpatrick
6252a0747c9fSpatrick QualType Pointee = PT->getPointeeType();
6253a0747c9fSpatrick
6254a0747c9fSpatrick // Check for NSError**.
6255a0747c9fSpatrick if (const auto *OPT = Pointee->getAs<ObjCObjectPointerType>())
6256a0747c9fSpatrick if (const auto *ID = OPT->getInterfaceDecl())
6257a0747c9fSpatrick if (ID->getIdentifier() == S.getNSErrorIdent())
6258a0747c9fSpatrick return true;
6259a0747c9fSpatrick
6260a0747c9fSpatrick // Check for CFError**.
6261a0747c9fSpatrick if (const auto *PT = Pointee->getAs<PointerType>())
6262a0747c9fSpatrick if (const auto *RT = PT->getPointeeType()->getAs<RecordType>())
6263a0747c9fSpatrick if (S.isCFError(RT->getDecl()))
6264a0747c9fSpatrick return true;
6265a0747c9fSpatrick
6266a0747c9fSpatrick return false;
6267a0747c9fSpatrick }
6268a0747c9fSpatrick
handleSwiftError(Sema & S,Decl * D,const ParsedAttr & AL)6269a0747c9fSpatrick static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) {
6270a0747c9fSpatrick auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
6271a0747c9fSpatrick for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) {
6272a0747c9fSpatrick if (isErrorParameter(S, getFunctionOrMethodParamType(D, I)))
6273a0747c9fSpatrick return true;
6274a0747c9fSpatrick }
6275a0747c9fSpatrick
6276a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter)
6277a0747c9fSpatrick << AL << isa<ObjCMethodDecl>(D);
6278a0747c9fSpatrick return false;
6279a0747c9fSpatrick };
6280a0747c9fSpatrick
6281a0747c9fSpatrick auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
6282a0747c9fSpatrick // - C, ObjC, and block pointers are definitely okay.
6283a0747c9fSpatrick // - References are definitely not okay.
6284a0747c9fSpatrick // - nullptr_t is weird, but acceptable.
6285a0747c9fSpatrick QualType RT = getFunctionOrMethodResultType(D);
6286a0747c9fSpatrick if (RT->hasPointerRepresentation() && !RT->isReferenceType())
6287a0747c9fSpatrick return true;
6288a0747c9fSpatrick
6289a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type)
6290a0747c9fSpatrick << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D)
6291a0747c9fSpatrick << /*pointer*/ 1;
6292a0747c9fSpatrick return false;
6293a0747c9fSpatrick };
6294a0747c9fSpatrick
6295a0747c9fSpatrick auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
6296a0747c9fSpatrick QualType RT = getFunctionOrMethodResultType(D);
6297a0747c9fSpatrick if (RT->isIntegralType(S.Context))
6298a0747c9fSpatrick return true;
6299a0747c9fSpatrick
6300a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type)
6301a0747c9fSpatrick << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D)
6302a0747c9fSpatrick << /*integral*/ 0;
6303a0747c9fSpatrick return false;
6304a0747c9fSpatrick };
6305a0747c9fSpatrick
6306a0747c9fSpatrick if (D->isInvalidDecl())
6307a0747c9fSpatrick return;
6308a0747c9fSpatrick
6309a0747c9fSpatrick IdentifierLoc *Loc = AL.getArgAsIdent(0);
6310a0747c9fSpatrick SwiftErrorAttr::ConventionKind Convention;
6311a0747c9fSpatrick if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(),
6312a0747c9fSpatrick Convention)) {
6313a0747c9fSpatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
6314a0747c9fSpatrick << AL << Loc->Ident;
6315a0747c9fSpatrick return;
6316a0747c9fSpatrick }
6317a0747c9fSpatrick
6318a0747c9fSpatrick switch (Convention) {
6319a0747c9fSpatrick case SwiftErrorAttr::None:
6320a0747c9fSpatrick // No additional validation required.
6321a0747c9fSpatrick break;
6322a0747c9fSpatrick
6323a0747c9fSpatrick case SwiftErrorAttr::NonNullError:
6324a0747c9fSpatrick if (!hasErrorParameter(S, D, AL))
6325a0747c9fSpatrick return;
6326a0747c9fSpatrick break;
6327a0747c9fSpatrick
6328a0747c9fSpatrick case SwiftErrorAttr::NullResult:
6329a0747c9fSpatrick if (!hasErrorParameter(S, D, AL) || !hasPointerResult(S, D, AL))
6330a0747c9fSpatrick return;
6331a0747c9fSpatrick break;
6332a0747c9fSpatrick
6333a0747c9fSpatrick case SwiftErrorAttr::NonZeroResult:
6334a0747c9fSpatrick case SwiftErrorAttr::ZeroResult:
6335a0747c9fSpatrick if (!hasErrorParameter(S, D, AL) || !hasIntegerResult(S, D, AL))
6336a0747c9fSpatrick return;
6337a0747c9fSpatrick break;
6338a0747c9fSpatrick }
6339a0747c9fSpatrick
6340a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention));
6341a0747c9fSpatrick }
6342a0747c9fSpatrick
checkSwiftAsyncErrorBlock(Sema & S,Decl * D,const SwiftAsyncErrorAttr * ErrorAttr,const SwiftAsyncAttr * AsyncAttr)6343a0747c9fSpatrick static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D,
6344a0747c9fSpatrick const SwiftAsyncErrorAttr *ErrorAttr,
6345a0747c9fSpatrick const SwiftAsyncAttr *AsyncAttr) {
6346a0747c9fSpatrick if (AsyncAttr->getKind() == SwiftAsyncAttr::None) {
6347a0747c9fSpatrick if (ErrorAttr->getConvention() != SwiftAsyncErrorAttr::None) {
6348a0747c9fSpatrick S.Diag(AsyncAttr->getLocation(),
6349a0747c9fSpatrick diag::err_swift_async_error_without_swift_async)
6350a0747c9fSpatrick << AsyncAttr << isa<ObjCMethodDecl>(D);
6351a0747c9fSpatrick }
6352a0747c9fSpatrick return;
6353a0747c9fSpatrick }
6354a0747c9fSpatrick
6355a0747c9fSpatrick const ParmVarDecl *HandlerParam = getFunctionOrMethodParam(
6356a0747c9fSpatrick D, AsyncAttr->getCompletionHandlerIndex().getASTIndex());
6357a0747c9fSpatrick // handleSwiftAsyncAttr already verified the type is correct, so no need to
6358a0747c9fSpatrick // double-check it here.
6359a0747c9fSpatrick const auto *FuncTy = HandlerParam->getType()
6360a0747c9fSpatrick ->castAs<BlockPointerType>()
6361a0747c9fSpatrick ->getPointeeType()
6362a0747c9fSpatrick ->getAs<FunctionProtoType>();
6363a0747c9fSpatrick ArrayRef<QualType> BlockParams;
6364a0747c9fSpatrick if (FuncTy)
6365a0747c9fSpatrick BlockParams = FuncTy->getParamTypes();
6366a0747c9fSpatrick
6367a0747c9fSpatrick switch (ErrorAttr->getConvention()) {
6368a0747c9fSpatrick case SwiftAsyncErrorAttr::ZeroArgument:
6369a0747c9fSpatrick case SwiftAsyncErrorAttr::NonZeroArgument: {
6370a0747c9fSpatrick uint32_t ParamIdx = ErrorAttr->getHandlerParamIdx();
6371a0747c9fSpatrick if (ParamIdx == 0 || ParamIdx > BlockParams.size()) {
6372a0747c9fSpatrick S.Diag(ErrorAttr->getLocation(),
6373a0747c9fSpatrick diag::err_attribute_argument_out_of_bounds) << ErrorAttr << 2;
6374a0747c9fSpatrick return;
6375a0747c9fSpatrick }
6376a0747c9fSpatrick QualType ErrorParam = BlockParams[ParamIdx - 1];
6377a0747c9fSpatrick if (!ErrorParam->isIntegralType(S.Context)) {
6378a0747c9fSpatrick StringRef ConvStr =
6379a0747c9fSpatrick ErrorAttr->getConvention() == SwiftAsyncErrorAttr::ZeroArgument
6380a0747c9fSpatrick ? "zero_argument"
6381a0747c9fSpatrick : "nonzero_argument";
6382a0747c9fSpatrick S.Diag(ErrorAttr->getLocation(), diag::err_swift_async_error_non_integral)
6383a0747c9fSpatrick << ErrorAttr << ConvStr << ParamIdx << ErrorParam;
6384a0747c9fSpatrick return;
6385a0747c9fSpatrick }
6386a0747c9fSpatrick break;
6387a0747c9fSpatrick }
6388a0747c9fSpatrick case SwiftAsyncErrorAttr::NonNullError: {
6389a0747c9fSpatrick bool AnyErrorParams = false;
6390a0747c9fSpatrick for (QualType Param : BlockParams) {
6391a0747c9fSpatrick // Check for NSError *.
6392a0747c9fSpatrick if (const auto *ObjCPtrTy = Param->getAs<ObjCObjectPointerType>()) {
6393a0747c9fSpatrick if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) {
6394a0747c9fSpatrick if (ID->getIdentifier() == S.getNSErrorIdent()) {
6395a0747c9fSpatrick AnyErrorParams = true;
6396a0747c9fSpatrick break;
6397a0747c9fSpatrick }
6398a0747c9fSpatrick }
6399a0747c9fSpatrick }
6400a0747c9fSpatrick // Check for CFError *.
6401a0747c9fSpatrick if (const auto *PtrTy = Param->getAs<PointerType>()) {
6402a0747c9fSpatrick if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) {
6403a0747c9fSpatrick if (S.isCFError(RT->getDecl())) {
6404a0747c9fSpatrick AnyErrorParams = true;
6405a0747c9fSpatrick break;
6406a0747c9fSpatrick }
6407a0747c9fSpatrick }
6408a0747c9fSpatrick }
6409a0747c9fSpatrick }
6410a0747c9fSpatrick
6411a0747c9fSpatrick if (!AnyErrorParams) {
6412a0747c9fSpatrick S.Diag(ErrorAttr->getLocation(),
6413a0747c9fSpatrick diag::err_swift_async_error_no_error_parameter)
6414a0747c9fSpatrick << ErrorAttr << isa<ObjCMethodDecl>(D);
6415a0747c9fSpatrick return;
6416a0747c9fSpatrick }
6417a0747c9fSpatrick break;
6418a0747c9fSpatrick }
6419a0747c9fSpatrick case SwiftAsyncErrorAttr::None:
6420a0747c9fSpatrick break;
6421a0747c9fSpatrick }
6422a0747c9fSpatrick }
6423a0747c9fSpatrick
handleSwiftAsyncError(Sema & S,Decl * D,const ParsedAttr & AL)6424a0747c9fSpatrick static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) {
6425a0747c9fSpatrick IdentifierLoc *IDLoc = AL.getArgAsIdent(0);
6426a0747c9fSpatrick SwiftAsyncErrorAttr::ConventionKind ConvKind;
6427a0747c9fSpatrick if (!SwiftAsyncErrorAttr::ConvertStrToConventionKind(IDLoc->Ident->getName(),
6428a0747c9fSpatrick ConvKind)) {
6429a0747c9fSpatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
6430a0747c9fSpatrick << AL << IDLoc->Ident;
6431a0747c9fSpatrick return;
6432a0747c9fSpatrick }
6433a0747c9fSpatrick
6434a0747c9fSpatrick uint32_t ParamIdx = 0;
6435a0747c9fSpatrick switch (ConvKind) {
6436a0747c9fSpatrick case SwiftAsyncErrorAttr::ZeroArgument:
6437a0747c9fSpatrick case SwiftAsyncErrorAttr::NonZeroArgument: {
6438a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 2))
6439a0747c9fSpatrick return;
6440a0747c9fSpatrick
6441a0747c9fSpatrick Expr *IdxExpr = AL.getArgAsExpr(1);
6442a0747c9fSpatrick if (!checkUInt32Argument(S, AL, IdxExpr, ParamIdx))
6443a0747c9fSpatrick return;
6444a0747c9fSpatrick break;
6445a0747c9fSpatrick }
6446a0747c9fSpatrick case SwiftAsyncErrorAttr::NonNullError:
6447a0747c9fSpatrick case SwiftAsyncErrorAttr::None: {
6448a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
6449a0747c9fSpatrick return;
6450a0747c9fSpatrick break;
6451a0747c9fSpatrick }
6452a0747c9fSpatrick }
6453a0747c9fSpatrick
6454a0747c9fSpatrick auto *ErrorAttr =
6455a0747c9fSpatrick ::new (S.Context) SwiftAsyncErrorAttr(S.Context, AL, ConvKind, ParamIdx);
6456a0747c9fSpatrick D->addAttr(ErrorAttr);
6457a0747c9fSpatrick
6458a0747c9fSpatrick if (auto *AsyncAttr = D->getAttr<SwiftAsyncAttr>())
6459a0747c9fSpatrick checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr);
6460a0747c9fSpatrick }
6461a0747c9fSpatrick
6462a0747c9fSpatrick // For a function, this will validate a compound Swift name, e.g.
6463a0747c9fSpatrick // <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>, and
6464a0747c9fSpatrick // the function will output the number of parameter names, and whether this is a
6465a0747c9fSpatrick // single-arg initializer.
6466a0747c9fSpatrick //
6467a0747c9fSpatrick // For a type, enum constant, property, or variable declaration, this will
6468a0747c9fSpatrick // validate either a simple identifier, or a qualified
6469a0747c9fSpatrick // <code>context.identifier</code> name.
6470a0747c9fSpatrick static bool
validateSwiftFunctionName(Sema & S,const ParsedAttr & AL,SourceLocation Loc,StringRef Name,unsigned & SwiftParamCount,bool & IsSingleParamInit)6471a0747c9fSpatrick validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
6472a0747c9fSpatrick StringRef Name, unsigned &SwiftParamCount,
6473a0747c9fSpatrick bool &IsSingleParamInit) {
6474a0747c9fSpatrick SwiftParamCount = 0;
6475a0747c9fSpatrick IsSingleParamInit = false;
6476a0747c9fSpatrick
6477a0747c9fSpatrick // Check whether this will be mapped to a getter or setter of a property.
6478a0747c9fSpatrick bool IsGetter = false, IsSetter = false;
6479a0747c9fSpatrick if (Name.startswith("getter:")) {
6480a0747c9fSpatrick IsGetter = true;
6481a0747c9fSpatrick Name = Name.substr(7);
6482a0747c9fSpatrick } else if (Name.startswith("setter:")) {
6483a0747c9fSpatrick IsSetter = true;
6484a0747c9fSpatrick Name = Name.substr(7);
6485a0747c9fSpatrick }
6486a0747c9fSpatrick
6487a0747c9fSpatrick if (Name.back() != ')') {
6488a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
6489a0747c9fSpatrick return false;
6490a0747c9fSpatrick }
6491a0747c9fSpatrick
6492a0747c9fSpatrick bool IsMember = false;
6493a0747c9fSpatrick StringRef ContextName, BaseName, Parameters;
6494a0747c9fSpatrick
6495a0747c9fSpatrick std::tie(BaseName, Parameters) = Name.split('(');
6496a0747c9fSpatrick
6497a0747c9fSpatrick // Split at the first '.', if it exists, which separates the context name
6498a0747c9fSpatrick // from the base name.
6499a0747c9fSpatrick std::tie(ContextName, BaseName) = BaseName.split('.');
6500a0747c9fSpatrick if (BaseName.empty()) {
6501a0747c9fSpatrick BaseName = ContextName;
6502a0747c9fSpatrick ContextName = StringRef();
6503*7a9b00ceSrobert } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) {
6504a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
6505a0747c9fSpatrick << AL << /*context*/ 1;
6506a0747c9fSpatrick return false;
6507a0747c9fSpatrick } else {
6508a0747c9fSpatrick IsMember = true;
6509a0747c9fSpatrick }
6510a0747c9fSpatrick
6511*7a9b00ceSrobert if (!isValidAsciiIdentifier(BaseName) || BaseName == "_") {
6512a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
6513a0747c9fSpatrick << AL << /*basename*/ 0;
6514a0747c9fSpatrick return false;
6515a0747c9fSpatrick }
6516a0747c9fSpatrick
6517a0747c9fSpatrick bool IsSubscript = BaseName == "subscript";
6518a0747c9fSpatrick // A subscript accessor must be a getter or setter.
6519a0747c9fSpatrick if (IsSubscript && !IsGetter && !IsSetter) {
6520a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
6521a0747c9fSpatrick << AL << /* getter or setter */ 0;
6522a0747c9fSpatrick return false;
6523a0747c9fSpatrick }
6524a0747c9fSpatrick
6525a0747c9fSpatrick if (Parameters.empty()) {
6526a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL;
6527a0747c9fSpatrick return false;
6528a0747c9fSpatrick }
6529a0747c9fSpatrick
6530a0747c9fSpatrick assert(Parameters.back() == ')' && "expected ')'");
6531a0747c9fSpatrick Parameters = Parameters.drop_back(); // ')'
6532a0747c9fSpatrick
6533a0747c9fSpatrick if (Parameters.empty()) {
6534a0747c9fSpatrick // Setters and subscripts must have at least one parameter.
6535a0747c9fSpatrick if (IsSubscript) {
6536a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
6537a0747c9fSpatrick << AL << /* have at least one parameter */1;
6538a0747c9fSpatrick return false;
6539a0747c9fSpatrick }
6540a0747c9fSpatrick
6541a0747c9fSpatrick if (IsSetter) {
6542a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL;
6543a0747c9fSpatrick return false;
6544a0747c9fSpatrick }
6545a0747c9fSpatrick
6546a0747c9fSpatrick return true;
6547a0747c9fSpatrick }
6548a0747c9fSpatrick
6549a0747c9fSpatrick if (Parameters.back() != ':') {
6550a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
6551a0747c9fSpatrick return false;
6552a0747c9fSpatrick }
6553a0747c9fSpatrick
6554a0747c9fSpatrick StringRef CurrentParam;
6555*7a9b00ceSrobert std::optional<unsigned> SelfLocation;
6556a0747c9fSpatrick unsigned NewValueCount = 0;
6557*7a9b00ceSrobert std::optional<unsigned> NewValueLocation;
6558a0747c9fSpatrick do {
6559a0747c9fSpatrick std::tie(CurrentParam, Parameters) = Parameters.split(':');
6560a0747c9fSpatrick
6561*7a9b00ceSrobert if (!isValidAsciiIdentifier(CurrentParam)) {
6562a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
6563a0747c9fSpatrick << AL << /*parameter*/2;
6564a0747c9fSpatrick return false;
6565a0747c9fSpatrick }
6566a0747c9fSpatrick
6567a0747c9fSpatrick if (IsMember && CurrentParam == "self") {
6568a0747c9fSpatrick // "self" indicates the "self" argument for a member.
6569a0747c9fSpatrick
6570a0747c9fSpatrick // More than one "self"?
6571a0747c9fSpatrick if (SelfLocation) {
6572a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL;
6573a0747c9fSpatrick return false;
6574a0747c9fSpatrick }
6575a0747c9fSpatrick
6576a0747c9fSpatrick // The "self" location is the current parameter.
6577a0747c9fSpatrick SelfLocation = SwiftParamCount;
6578a0747c9fSpatrick } else if (CurrentParam == "newValue") {
6579a0747c9fSpatrick // "newValue" indicates the "newValue" argument for a setter.
6580a0747c9fSpatrick
6581a0747c9fSpatrick // There should only be one 'newValue', but it's only significant for
6582a0747c9fSpatrick // subscript accessors, so don't error right away.
6583a0747c9fSpatrick ++NewValueCount;
6584a0747c9fSpatrick
6585a0747c9fSpatrick NewValueLocation = SwiftParamCount;
6586a0747c9fSpatrick }
6587a0747c9fSpatrick
6588a0747c9fSpatrick ++SwiftParamCount;
6589a0747c9fSpatrick } while (!Parameters.empty());
6590a0747c9fSpatrick
6591a0747c9fSpatrick // Only instance subscripts are currently supported.
6592a0747c9fSpatrick if (IsSubscript && !SelfLocation) {
6593a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
6594a0747c9fSpatrick << AL << /*have a 'self:' parameter*/2;
6595a0747c9fSpatrick return false;
6596a0747c9fSpatrick }
6597a0747c9fSpatrick
6598a0747c9fSpatrick IsSingleParamInit =
6599a0747c9fSpatrick SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_";
6600a0747c9fSpatrick
6601a0747c9fSpatrick // Check the number of parameters for a getter/setter.
6602a0747c9fSpatrick if (IsGetter || IsSetter) {
6603a0747c9fSpatrick // Setters have one parameter for the new value.
6604a0747c9fSpatrick unsigned NumExpectedParams = IsGetter ? 0 : 1;
6605a0747c9fSpatrick unsigned ParamDiag =
6606a0747c9fSpatrick IsGetter ? diag::warn_attr_swift_name_getter_parameters
6607a0747c9fSpatrick : diag::warn_attr_swift_name_setter_parameters;
6608a0747c9fSpatrick
6609a0747c9fSpatrick // Instance methods have one parameter for "self".
6610a0747c9fSpatrick if (SelfLocation)
6611a0747c9fSpatrick ++NumExpectedParams;
6612a0747c9fSpatrick
6613a0747c9fSpatrick // Subscripts may have additional parameters beyond the expected params for
6614a0747c9fSpatrick // the index.
6615a0747c9fSpatrick if (IsSubscript) {
6616a0747c9fSpatrick if (SwiftParamCount < NumExpectedParams) {
6617a0747c9fSpatrick S.Diag(Loc, ParamDiag) << AL;
6618a0747c9fSpatrick return false;
6619a0747c9fSpatrick }
6620a0747c9fSpatrick
6621a0747c9fSpatrick // A subscript setter must explicitly label its newValue parameter to
6622a0747c9fSpatrick // distinguish it from index parameters.
6623a0747c9fSpatrick if (IsSetter) {
6624a0747c9fSpatrick if (!NewValueLocation) {
6625a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue)
6626a0747c9fSpatrick << AL;
6627a0747c9fSpatrick return false;
6628a0747c9fSpatrick }
6629a0747c9fSpatrick if (NewValueCount > 1) {
6630a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues)
6631a0747c9fSpatrick << AL;
6632a0747c9fSpatrick return false;
6633a0747c9fSpatrick }
6634a0747c9fSpatrick } else {
6635a0747c9fSpatrick // Subscript getters should have no 'newValue:' parameter.
6636a0747c9fSpatrick if (NewValueLocation) {
6637a0747c9fSpatrick S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue)
6638a0747c9fSpatrick << AL;
6639a0747c9fSpatrick return false;
6640a0747c9fSpatrick }
6641a0747c9fSpatrick }
6642a0747c9fSpatrick } else {
6643a0747c9fSpatrick // Property accessors must have exactly the number of expected params.
6644a0747c9fSpatrick if (SwiftParamCount != NumExpectedParams) {
6645a0747c9fSpatrick S.Diag(Loc, ParamDiag) << AL;
6646a0747c9fSpatrick return false;
6647a0747c9fSpatrick }
6648a0747c9fSpatrick }
6649a0747c9fSpatrick }
6650a0747c9fSpatrick
6651a0747c9fSpatrick return true;
6652a0747c9fSpatrick }
6653a0747c9fSpatrick
DiagnoseSwiftName(Decl * D,StringRef Name,SourceLocation Loc,const ParsedAttr & AL,bool IsAsync)6654a0747c9fSpatrick bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
6655a0747c9fSpatrick const ParsedAttr &AL, bool IsAsync) {
6656a0747c9fSpatrick if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
6657a0747c9fSpatrick ArrayRef<ParmVarDecl*> Params;
6658a0747c9fSpatrick unsigned ParamCount;
6659a0747c9fSpatrick
6660a0747c9fSpatrick if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
6661a0747c9fSpatrick ParamCount = Method->getSelector().getNumArgs();
6662a0747c9fSpatrick Params = Method->parameters().slice(0, ParamCount);
6663a0747c9fSpatrick } else {
6664a0747c9fSpatrick const auto *F = cast<FunctionDecl>(D);
6665a0747c9fSpatrick
6666a0747c9fSpatrick ParamCount = F->getNumParams();
6667a0747c9fSpatrick Params = F->parameters();
6668a0747c9fSpatrick
6669a0747c9fSpatrick if (!F->hasWrittenPrototype()) {
6670a0747c9fSpatrick Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL
6671a0747c9fSpatrick << ExpectedFunctionWithProtoType;
6672a0747c9fSpatrick return false;
6673a0747c9fSpatrick }
6674a0747c9fSpatrick }
6675a0747c9fSpatrick
6676a0747c9fSpatrick // The async name drops the last callback parameter.
6677a0747c9fSpatrick if (IsAsync) {
6678a0747c9fSpatrick if (ParamCount == 0) {
6679a0747c9fSpatrick Diag(Loc, diag::warn_attr_swift_name_decl_missing_params)
6680a0747c9fSpatrick << AL << isa<ObjCMethodDecl>(D);
6681a0747c9fSpatrick return false;
6682a0747c9fSpatrick }
6683a0747c9fSpatrick ParamCount -= 1;
6684a0747c9fSpatrick }
6685a0747c9fSpatrick
6686a0747c9fSpatrick unsigned SwiftParamCount;
6687a0747c9fSpatrick bool IsSingleParamInit;
6688a0747c9fSpatrick if (!validateSwiftFunctionName(*this, AL, Loc, Name,
6689a0747c9fSpatrick SwiftParamCount, IsSingleParamInit))
6690a0747c9fSpatrick return false;
6691a0747c9fSpatrick
6692a0747c9fSpatrick bool ParamCountValid;
6693a0747c9fSpatrick if (SwiftParamCount == ParamCount) {
6694a0747c9fSpatrick ParamCountValid = true;
6695a0747c9fSpatrick } else if (SwiftParamCount > ParamCount) {
6696a0747c9fSpatrick ParamCountValid = IsSingleParamInit && ParamCount == 0;
6697a0747c9fSpatrick } else {
6698a0747c9fSpatrick // We have fewer Swift parameters than Objective-C parameters, but that
6699a0747c9fSpatrick // might be because we've transformed some of them. Check for potential
6700a0747c9fSpatrick // "out" parameters and err on the side of not warning.
6701a0747c9fSpatrick unsigned MaybeOutParamCount =
6702*7a9b00ceSrobert llvm::count_if(Params, [](const ParmVarDecl *Param) -> bool {
6703a0747c9fSpatrick QualType ParamTy = Param->getType();
6704a0747c9fSpatrick if (ParamTy->isReferenceType() || ParamTy->isPointerType())
6705a0747c9fSpatrick return !ParamTy->getPointeeType().isConstQualified();
6706a0747c9fSpatrick return false;
6707a0747c9fSpatrick });
6708a0747c9fSpatrick
6709a0747c9fSpatrick ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount;
6710a0747c9fSpatrick }
6711a0747c9fSpatrick
6712a0747c9fSpatrick if (!ParamCountValid) {
6713a0747c9fSpatrick Diag(Loc, diag::warn_attr_swift_name_num_params)
6714a0747c9fSpatrick << (SwiftParamCount > ParamCount) << AL << ParamCount
6715a0747c9fSpatrick << SwiftParamCount;
6716a0747c9fSpatrick return false;
6717a0747c9fSpatrick }
6718a0747c9fSpatrick } else if ((isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) ||
6719a0747c9fSpatrick isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) ||
6720a0747c9fSpatrick isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) ||
6721a0747c9fSpatrick isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) &&
6722a0747c9fSpatrick !IsAsync) {
6723a0747c9fSpatrick StringRef ContextName, BaseName;
6724a0747c9fSpatrick
6725a0747c9fSpatrick std::tie(ContextName, BaseName) = Name.split('.');
6726a0747c9fSpatrick if (BaseName.empty()) {
6727a0747c9fSpatrick BaseName = ContextName;
6728a0747c9fSpatrick ContextName = StringRef();
6729*7a9b00ceSrobert } else if (!isValidAsciiIdentifier(ContextName)) {
6730a0747c9fSpatrick Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
6731a0747c9fSpatrick << /*context*/1;
6732a0747c9fSpatrick return false;
6733a0747c9fSpatrick }
6734a0747c9fSpatrick
6735*7a9b00ceSrobert if (!isValidAsciiIdentifier(BaseName)) {
6736a0747c9fSpatrick Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
6737a0747c9fSpatrick << /*basename*/0;
6738a0747c9fSpatrick return false;
6739a0747c9fSpatrick }
6740a0747c9fSpatrick } else {
6741a0747c9fSpatrick Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL;
6742a0747c9fSpatrick return false;
6743a0747c9fSpatrick }
6744a0747c9fSpatrick return true;
6745a0747c9fSpatrick }
6746a0747c9fSpatrick
handleSwiftName(Sema & S,Decl * D,const ParsedAttr & AL)6747a0747c9fSpatrick static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
6748a0747c9fSpatrick StringRef Name;
6749a0747c9fSpatrick SourceLocation Loc;
6750a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
6751a0747c9fSpatrick return;
6752a0747c9fSpatrick
6753a0747c9fSpatrick if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false))
6754a0747c9fSpatrick return;
6755a0747c9fSpatrick
6756a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
6757a0747c9fSpatrick }
6758a0747c9fSpatrick
handleSwiftAsyncName(Sema & S,Decl * D,const ParsedAttr & AL)6759a0747c9fSpatrick static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) {
6760a0747c9fSpatrick StringRef Name;
6761a0747c9fSpatrick SourceLocation Loc;
6762a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
6763a0747c9fSpatrick return;
6764a0747c9fSpatrick
6765a0747c9fSpatrick if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/true))
6766a0747c9fSpatrick return;
6767a0747c9fSpatrick
6768a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name));
6769a0747c9fSpatrick }
6770a0747c9fSpatrick
handleSwiftNewType(Sema & S,Decl * D,const ParsedAttr & AL)6771a0747c9fSpatrick static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
6772a0747c9fSpatrick // Make sure that there is an identifier as the annotation's single argument.
6773a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
6774a0747c9fSpatrick return;
6775a0747c9fSpatrick
6776a0747c9fSpatrick if (!AL.isArgIdent(0)) {
6777a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
6778a0747c9fSpatrick << AL << AANT_ArgumentIdentifier;
6779a0747c9fSpatrick return;
6780a0747c9fSpatrick }
6781a0747c9fSpatrick
6782a0747c9fSpatrick SwiftNewTypeAttr::NewtypeKind Kind;
6783a0747c9fSpatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
6784a0747c9fSpatrick if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) {
6785a0747c9fSpatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
6786a0747c9fSpatrick return;
6787a0747c9fSpatrick }
6788a0747c9fSpatrick
6789a0747c9fSpatrick if (!isa<TypedefNameDecl>(D)) {
6790a0747c9fSpatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
6791a0747c9fSpatrick << AL << "typedefs";
6792a0747c9fSpatrick return;
6793a0747c9fSpatrick }
6794a0747c9fSpatrick
6795a0747c9fSpatrick D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind));
6796a0747c9fSpatrick }
6797a0747c9fSpatrick
handleSwiftAsyncAttr(Sema & S,Decl * D,const ParsedAttr & AL)6798a0747c9fSpatrick static void handleSwiftAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6799a0747c9fSpatrick if (!AL.isArgIdent(0)) {
6800a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
6801a0747c9fSpatrick << AL << 1 << AANT_ArgumentIdentifier;
6802a0747c9fSpatrick return;
6803a0747c9fSpatrick }
6804a0747c9fSpatrick
6805a0747c9fSpatrick SwiftAsyncAttr::Kind Kind;
6806a0747c9fSpatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
6807a0747c9fSpatrick if (!SwiftAsyncAttr::ConvertStrToKind(II->getName(), Kind)) {
6808a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_swift_async_no_access) << AL << II;
6809a0747c9fSpatrick return;
6810a0747c9fSpatrick }
6811a0747c9fSpatrick
6812a0747c9fSpatrick ParamIdx Idx;
6813a0747c9fSpatrick if (Kind == SwiftAsyncAttr::None) {
6814a0747c9fSpatrick // If this is 'none', then there shouldn't be any additional arguments.
6815a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
6816a0747c9fSpatrick return;
6817a0747c9fSpatrick } else {
6818a0747c9fSpatrick // Non-none swift_async requires a completion handler index argument.
6819a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 2))
6820a0747c9fSpatrick return;
6821a0747c9fSpatrick
6822a0747c9fSpatrick Expr *HandlerIdx = AL.getArgAsExpr(1);
6823a0747c9fSpatrick if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, HandlerIdx, Idx))
6824a0747c9fSpatrick return;
6825a0747c9fSpatrick
6826a0747c9fSpatrick const ParmVarDecl *CompletionBlock =
6827a0747c9fSpatrick getFunctionOrMethodParam(D, Idx.getASTIndex());
6828a0747c9fSpatrick QualType CompletionBlockType = CompletionBlock->getType();
6829a0747c9fSpatrick if (!CompletionBlockType->isBlockPointerType()) {
6830a0747c9fSpatrick S.Diag(CompletionBlock->getLocation(),
6831a0747c9fSpatrick diag::err_swift_async_bad_block_type)
6832a0747c9fSpatrick << CompletionBlock->getType();
6833a0747c9fSpatrick return;
6834a0747c9fSpatrick }
6835a0747c9fSpatrick QualType BlockTy =
6836a0747c9fSpatrick CompletionBlockType->castAs<BlockPointerType>()->getPointeeType();
6837a0747c9fSpatrick if (!BlockTy->castAs<FunctionType>()->getReturnType()->isVoidType()) {
6838a0747c9fSpatrick S.Diag(CompletionBlock->getLocation(),
6839a0747c9fSpatrick diag::err_swift_async_bad_block_type)
6840a0747c9fSpatrick << CompletionBlock->getType();
6841a0747c9fSpatrick return;
6842a0747c9fSpatrick }
6843a0747c9fSpatrick }
6844a0747c9fSpatrick
6845a0747c9fSpatrick auto *AsyncAttr =
6846a0747c9fSpatrick ::new (S.Context) SwiftAsyncAttr(S.Context, AL, Kind, Idx);
6847a0747c9fSpatrick D->addAttr(AsyncAttr);
6848a0747c9fSpatrick
6849a0747c9fSpatrick if (auto *ErrorAttr = D->getAttr<SwiftAsyncErrorAttr>())
6850a0747c9fSpatrick checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr);
6851a0747c9fSpatrick }
6852a0747c9fSpatrick
6853e5dd7070Spatrick //===----------------------------------------------------------------------===//
6854e5dd7070Spatrick // Microsoft specific attribute handlers.
6855e5dd7070Spatrick //===----------------------------------------------------------------------===//
6856e5dd7070Spatrick
mergeUuidAttr(Decl * D,const AttributeCommonInfo & CI,StringRef UuidAsWritten,MSGuidDecl * GuidDecl)6857e5dd7070Spatrick UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
6858ec727ea7Spatrick StringRef UuidAsWritten, MSGuidDecl *GuidDecl) {
6859e5dd7070Spatrick if (const auto *UA = D->getAttr<UuidAttr>()) {
6860ec727ea7Spatrick if (declaresSameEntity(UA->getGuidDecl(), GuidDecl))
6861e5dd7070Spatrick return nullptr;
6862e5dd7070Spatrick if (!UA->getGuid().empty()) {
6863e5dd7070Spatrick Diag(UA->getLocation(), diag::err_mismatched_uuid);
6864e5dd7070Spatrick Diag(CI.getLoc(), diag::note_previous_uuid);
6865e5dd7070Spatrick D->dropAttr<UuidAttr>();
6866e5dd7070Spatrick }
6867e5dd7070Spatrick }
6868e5dd7070Spatrick
6869ec727ea7Spatrick return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl);
6870e5dd7070Spatrick }
6871e5dd7070Spatrick
handleUuidAttr(Sema & S,Decl * D,const ParsedAttr & AL)6872e5dd7070Spatrick static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6873e5dd7070Spatrick if (!S.LangOpts.CPlusPlus) {
6874e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
6875e5dd7070Spatrick << AL << AttributeLangSupport::C;
6876e5dd7070Spatrick return;
6877e5dd7070Spatrick }
6878e5dd7070Spatrick
6879ec727ea7Spatrick StringRef OrigStrRef;
6880e5dd7070Spatrick SourceLocation LiteralLoc;
6881ec727ea7Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc))
6882e5dd7070Spatrick return;
6883e5dd7070Spatrick
6884e5dd7070Spatrick // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
6885e5dd7070Spatrick // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former.
6886ec727ea7Spatrick StringRef StrRef = OrigStrRef;
6887e5dd7070Spatrick if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}')
6888e5dd7070Spatrick StrRef = StrRef.drop_front().drop_back();
6889e5dd7070Spatrick
6890e5dd7070Spatrick // Validate GUID length.
6891e5dd7070Spatrick if (StrRef.size() != 36) {
6892e5dd7070Spatrick S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
6893e5dd7070Spatrick return;
6894e5dd7070Spatrick }
6895e5dd7070Spatrick
6896e5dd7070Spatrick for (unsigned i = 0; i < 36; ++i) {
6897e5dd7070Spatrick if (i == 8 || i == 13 || i == 18 || i == 23) {
6898e5dd7070Spatrick if (StrRef[i] != '-') {
6899e5dd7070Spatrick S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
6900e5dd7070Spatrick return;
6901e5dd7070Spatrick }
6902e5dd7070Spatrick } else if (!isHexDigit(StrRef[i])) {
6903e5dd7070Spatrick S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
6904e5dd7070Spatrick return;
6905e5dd7070Spatrick }
6906e5dd7070Spatrick }
6907e5dd7070Spatrick
6908ec727ea7Spatrick // Convert to our parsed format and canonicalize.
6909ec727ea7Spatrick MSGuidDecl::Parts Parsed;
6910ec727ea7Spatrick StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1);
6911ec727ea7Spatrick StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2);
6912ec727ea7Spatrick StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3);
6913ec727ea7Spatrick for (unsigned i = 0; i != 8; ++i)
6914ec727ea7Spatrick StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2)
6915ec727ea7Spatrick .getAsInteger(16, Parsed.Part4And5[i]);
6916ec727ea7Spatrick MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed);
6917ec727ea7Spatrick
6918e5dd7070Spatrick // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
6919e5dd7070Spatrick // the only thing in the [] list, the [] too), and add an insertion of
6920e5dd7070Spatrick // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
6921e5dd7070Spatrick // separating attributes nor of the [ and the ] are in the AST.
6922e5dd7070Spatrick // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc"
6923e5dd7070Spatrick // on cfe-dev.
6924e5dd7070Spatrick if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
6925e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
6926e5dd7070Spatrick
6927ec727ea7Spatrick UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid);
6928e5dd7070Spatrick if (UA)
6929e5dd7070Spatrick D->addAttr(UA);
6930e5dd7070Spatrick }
6931e5dd7070Spatrick
handleHLSLNumThreadsAttr(Sema & S,Decl * D,const ParsedAttr & AL)6932*7a9b00ceSrobert static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6933*7a9b00ceSrobert using llvm::Triple;
6934*7a9b00ceSrobert Triple Target = S.Context.getTargetInfo().getTriple();
6935*7a9b00ceSrobert auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
6936*7a9b00ceSrobert if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification,
6937*7a9b00ceSrobert Triple::Library},
6938*7a9b00ceSrobert Env)) {
6939*7a9b00ceSrobert uint32_t Pipeline =
6940*7a9b00ceSrobert static_cast<uint32_t>(hlsl::getStageFromEnvironment(Env));
6941*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
6942*7a9b00ceSrobert << AL << Pipeline << "Compute, Amplification, Mesh or Library";
6943*7a9b00ceSrobert return;
6944*7a9b00ceSrobert }
6945*7a9b00ceSrobert
6946*7a9b00ceSrobert llvm::VersionTuple SMVersion = Target.getOSVersion();
6947*7a9b00ceSrobert uint32_t ZMax = 1024;
6948*7a9b00ceSrobert uint32_t ThreadMax = 1024;
6949*7a9b00ceSrobert if (SMVersion.getMajor() <= 4) {
6950*7a9b00ceSrobert ZMax = 1;
6951*7a9b00ceSrobert ThreadMax = 768;
6952*7a9b00ceSrobert } else if (SMVersion.getMajor() == 5) {
6953*7a9b00ceSrobert ZMax = 64;
6954*7a9b00ceSrobert ThreadMax = 1024;
6955*7a9b00ceSrobert }
6956*7a9b00ceSrobert
6957*7a9b00ceSrobert uint32_t X;
6958*7a9b00ceSrobert if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), X))
6959*7a9b00ceSrobert return;
6960*7a9b00ceSrobert if (X > 1024) {
6961*7a9b00ceSrobert S.Diag(AL.getArgAsExpr(0)->getExprLoc(),
6962*7a9b00ceSrobert diag::err_hlsl_numthreads_argument_oor) << 0 << 1024;
6963*7a9b00ceSrobert return;
6964*7a9b00ceSrobert }
6965*7a9b00ceSrobert uint32_t Y;
6966*7a9b00ceSrobert if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Y))
6967*7a9b00ceSrobert return;
6968*7a9b00ceSrobert if (Y > 1024) {
6969*7a9b00ceSrobert S.Diag(AL.getArgAsExpr(1)->getExprLoc(),
6970*7a9b00ceSrobert diag::err_hlsl_numthreads_argument_oor) << 1 << 1024;
6971*7a9b00ceSrobert return;
6972*7a9b00ceSrobert }
6973*7a9b00ceSrobert uint32_t Z;
6974*7a9b00ceSrobert if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(2), Z))
6975*7a9b00ceSrobert return;
6976*7a9b00ceSrobert if (Z > ZMax) {
6977*7a9b00ceSrobert S.Diag(AL.getArgAsExpr(2)->getExprLoc(),
6978*7a9b00ceSrobert diag::err_hlsl_numthreads_argument_oor) << 2 << ZMax;
6979*7a9b00ceSrobert return;
6980*7a9b00ceSrobert }
6981*7a9b00ceSrobert
6982*7a9b00ceSrobert if (X * Y * Z > ThreadMax) {
6983*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
6984*7a9b00ceSrobert return;
6985*7a9b00ceSrobert }
6986*7a9b00ceSrobert
6987*7a9b00ceSrobert HLSLNumThreadsAttr *NewAttr = S.mergeHLSLNumThreadsAttr(D, AL, X, Y, Z);
6988*7a9b00ceSrobert if (NewAttr)
6989*7a9b00ceSrobert D->addAttr(NewAttr);
6990*7a9b00ceSrobert }
6991*7a9b00ceSrobert
mergeHLSLNumThreadsAttr(Decl * D,const AttributeCommonInfo & AL,int X,int Y,int Z)6992*7a9b00ceSrobert HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
6993*7a9b00ceSrobert const AttributeCommonInfo &AL,
6994*7a9b00ceSrobert int X, int Y, int Z) {
6995*7a9b00ceSrobert if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
6996*7a9b00ceSrobert if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
6997*7a9b00ceSrobert Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
6998*7a9b00ceSrobert Diag(AL.getLoc(), diag::note_conflicting_attribute);
6999*7a9b00ceSrobert }
7000*7a9b00ceSrobert return nullptr;
7001*7a9b00ceSrobert }
7002*7a9b00ceSrobert return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z);
7003*7a9b00ceSrobert }
7004*7a9b00ceSrobert
handleHLSLSVGroupIndexAttr(Sema & S,Decl * D,const ParsedAttr & AL)7005*7a9b00ceSrobert static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7006*7a9b00ceSrobert using llvm::Triple;
7007*7a9b00ceSrobert auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
7008*7a9b00ceSrobert if (Env != Triple::Compute && Env != Triple::Library) {
7009*7a9b00ceSrobert // FIXME: it is OK for a compute shader entry and pixel shader entry live in
7010*7a9b00ceSrobert // same HLSL file. Issue https://github.com/llvm/llvm-project/issues/57880.
7011*7a9b00ceSrobert ShaderStage Pipeline = hlsl::getStageFromEnvironment(Env);
7012*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
7013*7a9b00ceSrobert << AL << (uint32_t)Pipeline << "Compute";
7014*7a9b00ceSrobert return;
7015*7a9b00ceSrobert }
7016*7a9b00ceSrobert
7017*7a9b00ceSrobert D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
7018*7a9b00ceSrobert }
7019*7a9b00ceSrobert
isLegalTypeForHLSLSV_DispatchThreadID(QualType T)7020*7a9b00ceSrobert static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
7021*7a9b00ceSrobert if (!T->hasUnsignedIntegerRepresentation())
7022*7a9b00ceSrobert return false;
7023*7a9b00ceSrobert if (const auto *VT = T->getAs<VectorType>())
7024*7a9b00ceSrobert return VT->getNumElements() <= 3;
7025*7a9b00ceSrobert return true;
7026*7a9b00ceSrobert }
7027*7a9b00ceSrobert
handleHLSLSV_DispatchThreadIDAttr(Sema & S,Decl * D,const ParsedAttr & AL)7028*7a9b00ceSrobert static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
7029*7a9b00ceSrobert const ParsedAttr &AL) {
7030*7a9b00ceSrobert using llvm::Triple;
7031*7a9b00ceSrobert Triple Target = S.Context.getTargetInfo().getTriple();
7032*7a9b00ceSrobert // FIXME: it is OK for a compute shader entry and pixel shader entry live in
7033*7a9b00ceSrobert // same HLSL file.Issue https://github.com/llvm/llvm-project/issues/57880.
7034*7a9b00ceSrobert if (Target.getEnvironment() != Triple::Compute &&
7035*7a9b00ceSrobert Target.getEnvironment() != Triple::Library) {
7036*7a9b00ceSrobert uint32_t Pipeline =
7037*7a9b00ceSrobert (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
7038*7a9b00ceSrobert (uint32_t)llvm::Triple::Pixel;
7039*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
7040*7a9b00ceSrobert << AL << Pipeline << "Compute";
7041*7a9b00ceSrobert return;
7042*7a9b00ceSrobert }
7043*7a9b00ceSrobert
7044*7a9b00ceSrobert // FIXME: report warning and ignore semantic when cannot apply on the Decl.
7045*7a9b00ceSrobert // See https://github.com/llvm/llvm-project/issues/57916.
7046*7a9b00ceSrobert
7047*7a9b00ceSrobert // FIXME: support semantic on field.
7048*7a9b00ceSrobert // See https://github.com/llvm/llvm-project/issues/57889.
7049*7a9b00ceSrobert if (isa<FieldDecl>(D)) {
7050*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
7051*7a9b00ceSrobert << AL << "parameter";
7052*7a9b00ceSrobert return;
7053*7a9b00ceSrobert }
7054*7a9b00ceSrobert
7055*7a9b00ceSrobert auto *VD = cast<ValueDecl>(D);
7056*7a9b00ceSrobert if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
7057*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
7058*7a9b00ceSrobert << AL << "uint/uint2/uint3";
7059*7a9b00ceSrobert return;
7060*7a9b00ceSrobert }
7061*7a9b00ceSrobert
7062*7a9b00ceSrobert D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
7063*7a9b00ceSrobert }
7064*7a9b00ceSrobert
handleHLSLShaderAttr(Sema & S,Decl * D,const ParsedAttr & AL)7065*7a9b00ceSrobert static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7066*7a9b00ceSrobert StringRef Str;
7067*7a9b00ceSrobert SourceLocation ArgLoc;
7068*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7069*7a9b00ceSrobert return;
7070*7a9b00ceSrobert
7071*7a9b00ceSrobert HLSLShaderAttr::ShaderType ShaderType;
7072*7a9b00ceSrobert if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType) ||
7073*7a9b00ceSrobert // Library is added to help convert HLSLShaderAttr::ShaderType to
7074*7a9b00ceSrobert // llvm::Triple::EnviromentType. It is not a legal
7075*7a9b00ceSrobert // HLSLShaderAttr::ShaderType.
7076*7a9b00ceSrobert ShaderType == HLSLShaderAttr::Library) {
7077*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
7078*7a9b00ceSrobert << AL << Str << ArgLoc;
7079*7a9b00ceSrobert return;
7080*7a9b00ceSrobert }
7081*7a9b00ceSrobert
7082*7a9b00ceSrobert // FIXME: check function match the shader stage.
7083*7a9b00ceSrobert
7084*7a9b00ceSrobert HLSLShaderAttr *NewAttr = S.mergeHLSLShaderAttr(D, AL, ShaderType);
7085*7a9b00ceSrobert if (NewAttr)
7086*7a9b00ceSrobert D->addAttr(NewAttr);
7087*7a9b00ceSrobert }
7088*7a9b00ceSrobert
7089*7a9b00ceSrobert HLSLShaderAttr *
mergeHLSLShaderAttr(Decl * D,const AttributeCommonInfo & AL,HLSLShaderAttr::ShaderType ShaderType)7090*7a9b00ceSrobert Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
7091*7a9b00ceSrobert HLSLShaderAttr::ShaderType ShaderType) {
7092*7a9b00ceSrobert if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
7093*7a9b00ceSrobert if (NT->getType() != ShaderType) {
7094*7a9b00ceSrobert Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
7095*7a9b00ceSrobert Diag(AL.getLoc(), diag::note_conflicting_attribute);
7096*7a9b00ceSrobert }
7097*7a9b00ceSrobert return nullptr;
7098*7a9b00ceSrobert }
7099*7a9b00ceSrobert return HLSLShaderAttr::Create(Context, ShaderType, AL);
7100*7a9b00ceSrobert }
7101*7a9b00ceSrobert
handleHLSLResourceBindingAttr(Sema & S,Decl * D,const ParsedAttr & AL)7102*7a9b00ceSrobert static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
7103*7a9b00ceSrobert const ParsedAttr &AL) {
7104*7a9b00ceSrobert StringRef Space = "space0";
7105*7a9b00ceSrobert StringRef Slot = "";
7106*7a9b00ceSrobert
7107*7a9b00ceSrobert if (!AL.isArgIdent(0)) {
7108*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7109*7a9b00ceSrobert << AL << AANT_ArgumentIdentifier;
7110*7a9b00ceSrobert return;
7111*7a9b00ceSrobert }
7112*7a9b00ceSrobert
7113*7a9b00ceSrobert IdentifierLoc *Loc = AL.getArgAsIdent(0);
7114*7a9b00ceSrobert StringRef Str = Loc->Ident->getName();
7115*7a9b00ceSrobert SourceLocation ArgLoc = Loc->Loc;
7116*7a9b00ceSrobert
7117*7a9b00ceSrobert SourceLocation SpaceArgLoc;
7118*7a9b00ceSrobert if (AL.getNumArgs() == 2) {
7119*7a9b00ceSrobert Slot = Str;
7120*7a9b00ceSrobert if (!AL.isArgIdent(1)) {
7121*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7122*7a9b00ceSrobert << AL << AANT_ArgumentIdentifier;
7123*7a9b00ceSrobert return;
7124*7a9b00ceSrobert }
7125*7a9b00ceSrobert
7126*7a9b00ceSrobert IdentifierLoc *Loc = AL.getArgAsIdent(1);
7127*7a9b00ceSrobert Space = Loc->Ident->getName();
7128*7a9b00ceSrobert SpaceArgLoc = Loc->Loc;
7129*7a9b00ceSrobert } else {
7130*7a9b00ceSrobert Slot = Str;
7131*7a9b00ceSrobert }
7132*7a9b00ceSrobert
7133*7a9b00ceSrobert // Validate.
7134*7a9b00ceSrobert if (!Slot.empty()) {
7135*7a9b00ceSrobert switch (Slot[0]) {
7136*7a9b00ceSrobert case 'u':
7137*7a9b00ceSrobert case 'b':
7138*7a9b00ceSrobert case 's':
7139*7a9b00ceSrobert case 't':
7140*7a9b00ceSrobert break;
7141*7a9b00ceSrobert default:
7142*7a9b00ceSrobert S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
7143*7a9b00ceSrobert << Slot.substr(0, 1);
7144*7a9b00ceSrobert return;
7145*7a9b00ceSrobert }
7146*7a9b00ceSrobert
7147*7a9b00ceSrobert StringRef SlotNum = Slot.substr(1);
7148*7a9b00ceSrobert unsigned Num = 0;
7149*7a9b00ceSrobert if (SlotNum.getAsInteger(10, Num)) {
7150*7a9b00ceSrobert S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
7151*7a9b00ceSrobert return;
7152*7a9b00ceSrobert }
7153*7a9b00ceSrobert }
7154*7a9b00ceSrobert
7155*7a9b00ceSrobert if (!Space.startswith("space")) {
7156*7a9b00ceSrobert S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
7157*7a9b00ceSrobert return;
7158*7a9b00ceSrobert }
7159*7a9b00ceSrobert StringRef SpaceNum = Space.substr(5);
7160*7a9b00ceSrobert unsigned Num = 0;
7161*7a9b00ceSrobert if (SpaceNum.getAsInteger(10, Num)) {
7162*7a9b00ceSrobert S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
7163*7a9b00ceSrobert return;
7164*7a9b00ceSrobert }
7165*7a9b00ceSrobert
7166*7a9b00ceSrobert // FIXME: check reg type match decl. Issue
7167*7a9b00ceSrobert // https://github.com/llvm/llvm-project/issues/57886.
7168*7a9b00ceSrobert HLSLResourceBindingAttr *NewAttr =
7169*7a9b00ceSrobert HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
7170*7a9b00ceSrobert if (NewAttr)
7171*7a9b00ceSrobert D->addAttr(NewAttr);
7172*7a9b00ceSrobert }
7173*7a9b00ceSrobert
handleMSInheritanceAttr(Sema & S,Decl * D,const ParsedAttr & AL)7174e5dd7070Spatrick static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7175e5dd7070Spatrick if (!S.LangOpts.CPlusPlus) {
7176e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
7177e5dd7070Spatrick << AL << AttributeLangSupport::C;
7178e5dd7070Spatrick return;
7179e5dd7070Spatrick }
7180e5dd7070Spatrick MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
7181e5dd7070Spatrick D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling());
7182e5dd7070Spatrick if (IA) {
7183e5dd7070Spatrick D->addAttr(IA);
7184e5dd7070Spatrick S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
7185e5dd7070Spatrick }
7186e5dd7070Spatrick }
7187e5dd7070Spatrick
handleDeclspecThreadAttr(Sema & S,Decl * D,const ParsedAttr & AL)7188e5dd7070Spatrick static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7189e5dd7070Spatrick const auto *VD = cast<VarDecl>(D);
7190e5dd7070Spatrick if (!S.Context.getTargetInfo().isTLSSupported()) {
7191e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_thread_unsupported);
7192e5dd7070Spatrick return;
7193e5dd7070Spatrick }
7194e5dd7070Spatrick if (VD->getTSCSpec() != TSCS_unspecified) {
7195e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable);
7196e5dd7070Spatrick return;
7197e5dd7070Spatrick }
7198e5dd7070Spatrick if (VD->hasLocalStorage()) {
7199e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
7200e5dd7070Spatrick return;
7201e5dd7070Spatrick }
7202e5dd7070Spatrick D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL));
7203e5dd7070Spatrick }
7204e5dd7070Spatrick
handleAbiTagAttr(Sema & S,Decl * D,const ParsedAttr & AL)7205e5dd7070Spatrick static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7206e5dd7070Spatrick SmallVector<StringRef, 4> Tags;
7207e5dd7070Spatrick for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
7208e5dd7070Spatrick StringRef Tag;
7209e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, I, Tag))
7210e5dd7070Spatrick return;
7211e5dd7070Spatrick Tags.push_back(Tag);
7212e5dd7070Spatrick }
7213e5dd7070Spatrick
7214e5dd7070Spatrick if (const auto *NS = dyn_cast<NamespaceDecl>(D)) {
7215e5dd7070Spatrick if (!NS->isInline()) {
7216e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 0;
7217e5dd7070Spatrick return;
7218e5dd7070Spatrick }
7219e5dd7070Spatrick if (NS->isAnonymousNamespace()) {
7220e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1;
7221e5dd7070Spatrick return;
7222e5dd7070Spatrick }
7223e5dd7070Spatrick if (AL.getNumArgs() == 0)
7224e5dd7070Spatrick Tags.push_back(NS->getName());
7225a0747c9fSpatrick } else if (!AL.checkAtLeastNumArgs(S, 1))
7226e5dd7070Spatrick return;
7227e5dd7070Spatrick
7228e5dd7070Spatrick // Store tags sorted and without duplicates.
7229e5dd7070Spatrick llvm::sort(Tags);
7230e5dd7070Spatrick Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
7231e5dd7070Spatrick
7232e5dd7070Spatrick D->addAttr(::new (S.Context)
7233e5dd7070Spatrick AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
7234e5dd7070Spatrick }
7235e5dd7070Spatrick
handleARMInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7236e5dd7070Spatrick static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7237e5dd7070Spatrick // Check the attribute arguments.
7238e5dd7070Spatrick if (AL.getNumArgs() > 1) {
7239e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
7240e5dd7070Spatrick return;
7241e5dd7070Spatrick }
7242e5dd7070Spatrick
7243e5dd7070Spatrick StringRef Str;
7244e5dd7070Spatrick SourceLocation ArgLoc;
7245e5dd7070Spatrick
7246e5dd7070Spatrick if (AL.getNumArgs() == 0)
7247e5dd7070Spatrick Str = "";
7248e5dd7070Spatrick else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7249e5dd7070Spatrick return;
7250e5dd7070Spatrick
7251e5dd7070Spatrick ARMInterruptAttr::InterruptType Kind;
7252e5dd7070Spatrick if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
7253e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
7254e5dd7070Spatrick << ArgLoc;
7255e5dd7070Spatrick return;
7256e5dd7070Spatrick }
7257e5dd7070Spatrick
7258e5dd7070Spatrick D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind));
7259e5dd7070Spatrick }
7260e5dd7070Spatrick
handleMSP430InterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7261e5dd7070Spatrick static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7262e5dd7070Spatrick // MSP430 'interrupt' attribute is applied to
7263e5dd7070Spatrick // a function with no parameters and void return type.
7264e5dd7070Spatrick if (!isFunctionOrMethod(D)) {
7265e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7266e5dd7070Spatrick << "'interrupt'" << ExpectedFunctionOrMethod;
7267e5dd7070Spatrick return;
7268e5dd7070Spatrick }
7269e5dd7070Spatrick
7270e5dd7070Spatrick if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
7271e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7272e5dd7070Spatrick << /*MSP430*/ 1 << 0;
7273e5dd7070Spatrick return;
7274e5dd7070Spatrick }
7275e5dd7070Spatrick
7276e5dd7070Spatrick if (!getFunctionOrMethodResultType(D)->isVoidType()) {
7277e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7278e5dd7070Spatrick << /*MSP430*/ 1 << 1;
7279e5dd7070Spatrick return;
7280e5dd7070Spatrick }
7281e5dd7070Spatrick
7282e5dd7070Spatrick // The attribute takes one integer argument.
7283a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
7284e5dd7070Spatrick return;
7285e5dd7070Spatrick
7286e5dd7070Spatrick if (!AL.isArgExpr(0)) {
7287e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7288e5dd7070Spatrick << AL << AANT_ArgumentIntegerConstant;
7289e5dd7070Spatrick return;
7290e5dd7070Spatrick }
7291e5dd7070Spatrick
7292e5dd7070Spatrick Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
7293*7a9b00ceSrobert std::optional<llvm::APSInt> NumParams = llvm::APSInt(32);
7294a0747c9fSpatrick if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) {
7295e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7296e5dd7070Spatrick << AL << AANT_ArgumentIntegerConstant
7297e5dd7070Spatrick << NumParamsExpr->getSourceRange();
7298e5dd7070Spatrick return;
7299e5dd7070Spatrick }
7300e5dd7070Spatrick // The argument should be in range 0..63.
7301a0747c9fSpatrick unsigned Num = NumParams->getLimitedValue(255);
7302e5dd7070Spatrick if (Num > 63) {
7303e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
7304a0747c9fSpatrick << AL << (int)NumParams->getSExtValue()
7305e5dd7070Spatrick << NumParamsExpr->getSourceRange();
7306e5dd7070Spatrick return;
7307e5dd7070Spatrick }
7308e5dd7070Spatrick
7309e5dd7070Spatrick D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num));
7310e5dd7070Spatrick D->addAttr(UsedAttr::CreateImplicit(S.Context));
7311e5dd7070Spatrick }
7312e5dd7070Spatrick
handleMipsInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7313e5dd7070Spatrick static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7314e5dd7070Spatrick // Only one optional argument permitted.
7315e5dd7070Spatrick if (AL.getNumArgs() > 1) {
7316e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
7317e5dd7070Spatrick return;
7318e5dd7070Spatrick }
7319e5dd7070Spatrick
7320e5dd7070Spatrick StringRef Str;
7321e5dd7070Spatrick SourceLocation ArgLoc;
7322e5dd7070Spatrick
7323e5dd7070Spatrick if (AL.getNumArgs() == 0)
7324e5dd7070Spatrick Str = "";
7325e5dd7070Spatrick else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7326e5dd7070Spatrick return;
7327e5dd7070Spatrick
7328e5dd7070Spatrick // Semantic checks for a function with the 'interrupt' attribute for MIPS:
7329e5dd7070Spatrick // a) Must be a function.
7330e5dd7070Spatrick // b) Must have no parameters.
7331e5dd7070Spatrick // c) Must have the 'void' return type.
7332e5dd7070Spatrick // d) Cannot have the 'mips16' attribute, as that instruction set
7333e5dd7070Spatrick // lacks the 'eret' instruction.
7334e5dd7070Spatrick // e) The attribute itself must either have no argument or one of the
7335e5dd7070Spatrick // valid interrupt types, see [MipsInterruptDocs].
7336e5dd7070Spatrick
7337e5dd7070Spatrick if (!isFunctionOrMethod(D)) {
7338e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7339e5dd7070Spatrick << "'interrupt'" << ExpectedFunctionOrMethod;
7340e5dd7070Spatrick return;
7341e5dd7070Spatrick }
7342e5dd7070Spatrick
7343e5dd7070Spatrick if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
7344e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7345e5dd7070Spatrick << /*MIPS*/ 0 << 0;
7346e5dd7070Spatrick return;
7347e5dd7070Spatrick }
7348e5dd7070Spatrick
7349e5dd7070Spatrick if (!getFunctionOrMethodResultType(D)->isVoidType()) {
7350e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7351e5dd7070Spatrick << /*MIPS*/ 0 << 1;
7352e5dd7070Spatrick return;
7353e5dd7070Spatrick }
7354e5dd7070Spatrick
7355a0747c9fSpatrick // We still have to do this manually because the Interrupt attributes are
7356a0747c9fSpatrick // a bit special due to sharing their spellings across targets.
7357e5dd7070Spatrick if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL))
7358e5dd7070Spatrick return;
7359e5dd7070Spatrick
7360e5dd7070Spatrick MipsInterruptAttr::InterruptType Kind;
7361e5dd7070Spatrick if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
7362e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
7363e5dd7070Spatrick << AL << "'" + std::string(Str) + "'";
7364e5dd7070Spatrick return;
7365e5dd7070Spatrick }
7366e5dd7070Spatrick
7367e5dd7070Spatrick D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind));
7368e5dd7070Spatrick }
7369e5dd7070Spatrick
handleM68kInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7370a0747c9fSpatrick static void handleM68kInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7371a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 1))
7372a0747c9fSpatrick return;
7373a0747c9fSpatrick
7374a0747c9fSpatrick if (!AL.isArgExpr(0)) {
7375a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7376a0747c9fSpatrick << AL << AANT_ArgumentIntegerConstant;
7377a0747c9fSpatrick return;
7378a0747c9fSpatrick }
7379a0747c9fSpatrick
7380a0747c9fSpatrick // FIXME: Check for decl - it should be void ()(void).
7381a0747c9fSpatrick
7382a0747c9fSpatrick Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
7383a0747c9fSpatrick auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(S.Context);
7384a0747c9fSpatrick if (!MaybeNumParams) {
7385a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
7386a0747c9fSpatrick << AL << AANT_ArgumentIntegerConstant
7387a0747c9fSpatrick << NumParamsExpr->getSourceRange();
7388a0747c9fSpatrick return;
7389a0747c9fSpatrick }
7390a0747c9fSpatrick
7391a0747c9fSpatrick unsigned Num = MaybeNumParams->getLimitedValue(255);
7392a0747c9fSpatrick if ((Num & 1) || Num > 30) {
7393a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
7394a0747c9fSpatrick << AL << (int)MaybeNumParams->getSExtValue()
7395a0747c9fSpatrick << NumParamsExpr->getSourceRange();
7396a0747c9fSpatrick return;
7397a0747c9fSpatrick }
7398a0747c9fSpatrick
7399a0747c9fSpatrick D->addAttr(::new (S.Context) M68kInterruptAttr(S.Context, AL, Num));
7400a0747c9fSpatrick D->addAttr(UsedAttr::CreateImplicit(S.Context));
7401a0747c9fSpatrick }
7402a0747c9fSpatrick
handleAnyX86InterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7403e5dd7070Spatrick static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7404e5dd7070Spatrick // Semantic checks for a function with the 'interrupt' attribute.
7405e5dd7070Spatrick // a) Must be a function.
7406e5dd7070Spatrick // b) Must have the 'void' return type.
7407e5dd7070Spatrick // c) Must take 1 or 2 arguments.
7408e5dd7070Spatrick // d) The 1st argument must be a pointer.
7409e5dd7070Spatrick // e) The 2nd argument (if any) must be an unsigned integer.
7410e5dd7070Spatrick if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
7411e5dd7070Spatrick CXXMethodDecl::isStaticOverloadedOperator(
7412e5dd7070Spatrick cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
7413e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
7414e5dd7070Spatrick << AL << ExpectedFunctionWithProtoType;
7415e5dd7070Spatrick return;
7416e5dd7070Spatrick }
7417e5dd7070Spatrick // Interrupt handler must have void return type.
7418e5dd7070Spatrick if (!getFunctionOrMethodResultType(D)->isVoidType()) {
7419e5dd7070Spatrick S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
7420e5dd7070Spatrick diag::err_anyx86_interrupt_attribute)
7421e5dd7070Spatrick << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
7422e5dd7070Spatrick ? 0
7423e5dd7070Spatrick : 1)
7424e5dd7070Spatrick << 0;
7425e5dd7070Spatrick return;
7426e5dd7070Spatrick }
7427e5dd7070Spatrick // Interrupt handler must have 1 or 2 parameters.
7428e5dd7070Spatrick unsigned NumParams = getFunctionOrMethodNumParams(D);
7429e5dd7070Spatrick if (NumParams < 1 || NumParams > 2) {
7430e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute)
7431e5dd7070Spatrick << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
7432e5dd7070Spatrick ? 0
7433e5dd7070Spatrick : 1)
7434e5dd7070Spatrick << 1;
7435e5dd7070Spatrick return;
7436e5dd7070Spatrick }
7437e5dd7070Spatrick // The first argument must be a pointer.
7438e5dd7070Spatrick if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
7439e5dd7070Spatrick S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
7440e5dd7070Spatrick diag::err_anyx86_interrupt_attribute)
7441e5dd7070Spatrick << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
7442e5dd7070Spatrick ? 0
7443e5dd7070Spatrick : 1)
7444e5dd7070Spatrick << 2;
7445e5dd7070Spatrick return;
7446e5dd7070Spatrick }
7447e5dd7070Spatrick // The second argument, if present, must be an unsigned integer.
7448e5dd7070Spatrick unsigned TypeSize =
7449e5dd7070Spatrick S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
7450e5dd7070Spatrick ? 64
7451e5dd7070Spatrick : 32;
7452e5dd7070Spatrick if (NumParams == 2 &&
7453e5dd7070Spatrick (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
7454e5dd7070Spatrick S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
7455e5dd7070Spatrick S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
7456e5dd7070Spatrick diag::err_anyx86_interrupt_attribute)
7457e5dd7070Spatrick << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
7458e5dd7070Spatrick ? 0
7459e5dd7070Spatrick : 1)
7460e5dd7070Spatrick << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
7461e5dd7070Spatrick return;
7462e5dd7070Spatrick }
7463e5dd7070Spatrick D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL));
7464e5dd7070Spatrick D->addAttr(UsedAttr::CreateImplicit(S.Context));
7465e5dd7070Spatrick }
7466e5dd7070Spatrick
handleAVRInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7467e5dd7070Spatrick static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7468e5dd7070Spatrick if (!isFunctionOrMethod(D)) {
7469e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7470e5dd7070Spatrick << "'interrupt'" << ExpectedFunction;
7471e5dd7070Spatrick return;
7472e5dd7070Spatrick }
7473e5dd7070Spatrick
7474a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 0))
7475e5dd7070Spatrick return;
7476e5dd7070Spatrick
7477e5dd7070Spatrick handleSimpleAttribute<AVRInterruptAttr>(S, D, AL);
7478e5dd7070Spatrick }
7479e5dd7070Spatrick
handleAVRSignalAttr(Sema & S,Decl * D,const ParsedAttr & AL)7480e5dd7070Spatrick static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7481e5dd7070Spatrick if (!isFunctionOrMethod(D)) {
7482e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7483e5dd7070Spatrick << "'signal'" << ExpectedFunction;
7484e5dd7070Spatrick return;
7485e5dd7070Spatrick }
7486e5dd7070Spatrick
7487a0747c9fSpatrick if (!AL.checkExactlyNumArgs(S, 0))
7488e5dd7070Spatrick return;
7489e5dd7070Spatrick
7490e5dd7070Spatrick handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
7491e5dd7070Spatrick }
7492e5dd7070Spatrick
handleBPFPreserveAIRecord(Sema & S,RecordDecl * RD)7493e5dd7070Spatrick static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
7494e5dd7070Spatrick // Add preserve_access_index attribute to all fields and inner records.
7495*7a9b00ceSrobert for (auto *D : RD->decls()) {
7496e5dd7070Spatrick if (D->hasAttr<BPFPreserveAccessIndexAttr>())
7497e5dd7070Spatrick continue;
7498e5dd7070Spatrick
7499e5dd7070Spatrick D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context));
7500e5dd7070Spatrick if (auto *Rec = dyn_cast<RecordDecl>(D))
7501e5dd7070Spatrick handleBPFPreserveAIRecord(S, Rec);
7502e5dd7070Spatrick }
7503e5dd7070Spatrick }
7504e5dd7070Spatrick
handleBPFPreserveAccessIndexAttr(Sema & S,Decl * D,const ParsedAttr & AL)7505e5dd7070Spatrick static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,
7506e5dd7070Spatrick const ParsedAttr &AL) {
7507e5dd7070Spatrick auto *Rec = cast<RecordDecl>(D);
7508e5dd7070Spatrick handleBPFPreserveAIRecord(S, Rec);
7509e5dd7070Spatrick Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));
7510e5dd7070Spatrick }
7511e5dd7070Spatrick
hasBTFDeclTagAttr(Decl * D,StringRef Tag)7512*7a9b00ceSrobert static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) {
7513*7a9b00ceSrobert for (const auto *I : D->specific_attrs<BTFDeclTagAttr>()) {
7514*7a9b00ceSrobert if (I->getBTFDeclTag() == Tag)
7515*7a9b00ceSrobert return true;
7516*7a9b00ceSrobert }
7517*7a9b00ceSrobert return false;
7518*7a9b00ceSrobert }
7519*7a9b00ceSrobert
handleBTFDeclTagAttr(Sema & S,Decl * D,const ParsedAttr & AL)7520*7a9b00ceSrobert static void handleBTFDeclTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7521*7a9b00ceSrobert StringRef Str;
7522*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
7523*7a9b00ceSrobert return;
7524*7a9b00ceSrobert if (hasBTFDeclTagAttr(D, Str))
7525*7a9b00ceSrobert return;
7526*7a9b00ceSrobert
7527*7a9b00ceSrobert D->addAttr(::new (S.Context) BTFDeclTagAttr(S.Context, AL, Str));
7528*7a9b00ceSrobert }
7529*7a9b00ceSrobert
mergeBTFDeclTagAttr(Decl * D,const BTFDeclTagAttr & AL)7530*7a9b00ceSrobert BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) {
7531*7a9b00ceSrobert if (hasBTFDeclTagAttr(D, AL.getBTFDeclTag()))
7532*7a9b00ceSrobert return nullptr;
7533*7a9b00ceSrobert return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag());
7534*7a9b00ceSrobert }
7535*7a9b00ceSrobert
handleWebAssemblyExportNameAttr(Sema & S,Decl * D,const ParsedAttr & AL)7536e5dd7070Spatrick static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7537e5dd7070Spatrick if (!isFunctionOrMethod(D)) {
7538e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7539e5dd7070Spatrick << "'export_name'" << ExpectedFunction;
7540e5dd7070Spatrick return;
7541e5dd7070Spatrick }
7542e5dd7070Spatrick
7543e5dd7070Spatrick auto *FD = cast<FunctionDecl>(D);
7544e5dd7070Spatrick if (FD->isThisDeclarationADefinition()) {
7545e5dd7070Spatrick S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
7546e5dd7070Spatrick return;
7547e5dd7070Spatrick }
7548e5dd7070Spatrick
7549e5dd7070Spatrick StringRef Str;
7550e5dd7070Spatrick SourceLocation ArgLoc;
7551e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7552e5dd7070Spatrick return;
7553e5dd7070Spatrick
7554e5dd7070Spatrick D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str));
7555e5dd7070Spatrick D->addAttr(UsedAttr::CreateImplicit(S.Context));
7556e5dd7070Spatrick }
7557e5dd7070Spatrick
7558ec727ea7Spatrick WebAssemblyImportModuleAttr *
mergeImportModuleAttr(Decl * D,const WebAssemblyImportModuleAttr & AL)7559ec727ea7Spatrick Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) {
7560ec727ea7Spatrick auto *FD = cast<FunctionDecl>(D);
7561ec727ea7Spatrick
7562ec727ea7Spatrick if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
7563ec727ea7Spatrick if (ExistingAttr->getImportModule() == AL.getImportModule())
7564ec727ea7Spatrick return nullptr;
7565ec727ea7Spatrick Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0
7566ec727ea7Spatrick << ExistingAttr->getImportModule() << AL.getImportModule();
7567ec727ea7Spatrick Diag(AL.getLoc(), diag::note_previous_attribute);
7568ec727ea7Spatrick return nullptr;
7569ec727ea7Spatrick }
7570ec727ea7Spatrick if (FD->hasBody()) {
7571ec727ea7Spatrick Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
7572ec727ea7Spatrick return nullptr;
7573ec727ea7Spatrick }
7574ec727ea7Spatrick return ::new (Context) WebAssemblyImportModuleAttr(Context, AL,
7575ec727ea7Spatrick AL.getImportModule());
7576e5dd7070Spatrick }
7577e5dd7070Spatrick
7578ec727ea7Spatrick WebAssemblyImportNameAttr *
mergeImportNameAttr(Decl * D,const WebAssemblyImportNameAttr & AL)7579ec727ea7Spatrick Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
7580e5dd7070Spatrick auto *FD = cast<FunctionDecl>(D);
7581ec727ea7Spatrick
7582ec727ea7Spatrick if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
7583ec727ea7Spatrick if (ExistingAttr->getImportName() == AL.getImportName())
7584ec727ea7Spatrick return nullptr;
7585ec727ea7Spatrick Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1
7586ec727ea7Spatrick << ExistingAttr->getImportName() << AL.getImportName();
7587ec727ea7Spatrick Diag(AL.getLoc(), diag::note_previous_attribute);
7588ec727ea7Spatrick return nullptr;
7589e5dd7070Spatrick }
7590ec727ea7Spatrick if (FD->hasBody()) {
7591ec727ea7Spatrick Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
7592ec727ea7Spatrick return nullptr;
7593ec727ea7Spatrick }
7594ec727ea7Spatrick return ::new (Context) WebAssemblyImportNameAttr(Context, AL,
7595ec727ea7Spatrick AL.getImportName());
7596ec727ea7Spatrick }
7597ec727ea7Spatrick
7598ec727ea7Spatrick static void
handleWebAssemblyImportModuleAttr(Sema & S,Decl * D,const ParsedAttr & AL)7599ec727ea7Spatrick handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7600ec727ea7Spatrick auto *FD = cast<FunctionDecl>(D);
7601e5dd7070Spatrick
7602e5dd7070Spatrick StringRef Str;
7603e5dd7070Spatrick SourceLocation ArgLoc;
7604e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7605e5dd7070Spatrick return;
7606ec727ea7Spatrick if (FD->hasBody()) {
7607ec727ea7Spatrick S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
7608ec727ea7Spatrick return;
7609ec727ea7Spatrick }
7610e5dd7070Spatrick
7611e5dd7070Spatrick FD->addAttr(::new (S.Context)
7612e5dd7070Spatrick WebAssemblyImportModuleAttr(S.Context, AL, Str));
7613e5dd7070Spatrick }
7614e5dd7070Spatrick
7615ec727ea7Spatrick static void
handleWebAssemblyImportNameAttr(Sema & S,Decl * D,const ParsedAttr & AL)7616ec727ea7Spatrick handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7617e5dd7070Spatrick auto *FD = cast<FunctionDecl>(D);
7618e5dd7070Spatrick
7619e5dd7070Spatrick StringRef Str;
7620e5dd7070Spatrick SourceLocation ArgLoc;
7621e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7622e5dd7070Spatrick return;
7623ec727ea7Spatrick if (FD->hasBody()) {
7624ec727ea7Spatrick S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
7625ec727ea7Spatrick return;
7626ec727ea7Spatrick }
7627e5dd7070Spatrick
7628e5dd7070Spatrick FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
7629e5dd7070Spatrick }
7630e5dd7070Spatrick
handleRISCVInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7631e5dd7070Spatrick static void handleRISCVInterruptAttr(Sema &S, Decl *D,
7632e5dd7070Spatrick const ParsedAttr &AL) {
7633e5dd7070Spatrick // Warn about repeated attributes.
7634e5dd7070Spatrick if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
7635e5dd7070Spatrick S.Diag(AL.getRange().getBegin(),
7636e5dd7070Spatrick diag::warn_riscv_repeated_interrupt_attribute);
7637e5dd7070Spatrick S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
7638e5dd7070Spatrick return;
7639e5dd7070Spatrick }
7640e5dd7070Spatrick
7641e5dd7070Spatrick // Check the attribute argument. Argument is optional.
7642a0747c9fSpatrick if (!AL.checkAtMostNumArgs(S, 1))
7643e5dd7070Spatrick return;
7644e5dd7070Spatrick
7645e5dd7070Spatrick StringRef Str;
7646e5dd7070Spatrick SourceLocation ArgLoc;
7647e5dd7070Spatrick
7648e5dd7070Spatrick // 'machine'is the default interrupt mode.
7649e5dd7070Spatrick if (AL.getNumArgs() == 0)
7650e5dd7070Spatrick Str = "machine";
7651e5dd7070Spatrick else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
7652e5dd7070Spatrick return;
7653e5dd7070Spatrick
7654e5dd7070Spatrick // Semantic checks for a function with the 'interrupt' attribute:
7655e5dd7070Spatrick // - Must be a function.
7656e5dd7070Spatrick // - Must have no parameters.
7657e5dd7070Spatrick // - Must have the 'void' return type.
7658e5dd7070Spatrick // - The attribute itself must either have no argument or one of the
7659e5dd7070Spatrick // valid interrupt types, see [RISCVInterruptDocs].
7660e5dd7070Spatrick
7661e5dd7070Spatrick if (D->getFunctionType() == nullptr) {
7662e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
7663e5dd7070Spatrick << "'interrupt'" << ExpectedFunction;
7664e5dd7070Spatrick return;
7665e5dd7070Spatrick }
7666e5dd7070Spatrick
7667e5dd7070Spatrick if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
7668e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7669e5dd7070Spatrick << /*RISC-V*/ 2 << 0;
7670e5dd7070Spatrick return;
7671e5dd7070Spatrick }
7672e5dd7070Spatrick
7673e5dd7070Spatrick if (!getFunctionOrMethodResultType(D)->isVoidType()) {
7674e5dd7070Spatrick S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
7675e5dd7070Spatrick << /*RISC-V*/ 2 << 1;
7676e5dd7070Spatrick return;
7677e5dd7070Spatrick }
7678e5dd7070Spatrick
7679e5dd7070Spatrick RISCVInterruptAttr::InterruptType Kind;
7680e5dd7070Spatrick if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
7681e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
7682e5dd7070Spatrick << ArgLoc;
7683e5dd7070Spatrick return;
7684e5dd7070Spatrick }
7685e5dd7070Spatrick
7686e5dd7070Spatrick D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind));
7687e5dd7070Spatrick }
7688e5dd7070Spatrick
handleInterruptAttr(Sema & S,Decl * D,const ParsedAttr & AL)7689e5dd7070Spatrick static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7690e5dd7070Spatrick // Dispatch the interrupt attribute based on the current target.
7691e5dd7070Spatrick switch (S.Context.getTargetInfo().getTriple().getArch()) {
7692e5dd7070Spatrick case llvm::Triple::msp430:
7693e5dd7070Spatrick handleMSP430InterruptAttr(S, D, AL);
7694e5dd7070Spatrick break;
7695e5dd7070Spatrick case llvm::Triple::mipsel:
7696e5dd7070Spatrick case llvm::Triple::mips:
7697e5dd7070Spatrick handleMipsInterruptAttr(S, D, AL);
7698e5dd7070Spatrick break;
7699a0747c9fSpatrick case llvm::Triple::m68k:
7700a0747c9fSpatrick handleM68kInterruptAttr(S, D, AL);
7701a0747c9fSpatrick break;
7702e5dd7070Spatrick case llvm::Triple::x86:
7703e5dd7070Spatrick case llvm::Triple::x86_64:
7704e5dd7070Spatrick handleAnyX86InterruptAttr(S, D, AL);
7705e5dd7070Spatrick break;
7706e5dd7070Spatrick case llvm::Triple::avr:
7707e5dd7070Spatrick handleAVRInterruptAttr(S, D, AL);
7708e5dd7070Spatrick break;
7709e5dd7070Spatrick case llvm::Triple::riscv32:
7710e5dd7070Spatrick case llvm::Triple::riscv64:
7711e5dd7070Spatrick handleRISCVInterruptAttr(S, D, AL);
7712e5dd7070Spatrick break;
7713e5dd7070Spatrick default:
7714e5dd7070Spatrick handleARMInterruptAttr(S, D, AL);
7715e5dd7070Spatrick break;
7716e5dd7070Spatrick }
7717e5dd7070Spatrick }
7718e5dd7070Spatrick
7719e5dd7070Spatrick static bool
checkAMDGPUFlatWorkGroupSizeArguments(Sema & S,Expr * MinExpr,Expr * MaxExpr,const AMDGPUFlatWorkGroupSizeAttr & Attr)7720e5dd7070Spatrick checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
7721e5dd7070Spatrick const AMDGPUFlatWorkGroupSizeAttr &Attr) {
7722e5dd7070Spatrick // Accept template arguments for now as they depend on something else.
7723e5dd7070Spatrick // We'll get to check them when they eventually get instantiated.
7724e5dd7070Spatrick if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
7725e5dd7070Spatrick return false;
7726e5dd7070Spatrick
7727e5dd7070Spatrick uint32_t Min = 0;
7728e5dd7070Spatrick if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
7729e5dd7070Spatrick return true;
7730e5dd7070Spatrick
7731e5dd7070Spatrick uint32_t Max = 0;
7732e5dd7070Spatrick if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
7733e5dd7070Spatrick return true;
7734e5dd7070Spatrick
7735e5dd7070Spatrick if (Min == 0 && Max != 0) {
7736e5dd7070Spatrick S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
7737e5dd7070Spatrick << &Attr << 0;
7738e5dd7070Spatrick return true;
7739e5dd7070Spatrick }
7740e5dd7070Spatrick if (Min > Max) {
7741e5dd7070Spatrick S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
7742e5dd7070Spatrick << &Attr << 1;
7743e5dd7070Spatrick return true;
7744e5dd7070Spatrick }
7745e5dd7070Spatrick
7746e5dd7070Spatrick return false;
7747e5dd7070Spatrick }
7748e5dd7070Spatrick
addAMDGPUFlatWorkGroupSizeAttr(Decl * D,const AttributeCommonInfo & CI,Expr * MinExpr,Expr * MaxExpr)7749e5dd7070Spatrick void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
7750e5dd7070Spatrick const AttributeCommonInfo &CI,
7751e5dd7070Spatrick Expr *MinExpr, Expr *MaxExpr) {
7752e5dd7070Spatrick AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
7753e5dd7070Spatrick
7754e5dd7070Spatrick if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
7755e5dd7070Spatrick return;
7756e5dd7070Spatrick
7757e5dd7070Spatrick D->addAttr(::new (Context)
7758e5dd7070Spatrick AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr));
7759e5dd7070Spatrick }
7760e5dd7070Spatrick
handleAMDGPUFlatWorkGroupSizeAttr(Sema & S,Decl * D,const ParsedAttr & AL)7761e5dd7070Spatrick static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
7762e5dd7070Spatrick const ParsedAttr &AL) {
7763e5dd7070Spatrick Expr *MinExpr = AL.getArgAsExpr(0);
7764e5dd7070Spatrick Expr *MaxExpr = AL.getArgAsExpr(1);
7765e5dd7070Spatrick
7766e5dd7070Spatrick S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
7767e5dd7070Spatrick }
7768e5dd7070Spatrick
checkAMDGPUWavesPerEUArguments(Sema & S,Expr * MinExpr,Expr * MaxExpr,const AMDGPUWavesPerEUAttr & Attr)7769e5dd7070Spatrick static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
7770e5dd7070Spatrick Expr *MaxExpr,
7771e5dd7070Spatrick const AMDGPUWavesPerEUAttr &Attr) {
7772e5dd7070Spatrick if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
7773e5dd7070Spatrick (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
7774e5dd7070Spatrick return true;
7775e5dd7070Spatrick
7776e5dd7070Spatrick // Accept template arguments for now as they depend on something else.
7777e5dd7070Spatrick // We'll get to check them when they eventually get instantiated.
7778e5dd7070Spatrick if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
7779e5dd7070Spatrick return false;
7780e5dd7070Spatrick
7781e5dd7070Spatrick uint32_t Min = 0;
7782e5dd7070Spatrick if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
7783e5dd7070Spatrick return true;
7784e5dd7070Spatrick
7785e5dd7070Spatrick uint32_t Max = 0;
7786e5dd7070Spatrick if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
7787e5dd7070Spatrick return true;
7788e5dd7070Spatrick
7789e5dd7070Spatrick if (Min == 0 && Max != 0) {
7790e5dd7070Spatrick S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
7791e5dd7070Spatrick << &Attr << 0;
7792e5dd7070Spatrick return true;
7793e5dd7070Spatrick }
7794e5dd7070Spatrick if (Max != 0 && Min > Max) {
7795e5dd7070Spatrick S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
7796e5dd7070Spatrick << &Attr << 1;
7797e5dd7070Spatrick return true;
7798e5dd7070Spatrick }
7799e5dd7070Spatrick
7800e5dd7070Spatrick return false;
7801e5dd7070Spatrick }
7802e5dd7070Spatrick
addAMDGPUWavesPerEUAttr(Decl * D,const AttributeCommonInfo & CI,Expr * MinExpr,Expr * MaxExpr)7803e5dd7070Spatrick void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
7804e5dd7070Spatrick Expr *MinExpr, Expr *MaxExpr) {
7805e5dd7070Spatrick AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
7806e5dd7070Spatrick
7807e5dd7070Spatrick if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
7808e5dd7070Spatrick return;
7809e5dd7070Spatrick
7810e5dd7070Spatrick D->addAttr(::new (Context)
7811e5dd7070Spatrick AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr));
7812e5dd7070Spatrick }
7813e5dd7070Spatrick
handleAMDGPUWavesPerEUAttr(Sema & S,Decl * D,const ParsedAttr & AL)7814e5dd7070Spatrick static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7815a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
7816e5dd7070Spatrick return;
7817e5dd7070Spatrick
7818e5dd7070Spatrick Expr *MinExpr = AL.getArgAsExpr(0);
7819e5dd7070Spatrick Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
7820e5dd7070Spatrick
7821e5dd7070Spatrick S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
7822e5dd7070Spatrick }
7823e5dd7070Spatrick
handleAMDGPUNumSGPRAttr(Sema & S,Decl * D,const ParsedAttr & AL)7824e5dd7070Spatrick static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7825e5dd7070Spatrick uint32_t NumSGPR = 0;
7826e5dd7070Spatrick Expr *NumSGPRExpr = AL.getArgAsExpr(0);
7827e5dd7070Spatrick if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR))
7828e5dd7070Spatrick return;
7829e5dd7070Spatrick
7830e5dd7070Spatrick D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR));
7831e5dd7070Spatrick }
7832e5dd7070Spatrick
handleAMDGPUNumVGPRAttr(Sema & S,Decl * D,const ParsedAttr & AL)7833e5dd7070Spatrick static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7834e5dd7070Spatrick uint32_t NumVGPR = 0;
7835e5dd7070Spatrick Expr *NumVGPRExpr = AL.getArgAsExpr(0);
7836e5dd7070Spatrick if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR))
7837e5dd7070Spatrick return;
7838e5dd7070Spatrick
7839e5dd7070Spatrick D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR));
7840e5dd7070Spatrick }
7841e5dd7070Spatrick
handleX86ForceAlignArgPointerAttr(Sema & S,Decl * D,const ParsedAttr & AL)7842e5dd7070Spatrick static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
7843e5dd7070Spatrick const ParsedAttr &AL) {
7844e5dd7070Spatrick // If we try to apply it to a function pointer, don't warn, but don't
7845e5dd7070Spatrick // do anything, either. It doesn't matter anyway, because there's nothing
7846e5dd7070Spatrick // special about calling a force_align_arg_pointer function.
7847e5dd7070Spatrick const auto *VD = dyn_cast<ValueDecl>(D);
7848e5dd7070Spatrick if (VD && VD->getType()->isFunctionPointerType())
7849e5dd7070Spatrick return;
7850e5dd7070Spatrick // Also don't warn on function pointer typedefs.
7851e5dd7070Spatrick const auto *TD = dyn_cast<TypedefNameDecl>(D);
7852e5dd7070Spatrick if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
7853e5dd7070Spatrick TD->getUnderlyingType()->isFunctionType()))
7854e5dd7070Spatrick return;
7855e5dd7070Spatrick // Attribute can only be applied to function types.
7856e5dd7070Spatrick if (!isa<FunctionDecl>(D)) {
7857e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
7858e5dd7070Spatrick << AL << ExpectedFunction;
7859e5dd7070Spatrick return;
7860e5dd7070Spatrick }
7861e5dd7070Spatrick
7862e5dd7070Spatrick D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL));
7863e5dd7070Spatrick }
7864e5dd7070Spatrick
handleLayoutVersion(Sema & S,Decl * D,const ParsedAttr & AL)7865e5dd7070Spatrick static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
7866e5dd7070Spatrick uint32_t Version;
7867e5dd7070Spatrick Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
7868e5dd7070Spatrick if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version))
7869e5dd7070Spatrick return;
7870e5dd7070Spatrick
7871e5dd7070Spatrick // TODO: Investigate what happens with the next major version of MSVC.
7872e5dd7070Spatrick if (Version != LangOptions::MSVC2015 / 100) {
7873e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
7874e5dd7070Spatrick << AL << Version << VersionExpr->getSourceRange();
7875e5dd7070Spatrick return;
7876e5dd7070Spatrick }
7877e5dd7070Spatrick
7878e5dd7070Spatrick // The attribute expects a "major" version number like 19, but new versions of
7879e5dd7070Spatrick // MSVC have moved to updating the "minor", or less significant numbers, so we
7880e5dd7070Spatrick // have to multiply by 100 now.
7881e5dd7070Spatrick Version *= 100;
7882e5dd7070Spatrick
7883e5dd7070Spatrick D->addAttr(::new (S.Context) LayoutVersionAttr(S.Context, AL, Version));
7884e5dd7070Spatrick }
7885e5dd7070Spatrick
mergeDLLImportAttr(Decl * D,const AttributeCommonInfo & CI)7886e5dd7070Spatrick DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D,
7887e5dd7070Spatrick const AttributeCommonInfo &CI) {
7888e5dd7070Spatrick if (D->hasAttr<DLLExportAttr>()) {
7889e5dd7070Spatrick Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'dllimport'";
7890e5dd7070Spatrick return nullptr;
7891e5dd7070Spatrick }
7892e5dd7070Spatrick
7893e5dd7070Spatrick if (D->hasAttr<DLLImportAttr>())
7894e5dd7070Spatrick return nullptr;
7895e5dd7070Spatrick
7896e5dd7070Spatrick return ::new (Context) DLLImportAttr(Context, CI);
7897e5dd7070Spatrick }
7898e5dd7070Spatrick
mergeDLLExportAttr(Decl * D,const AttributeCommonInfo & CI)7899e5dd7070Spatrick DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
7900e5dd7070Spatrick const AttributeCommonInfo &CI) {
7901e5dd7070Spatrick if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
7902e5dd7070Spatrick Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import;
7903e5dd7070Spatrick D->dropAttr<DLLImportAttr>();
7904e5dd7070Spatrick }
7905e5dd7070Spatrick
7906e5dd7070Spatrick if (D->hasAttr<DLLExportAttr>())
7907e5dd7070Spatrick return nullptr;
7908e5dd7070Spatrick
7909e5dd7070Spatrick return ::new (Context) DLLExportAttr(Context, CI);
7910e5dd7070Spatrick }
7911e5dd7070Spatrick
handleDLLAttr(Sema & S,Decl * D,const ParsedAttr & A)7912e5dd7070Spatrick static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
7913e5dd7070Spatrick if (isa<ClassTemplatePartialSpecializationDecl>(D) &&
7914a0747c9fSpatrick (S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) {
7915e5dd7070Spatrick S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A;
7916e5dd7070Spatrick return;
7917e5dd7070Spatrick }
7918e5dd7070Spatrick
7919e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
7920e5dd7070Spatrick if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport &&
7921a0747c9fSpatrick !(S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) {
7922e5dd7070Spatrick // MinGW doesn't allow dllimport on inline functions.
7923e5dd7070Spatrick S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
7924e5dd7070Spatrick << A;
7925e5dd7070Spatrick return;
7926e5dd7070Spatrick }
7927e5dd7070Spatrick }
7928e5dd7070Spatrick
7929e5dd7070Spatrick if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
7930a0747c9fSpatrick if ((S.Context.getTargetInfo().shouldDLLImportComdatSymbols()) &&
7931e5dd7070Spatrick MD->getParent()->isLambda()) {
7932e5dd7070Spatrick S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A;
7933e5dd7070Spatrick return;
7934e5dd7070Spatrick }
7935e5dd7070Spatrick }
7936e5dd7070Spatrick
7937e5dd7070Spatrick Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport
7938e5dd7070Spatrick ? (Attr *)S.mergeDLLExportAttr(D, A)
7939e5dd7070Spatrick : (Attr *)S.mergeDLLImportAttr(D, A);
7940e5dd7070Spatrick if (NewAttr)
7941e5dd7070Spatrick D->addAttr(NewAttr);
7942e5dd7070Spatrick }
7943e5dd7070Spatrick
7944e5dd7070Spatrick MSInheritanceAttr *
mergeMSInheritanceAttr(Decl * D,const AttributeCommonInfo & CI,bool BestCase,MSInheritanceModel Model)7945e5dd7070Spatrick Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
7946e5dd7070Spatrick bool BestCase,
7947e5dd7070Spatrick MSInheritanceModel Model) {
7948e5dd7070Spatrick if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
7949e5dd7070Spatrick if (IA->getInheritanceModel() == Model)
7950e5dd7070Spatrick return nullptr;
7951e5dd7070Spatrick Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
7952e5dd7070Spatrick << 1 /*previous declaration*/;
7953e5dd7070Spatrick Diag(CI.getLoc(), diag::note_previous_ms_inheritance);
7954e5dd7070Spatrick D->dropAttr<MSInheritanceAttr>();
7955e5dd7070Spatrick }
7956e5dd7070Spatrick
7957e5dd7070Spatrick auto *RD = cast<CXXRecordDecl>(D);
7958e5dd7070Spatrick if (RD->hasDefinition()) {
7959e5dd7070Spatrick if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
7960e5dd7070Spatrick Model)) {
7961e5dd7070Spatrick return nullptr;
7962e5dd7070Spatrick }
7963e5dd7070Spatrick } else {
7964e5dd7070Spatrick if (isa<ClassTemplatePartialSpecializationDecl>(RD)) {
7965e5dd7070Spatrick Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
7966e5dd7070Spatrick << 1 /*partial specialization*/;
7967e5dd7070Spatrick return nullptr;
7968e5dd7070Spatrick }
7969e5dd7070Spatrick if (RD->getDescribedClassTemplate()) {
7970e5dd7070Spatrick Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
7971e5dd7070Spatrick << 0 /*primary template*/;
7972e5dd7070Spatrick return nullptr;
7973e5dd7070Spatrick }
7974e5dd7070Spatrick }
7975e5dd7070Spatrick
7976e5dd7070Spatrick return ::new (Context) MSInheritanceAttr(Context, CI, BestCase);
7977e5dd7070Spatrick }
7978e5dd7070Spatrick
handleCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)7979e5dd7070Spatrick static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7980e5dd7070Spatrick // The capability attributes take a single string parameter for the name of
7981e5dd7070Spatrick // the capability they represent. The lockable attribute does not take any
7982e5dd7070Spatrick // parameters. However, semantically, both attributes represent the same
7983e5dd7070Spatrick // concept, and so they use the same semantic attribute. Eventually, the
7984e5dd7070Spatrick // lockable attribute will be removed.
7985e5dd7070Spatrick //
7986e5dd7070Spatrick // For backward compatibility, any capability which has no specified string
7987e5dd7070Spatrick // literal will be considered a "mutex."
7988e5dd7070Spatrick StringRef N("mutex");
7989e5dd7070Spatrick SourceLocation LiteralLoc;
7990e5dd7070Spatrick if (AL.getKind() == ParsedAttr::AT_Capability &&
7991e5dd7070Spatrick !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc))
7992e5dd7070Spatrick return;
7993e5dd7070Spatrick
7994e5dd7070Spatrick D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N));
7995e5dd7070Spatrick }
7996e5dd7070Spatrick
handleAssertCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)7997e5dd7070Spatrick static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
7998e5dd7070Spatrick SmallVector<Expr*, 1> Args;
7999e5dd7070Spatrick if (!checkLockFunAttrCommon(S, D, AL, Args))
8000e5dd7070Spatrick return;
8001e5dd7070Spatrick
8002e5dd7070Spatrick D->addAttr(::new (S.Context)
8003e5dd7070Spatrick AssertCapabilityAttr(S.Context, AL, Args.data(), Args.size()));
8004e5dd7070Spatrick }
8005e5dd7070Spatrick
handleAcquireCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)8006e5dd7070Spatrick static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
8007e5dd7070Spatrick const ParsedAttr &AL) {
8008e5dd7070Spatrick SmallVector<Expr*, 1> Args;
8009e5dd7070Spatrick if (!checkLockFunAttrCommon(S, D, AL, Args))
8010e5dd7070Spatrick return;
8011e5dd7070Spatrick
8012e5dd7070Spatrick D->addAttr(::new (S.Context) AcquireCapabilityAttr(S.Context, AL, Args.data(),
8013e5dd7070Spatrick Args.size()));
8014e5dd7070Spatrick }
8015e5dd7070Spatrick
handleTryAcquireCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)8016e5dd7070Spatrick static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
8017e5dd7070Spatrick const ParsedAttr &AL) {
8018e5dd7070Spatrick SmallVector<Expr*, 2> Args;
8019e5dd7070Spatrick if (!checkTryLockFunAttrCommon(S, D, AL, Args))
8020e5dd7070Spatrick return;
8021e5dd7070Spatrick
8022e5dd7070Spatrick D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(
8023e5dd7070Spatrick S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
8024e5dd7070Spatrick }
8025e5dd7070Spatrick
handleReleaseCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)8026e5dd7070Spatrick static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
8027e5dd7070Spatrick const ParsedAttr &AL) {
8028e5dd7070Spatrick // Check that all arguments are lockable objects.
8029e5dd7070Spatrick SmallVector<Expr *, 1> Args;
8030e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true);
8031e5dd7070Spatrick
8032e5dd7070Spatrick D->addAttr(::new (S.Context) ReleaseCapabilityAttr(S.Context, AL, Args.data(),
8033e5dd7070Spatrick Args.size()));
8034e5dd7070Spatrick }
8035e5dd7070Spatrick
handleRequiresCapabilityAttr(Sema & S,Decl * D,const ParsedAttr & AL)8036e5dd7070Spatrick static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
8037e5dd7070Spatrick const ParsedAttr &AL) {
8038a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
8039e5dd7070Spatrick return;
8040e5dd7070Spatrick
8041e5dd7070Spatrick // check that all arguments are lockable objects
8042e5dd7070Spatrick SmallVector<Expr*, 1> Args;
8043e5dd7070Spatrick checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
8044e5dd7070Spatrick if (Args.empty())
8045e5dd7070Spatrick return;
8046e5dd7070Spatrick
8047e5dd7070Spatrick RequiresCapabilityAttr *RCA = ::new (S.Context)
8048e5dd7070Spatrick RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size());
8049e5dd7070Spatrick
8050e5dd7070Spatrick D->addAttr(RCA);
8051e5dd7070Spatrick }
8052e5dd7070Spatrick
handleDeprecatedAttr(Sema & S,Decl * D,const ParsedAttr & AL)8053e5dd7070Spatrick static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8054e5dd7070Spatrick if (const auto *NSD = dyn_cast<NamespaceDecl>(D)) {
8055e5dd7070Spatrick if (NSD->isAnonymousNamespace()) {
8056e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_deprecated_anonymous_namespace);
8057e5dd7070Spatrick // Do not want to attach the attribute to the namespace because that will
8058e5dd7070Spatrick // cause confusing diagnostic reports for uses of declarations within the
8059e5dd7070Spatrick // namespace.
8060e5dd7070Spatrick return;
8061e5dd7070Spatrick }
8062a0747c9fSpatrick } else if (isa<UsingDecl, UnresolvedUsingTypenameDecl,
8063a0747c9fSpatrick UnresolvedUsingValueDecl>(D)) {
8064a0747c9fSpatrick S.Diag(AL.getRange().getBegin(), diag::warn_deprecated_ignored_on_using)
8065a0747c9fSpatrick << AL;
8066a0747c9fSpatrick return;
8067e5dd7070Spatrick }
8068e5dd7070Spatrick
8069e5dd7070Spatrick // Handle the cases where the attribute has a text message.
8070e5dd7070Spatrick StringRef Str, Replacement;
8071e5dd7070Spatrick if (AL.isArgExpr(0) && AL.getArgAsExpr(0) &&
8072e5dd7070Spatrick !S.checkStringLiteralArgumentAttr(AL, 0, Str))
8073e5dd7070Spatrick return;
8074e5dd7070Spatrick
8075a0747c9fSpatrick // Support a single optional message only for Declspec and [[]] spellings.
8076a0747c9fSpatrick if (AL.isDeclspecAttribute() || AL.isStandardAttributeSyntax())
8077a0747c9fSpatrick AL.checkAtMostNumArgs(S, 1);
8078e5dd7070Spatrick else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) &&
8079e5dd7070Spatrick !S.checkStringLiteralArgumentAttr(AL, 1, Replacement))
8080e5dd7070Spatrick return;
8081e5dd7070Spatrick
8082e5dd7070Spatrick if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
8083e5dd7070Spatrick S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
8084e5dd7070Spatrick
8085e5dd7070Spatrick D->addAttr(::new (S.Context) DeprecatedAttr(S.Context, AL, Str, Replacement));
8086e5dd7070Spatrick }
8087e5dd7070Spatrick
isGlobalVar(const Decl * D)8088e5dd7070Spatrick static bool isGlobalVar(const Decl *D) {
8089e5dd7070Spatrick if (const auto *S = dyn_cast<VarDecl>(D))
8090e5dd7070Spatrick return S->hasGlobalStorage();
8091e5dd7070Spatrick return false;
8092e5dd7070Spatrick }
8093e5dd7070Spatrick
isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer)8094*7a9b00ceSrobert static bool isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer) {
8095*7a9b00ceSrobert return Sanitizer == "address" || Sanitizer == "hwaddress" ||
8096*7a9b00ceSrobert Sanitizer == "memtag";
8097*7a9b00ceSrobert }
8098*7a9b00ceSrobert
handleNoSanitizeAttr(Sema & S,Decl * D,const ParsedAttr & AL)8099e5dd7070Spatrick static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8100a0747c9fSpatrick if (!AL.checkAtLeastNumArgs(S, 1))
8101e5dd7070Spatrick return;
8102e5dd7070Spatrick
8103e5dd7070Spatrick std::vector<StringRef> Sanitizers;
8104e5dd7070Spatrick
8105e5dd7070Spatrick for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
8106e5dd7070Spatrick StringRef SanitizerName;
8107e5dd7070Spatrick SourceLocation LiteralLoc;
8108e5dd7070Spatrick
8109e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc))
8110e5dd7070Spatrick return;
8111e5dd7070Spatrick
8112e5dd7070Spatrick if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) ==
8113a0747c9fSpatrick SanitizerMask() &&
8114a0747c9fSpatrick SanitizerName != "coverage")
8115e5dd7070Spatrick S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
8116*7a9b00ceSrobert else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName))
8117*7a9b00ceSrobert S.Diag(D->getLocation(), diag::warn_attribute_type_not_supported_global)
8118*7a9b00ceSrobert << AL << SanitizerName;
8119e5dd7070Spatrick Sanitizers.push_back(SanitizerName);
8120e5dd7070Spatrick }
8121e5dd7070Spatrick
8122e5dd7070Spatrick D->addAttr(::new (S.Context) NoSanitizeAttr(S.Context, AL, Sanitizers.data(),
8123e5dd7070Spatrick Sanitizers.size()));
8124e5dd7070Spatrick }
8125e5dd7070Spatrick
handleNoSanitizeSpecificAttr(Sema & S,Decl * D,const ParsedAttr & AL)8126e5dd7070Spatrick static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
8127e5dd7070Spatrick const ParsedAttr &AL) {
8128e5dd7070Spatrick StringRef AttrName = AL.getAttrName()->getName();
8129e5dd7070Spatrick normalizeName(AttrName);
8130e5dd7070Spatrick StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName)
8131e5dd7070Spatrick .Case("no_address_safety_analysis", "address")
8132e5dd7070Spatrick .Case("no_sanitize_address", "address")
8133e5dd7070Spatrick .Case("no_sanitize_thread", "thread")
8134e5dd7070Spatrick .Case("no_sanitize_memory", "memory");
8135e5dd7070Spatrick if (isGlobalVar(D) && SanitizerName != "address")
8136e5dd7070Spatrick S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
8137e5dd7070Spatrick << AL << ExpectedFunction;
8138e5dd7070Spatrick
8139e5dd7070Spatrick // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a
8140e5dd7070Spatrick // NoSanitizeAttr object; but we need to calculate the correct spelling list
8141e5dd7070Spatrick // index rather than incorrectly assume the index for NoSanitizeSpecificAttr
8142e5dd7070Spatrick // has the same spellings as the index for NoSanitizeAttr. We don't have a
8143e5dd7070Spatrick // general way to "translate" between the two, so this hack attempts to work
8144*7a9b00ceSrobert // around the issue with hard-coded indices. This is critical for calling
8145e5dd7070Spatrick // getSpelling() or prettyPrint() on the resulting semantic attribute object
8146e5dd7070Spatrick // without failing assertions.
8147e5dd7070Spatrick unsigned TranslatedSpellingIndex = 0;
8148a0747c9fSpatrick if (AL.isStandardAttributeSyntax())
8149e5dd7070Spatrick TranslatedSpellingIndex = 1;
8150e5dd7070Spatrick
8151e5dd7070Spatrick AttributeCommonInfo Info = AL;
8152e5dd7070Spatrick Info.setAttributeSpellingListIndex(TranslatedSpellingIndex);
8153e5dd7070Spatrick D->addAttr(::new (S.Context)
8154e5dd7070Spatrick NoSanitizeAttr(S.Context, Info, &SanitizerName, 1));
8155e5dd7070Spatrick }
8156e5dd7070Spatrick
handleInternalLinkageAttr(Sema & S,Decl * D,const ParsedAttr & AL)8157e5dd7070Spatrick static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8158e5dd7070Spatrick if (InternalLinkageAttr *Internal = S.mergeInternalLinkageAttr(D, AL))
8159e5dd7070Spatrick D->addAttr(Internal);
8160e5dd7070Spatrick }
8161e5dd7070Spatrick
handleOpenCLNoSVMAttr(Sema & S,Decl * D,const ParsedAttr & AL)8162e5dd7070Spatrick static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8163*7a9b00ceSrobert if (S.LangOpts.getOpenCLCompatibleVersion() < 200)
8164e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version)
8165*7a9b00ceSrobert << AL << "2.0" << 1;
8166e5dd7070Spatrick else
8167*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored)
8168*7a9b00ceSrobert << AL << S.LangOpts.getOpenCLVersionString();
8169e5dd7070Spatrick }
8170e5dd7070Spatrick
handleOpenCLAccessAttr(Sema & S,Decl * D,const ParsedAttr & AL)8171e5dd7070Spatrick static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8172e5dd7070Spatrick if (D->isInvalidDecl())
8173e5dd7070Spatrick return;
8174e5dd7070Spatrick
8175e5dd7070Spatrick // Check if there is only one access qualifier.
8176e5dd7070Spatrick if (D->hasAttr<OpenCLAccessAttr>()) {
8177e5dd7070Spatrick if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
8178e5dd7070Spatrick AL.getSemanticSpelling()) {
8179e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_duplicate_declspec)
8180e5dd7070Spatrick << AL.getAttrName()->getName() << AL.getRange();
8181e5dd7070Spatrick } else {
8182e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
8183e5dd7070Spatrick << D->getSourceRange();
8184e5dd7070Spatrick D->setInvalidDecl(true);
8185e5dd7070Spatrick return;
8186e5dd7070Spatrick }
8187e5dd7070Spatrick }
8188e5dd7070Spatrick
8189a0747c9fSpatrick // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that
8190a0747c9fSpatrick // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel
8191a0747c9fSpatrick // cannot read from and write to the same pipe object. Using the read_write
8192a0747c9fSpatrick // (or __read_write) qualifier with the pipe qualifier is a compilation error.
8193a0747c9fSpatrick // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the
8194a0747c9fSpatrick // __opencl_c_read_write_images feature, image objects specified as arguments
8195a0747c9fSpatrick // to a kernel can additionally be declared to be read-write.
8196*7a9b00ceSrobert // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0.
8197*7a9b00ceSrobert // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0.
8198e5dd7070Spatrick if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
8199e5dd7070Spatrick const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
8200*7a9b00ceSrobert if (AL.getAttrName()->getName().contains("read_write")) {
8201*7a9b00ceSrobert bool ReadWriteImagesUnsupported =
8202*7a9b00ceSrobert (S.getLangOpts().getOpenCLCompatibleVersion() < 200) ||
8203*7a9b00ceSrobert (S.getLangOpts().getOpenCLCompatibleVersion() == 300 &&
8204a0747c9fSpatrick !S.getOpenCLOptions().isSupported("__opencl_c_read_write_images",
8205a0747c9fSpatrick S.getLangOpts()));
8206*7a9b00ceSrobert if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) {
8207e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
8208e5dd7070Spatrick << AL << PDecl->getType() << DeclTy->isImageType();
8209e5dd7070Spatrick D->setInvalidDecl(true);
8210e5dd7070Spatrick return;
8211e5dd7070Spatrick }
8212e5dd7070Spatrick }
8213e5dd7070Spatrick }
8214e5dd7070Spatrick
8215e5dd7070Spatrick D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
8216e5dd7070Spatrick }
8217e5dd7070Spatrick
handleZeroCallUsedRegsAttr(Sema & S,Decl * D,const ParsedAttr & AL)8218*7a9b00ceSrobert static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8219*7a9b00ceSrobert // Check that the argument is a string literal.
8220*7a9b00ceSrobert StringRef KindStr;
8221*7a9b00ceSrobert SourceLocation LiteralLoc;
8222*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, KindStr, &LiteralLoc))
8223*7a9b00ceSrobert return;
8224*7a9b00ceSrobert
8225*7a9b00ceSrobert ZeroCallUsedRegsAttr::ZeroCallUsedRegsKind Kind;
8226*7a9b00ceSrobert if (!ZeroCallUsedRegsAttr::ConvertStrToZeroCallUsedRegsKind(KindStr, Kind)) {
8227*7a9b00ceSrobert S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
8228*7a9b00ceSrobert << AL << KindStr;
8229*7a9b00ceSrobert return;
8230*7a9b00ceSrobert }
8231*7a9b00ceSrobert
8232*7a9b00ceSrobert D->dropAttr<ZeroCallUsedRegsAttr>();
8233*7a9b00ceSrobert D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
8234*7a9b00ceSrobert }
8235*7a9b00ceSrobert
handleFunctionReturnThunksAttr(Sema & S,Decl * D,const ParsedAttr & AL)8236*7a9b00ceSrobert static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
8237*7a9b00ceSrobert const ParsedAttr &AL) {
8238*7a9b00ceSrobert StringRef KindStr;
8239*7a9b00ceSrobert SourceLocation LiteralLoc;
8240*7a9b00ceSrobert if (!S.checkStringLiteralArgumentAttr(AL, 0, KindStr, &LiteralLoc))
8241*7a9b00ceSrobert return;
8242*7a9b00ceSrobert
8243*7a9b00ceSrobert FunctionReturnThunksAttr::Kind Kind;
8244*7a9b00ceSrobert if (!FunctionReturnThunksAttr::ConvertStrToKind(KindStr, Kind)) {
8245*7a9b00ceSrobert S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
8246*7a9b00ceSrobert << AL << KindStr;
8247*7a9b00ceSrobert return;
8248*7a9b00ceSrobert }
8249*7a9b00ceSrobert // FIXME: it would be good to better handle attribute merging rather than
8250*7a9b00ceSrobert // silently replacing the existing attribute, so long as it does not break
8251*7a9b00ceSrobert // the expected codegen tests.
8252*7a9b00ceSrobert D->dropAttr<FunctionReturnThunksAttr>();
8253*7a9b00ceSrobert D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
8254*7a9b00ceSrobert }
8255*7a9b00ceSrobert
handleSYCLKernelAttr(Sema & S,Decl * D,const ParsedAttr & AL)8256e5dd7070Spatrick static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8257e5dd7070Spatrick // The 'sycl_kernel' attribute applies only to function templates.
8258e5dd7070Spatrick const auto *FD = cast<FunctionDecl>(D);
8259e5dd7070Spatrick const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
8260e5dd7070Spatrick assert(FT && "Function template is expected");
8261e5dd7070Spatrick
8262e5dd7070Spatrick // Function template must have at least two template parameters.
8263e5dd7070Spatrick const TemplateParameterList *TL = FT->getTemplateParameters();
8264e5dd7070Spatrick if (TL->size() < 2) {
8265e5dd7070Spatrick S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
8266e5dd7070Spatrick return;
8267e5dd7070Spatrick }
8268e5dd7070Spatrick
8269e5dd7070Spatrick // Template parameters must be typenames.
8270e5dd7070Spatrick for (unsigned I = 0; I < 2; ++I) {
8271e5dd7070Spatrick const NamedDecl *TParam = TL->getParam(I);
8272e5dd7070Spatrick if (isa<NonTypeTemplateParmDecl>(TParam)) {
8273e5dd7070Spatrick S.Diag(FT->getLocation(),
8274e5dd7070Spatrick diag::warn_sycl_kernel_invalid_template_param_type);
8275e5dd7070Spatrick return;
8276e5dd7070Spatrick }
8277e5dd7070Spatrick }
8278e5dd7070Spatrick
8279e5dd7070Spatrick // Function must have at least one argument.
8280e5dd7070Spatrick if (getFunctionOrMethodNumParams(D) != 1) {
8281e5dd7070Spatrick S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
8282e5dd7070Spatrick return;
8283e5dd7070Spatrick }
8284e5dd7070Spatrick
8285e5dd7070Spatrick // Function must return void.
8286e5dd7070Spatrick QualType RetTy = getFunctionOrMethodResultType(D);
8287e5dd7070Spatrick if (!RetTy->isVoidType()) {
8288e5dd7070Spatrick S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
8289e5dd7070Spatrick return;
8290e5dd7070Spatrick }
8291e5dd7070Spatrick
8292e5dd7070Spatrick handleSimpleAttribute<SYCLKernelAttr>(S, D, AL);
8293e5dd7070Spatrick }
8294e5dd7070Spatrick
handleDestroyAttr(Sema & S,Decl * D,const ParsedAttr & A)8295e5dd7070Spatrick static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
8296e5dd7070Spatrick if (!cast<VarDecl>(D)->hasGlobalStorage()) {
8297e5dd7070Spatrick S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var)
8298e5dd7070Spatrick << (A.getKind() == ParsedAttr::AT_AlwaysDestroy);
8299e5dd7070Spatrick return;
8300e5dd7070Spatrick }
8301e5dd7070Spatrick
8302e5dd7070Spatrick if (A.getKind() == ParsedAttr::AT_AlwaysDestroy)
8303a0747c9fSpatrick handleSimpleAttribute<AlwaysDestroyAttr>(S, D, A);
8304e5dd7070Spatrick else
8305a0747c9fSpatrick handleSimpleAttribute<NoDestroyAttr>(S, D, A);
8306e5dd7070Spatrick }
8307e5dd7070Spatrick
handleUninitializedAttr(Sema & S,Decl * D,const ParsedAttr & AL)8308e5dd7070Spatrick static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8309e5dd7070Spatrick assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic &&
8310e5dd7070Spatrick "uninitialized is only valid on automatic duration variables");
8311e5dd7070Spatrick D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL));
8312e5dd7070Spatrick }
8313e5dd7070Spatrick
tryMakeVariablePseudoStrong(Sema & S,VarDecl * VD,bool DiagnoseFailure)8314e5dd7070Spatrick static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD,
8315e5dd7070Spatrick bool DiagnoseFailure) {
8316e5dd7070Spatrick QualType Ty = VD->getType();
8317e5dd7070Spatrick if (!Ty->isObjCRetainableType()) {
8318e5dd7070Spatrick if (DiagnoseFailure) {
8319e5dd7070Spatrick S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
8320e5dd7070Spatrick << 0;
8321e5dd7070Spatrick }
8322e5dd7070Spatrick return false;
8323e5dd7070Spatrick }
8324e5dd7070Spatrick
8325e5dd7070Spatrick Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime();
8326e5dd7070Spatrick
8327e5dd7070Spatrick // Sema::inferObjCARCLifetime must run after processing decl attributes
8328e5dd7070Spatrick // (because __block lowers to an attribute), so if the lifetime hasn't been
8329e5dd7070Spatrick // explicitly specified, infer it locally now.
8330e5dd7070Spatrick if (LifetimeQual == Qualifiers::OCL_None)
8331e5dd7070Spatrick LifetimeQual = Ty->getObjCARCImplicitLifetime();
8332e5dd7070Spatrick
8333e5dd7070Spatrick // The attributes only really makes sense for __strong variables; ignore any
8334e5dd7070Spatrick // attempts to annotate a parameter with any other lifetime qualifier.
8335e5dd7070Spatrick if (LifetimeQual != Qualifiers::OCL_Strong) {
8336e5dd7070Spatrick if (DiagnoseFailure) {
8337e5dd7070Spatrick S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
8338e5dd7070Spatrick << 1;
8339e5dd7070Spatrick }
8340e5dd7070Spatrick return false;
8341e5dd7070Spatrick }
8342e5dd7070Spatrick
8343e5dd7070Spatrick // Tampering with the type of a VarDecl here is a bit of a hack, but we need
8344e5dd7070Spatrick // to ensure that the variable is 'const' so that we can error on
8345e5dd7070Spatrick // modification, which can otherwise over-release.
8346e5dd7070Spatrick VD->setType(Ty.withConst());
8347e5dd7070Spatrick VD->setARCPseudoStrong(true);
8348e5dd7070Spatrick return true;
8349e5dd7070Spatrick }
8350e5dd7070Spatrick
handleObjCExternallyRetainedAttr(Sema & S,Decl * D,const ParsedAttr & AL)8351e5dd7070Spatrick static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
8352e5dd7070Spatrick const ParsedAttr &AL) {
8353e5dd7070Spatrick if (auto *VD = dyn_cast<VarDecl>(D)) {
8354e5dd7070Spatrick assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically");
8355e5dd7070Spatrick if (!VD->hasLocalStorage()) {
8356e5dd7070Spatrick S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
8357e5dd7070Spatrick << 0;
8358e5dd7070Spatrick return;
8359e5dd7070Spatrick }
8360e5dd7070Spatrick
8361e5dd7070Spatrick if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true))
8362e5dd7070Spatrick return;
8363e5dd7070Spatrick
8364e5dd7070Spatrick handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
8365e5dd7070Spatrick return;
8366e5dd7070Spatrick }
8367e5dd7070Spatrick
8368e5dd7070Spatrick // If D is a function-like declaration (method, block, or function), then we
8369e5dd7070Spatrick // make every parameter psuedo-strong.
8370ec727ea7Spatrick unsigned NumParams =
8371ec727ea7Spatrick hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0;
8372ec727ea7Spatrick for (unsigned I = 0; I != NumParams; ++I) {
8373e5dd7070Spatrick auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I));
8374e5dd7070Spatrick QualType Ty = PVD->getType();
8375e5dd7070Spatrick
8376e5dd7070Spatrick // If a user wrote a parameter with __strong explicitly, then assume they
8377e5dd7070Spatrick // want "real" strong semantics for that parameter. This works because if
8378e5dd7070Spatrick // the parameter was written with __strong, then the strong qualifier will
8379e5dd7070Spatrick // be non-local.
8380e5dd7070Spatrick if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() ==
8381e5dd7070Spatrick Qualifiers::OCL_Strong)
8382e5dd7070Spatrick continue;
8383e5dd7070Spatrick
8384e5dd7070Spatrick tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false);
8385e5dd7070Spatrick }
8386e5dd7070Spatrick handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
8387e5dd7070Spatrick }
8388e5dd7070Spatrick
handleMIGServerRoutineAttr(Sema & S,Decl * D,const ParsedAttr & AL)8389e5dd7070Spatrick static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8390e5dd7070Spatrick // Check that the return type is a `typedef int kern_return_t` or a typedef
8391e5dd7070Spatrick // around it, because otherwise MIG convention checks make no sense.
8392e5dd7070Spatrick // BlockDecl doesn't store a return type, so it's annoying to check,
8393e5dd7070Spatrick // so let's skip it for now.
8394e5dd7070Spatrick if (!isa<BlockDecl>(D)) {
8395e5dd7070Spatrick QualType T = getFunctionOrMethodResultType(D);
8396e5dd7070Spatrick bool IsKernReturnT = false;
8397e5dd7070Spatrick while (const auto *TT = T->getAs<TypedefType>()) {
8398e5dd7070Spatrick IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t");
8399e5dd7070Spatrick T = TT->desugar();
8400e5dd7070Spatrick }
8401e5dd7070Spatrick if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) {
8402e5dd7070Spatrick S.Diag(D->getBeginLoc(),
8403e5dd7070Spatrick diag::warn_mig_server_routine_does_not_return_kern_return_t);
8404e5dd7070Spatrick return;
8405e5dd7070Spatrick }
8406e5dd7070Spatrick }
8407e5dd7070Spatrick
8408e5dd7070Spatrick handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL);
8409e5dd7070Spatrick }
8410e5dd7070Spatrick
handleMSAllocatorAttr(Sema & S,Decl * D,const ParsedAttr & AL)8411e5dd7070Spatrick static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8412e5dd7070Spatrick // Warn if the return type is not a pointer or reference type.
8413e5dd7070Spatrick if (auto *FD = dyn_cast<FunctionDecl>(D)) {
8414e5dd7070Spatrick QualType RetTy = FD->getReturnType();
8415e5dd7070Spatrick if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
8416e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
8417e5dd7070Spatrick << AL.getRange() << RetTy;
8418e5dd7070Spatrick return;
8419e5dd7070Spatrick }
8420e5dd7070Spatrick }
8421e5dd7070Spatrick
8422e5dd7070Spatrick handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
8423e5dd7070Spatrick }
8424e5dd7070Spatrick
handleAcquireHandleAttr(Sema & S,Decl * D,const ParsedAttr & AL)8425ec727ea7Spatrick static void handleAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8426e5dd7070Spatrick if (AL.isUsedAsTypeAttr())
8427e5dd7070Spatrick return;
8428e5dd7070Spatrick // Warn if the parameter is definitely not an output parameter.
8429e5dd7070Spatrick if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
8430e5dd7070Spatrick if (PVD->getType()->isIntegerType()) {
8431e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_output_parameter)
8432e5dd7070Spatrick << AL.getRange();
8433e5dd7070Spatrick return;
8434e5dd7070Spatrick }
8435e5dd7070Spatrick }
8436e5dd7070Spatrick StringRef Argument;
8437e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
8438e5dd7070Spatrick return;
8439e5dd7070Spatrick D->addAttr(AcquireHandleAttr::Create(S.Context, Argument, AL));
8440e5dd7070Spatrick }
8441e5dd7070Spatrick
8442e5dd7070Spatrick template<typename Attr>
handleHandleAttr(Sema & S,Decl * D,const ParsedAttr & AL)8443e5dd7070Spatrick static void handleHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8444e5dd7070Spatrick StringRef Argument;
8445e5dd7070Spatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
8446e5dd7070Spatrick return;
8447e5dd7070Spatrick D->addAttr(Attr::Create(S.Context, Argument, AL));
8448e5dd7070Spatrick }
8449e5dd7070Spatrick
handleCFGuardAttr(Sema & S,Decl * D,const ParsedAttr & AL)8450e5dd7070Spatrick static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8451e5dd7070Spatrick // The guard attribute takes a single identifier argument.
8452e5dd7070Spatrick
8453e5dd7070Spatrick if (!AL.isArgIdent(0)) {
8454e5dd7070Spatrick S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
8455e5dd7070Spatrick << AL << AANT_ArgumentIdentifier;
8456e5dd7070Spatrick return;
8457e5dd7070Spatrick }
8458e5dd7070Spatrick
8459e5dd7070Spatrick CFGuardAttr::GuardArg Arg;
8460e5dd7070Spatrick IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
8461e5dd7070Spatrick if (!CFGuardAttr::ConvertStrToGuardArg(II->getName(), Arg)) {
8462e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
8463e5dd7070Spatrick return;
8464e5dd7070Spatrick }
8465e5dd7070Spatrick
8466e5dd7070Spatrick D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg));
8467e5dd7070Spatrick }
8468e5dd7070Spatrick
8469a0747c9fSpatrick
8470a0747c9fSpatrick template <typename AttrTy>
findEnforceTCBAttrByName(Decl * D,StringRef Name)8471a0747c9fSpatrick static const AttrTy *findEnforceTCBAttrByName(Decl *D, StringRef Name) {
8472a0747c9fSpatrick auto Attrs = D->specific_attrs<AttrTy>();
8473a0747c9fSpatrick auto I = llvm::find_if(Attrs,
8474a0747c9fSpatrick [Name](const AttrTy *A) {
8475a0747c9fSpatrick return A->getTCBName() == Name;
8476a0747c9fSpatrick });
8477a0747c9fSpatrick return I == Attrs.end() ? nullptr : *I;
8478a0747c9fSpatrick }
8479a0747c9fSpatrick
8480a0747c9fSpatrick template <typename AttrTy, typename ConflictingAttrTy>
handleEnforceTCBAttr(Sema & S,Decl * D,const ParsedAttr & AL)8481a0747c9fSpatrick static void handleEnforceTCBAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
8482a0747c9fSpatrick StringRef Argument;
8483a0747c9fSpatrick if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
8484a0747c9fSpatrick return;
8485a0747c9fSpatrick
8486a0747c9fSpatrick // A function cannot be have both regular and leaf membership in the same TCB.
8487a0747c9fSpatrick if (const ConflictingAttrTy *ConflictingAttr =
8488a0747c9fSpatrick findEnforceTCBAttrByName<ConflictingAttrTy>(D, Argument)) {
8489a0747c9fSpatrick // We could attach a note to the other attribute but in this case
8490a0747c9fSpatrick // there's no need given how the two are very close to each other.
8491a0747c9fSpatrick S.Diag(AL.getLoc(), diag::err_tcb_conflicting_attributes)
8492a0747c9fSpatrick << AL.getAttrName()->getName() << ConflictingAttr->getAttrName()->getName()
8493a0747c9fSpatrick << Argument;
8494a0747c9fSpatrick
8495a0747c9fSpatrick // Error recovery: drop the non-leaf attribute so that to suppress
8496a0747c9fSpatrick // all future warnings caused by erroneous attributes. The leaf attribute
8497a0747c9fSpatrick // needs to be kept because it can only suppresses warnings, not cause them.
8498a0747c9fSpatrick D->dropAttr<EnforceTCBAttr>();
8499a0747c9fSpatrick return;
8500a0747c9fSpatrick }
8501a0747c9fSpatrick
8502a0747c9fSpatrick D->addAttr(AttrTy::Create(S.Context, Argument, AL));
8503a0747c9fSpatrick }
8504a0747c9fSpatrick
8505a0747c9fSpatrick template <typename AttrTy, typename ConflictingAttrTy>
mergeEnforceTCBAttrImpl(Sema & S,Decl * D,const AttrTy & AL)8506a0747c9fSpatrick static AttrTy *mergeEnforceTCBAttrImpl(Sema &S, Decl *D, const AttrTy &AL) {
8507a0747c9fSpatrick // Check if the new redeclaration has different leaf-ness in the same TCB.
8508a0747c9fSpatrick StringRef TCBName = AL.getTCBName();
8509a0747c9fSpatrick if (const ConflictingAttrTy *ConflictingAttr =
8510a0747c9fSpatrick findEnforceTCBAttrByName<ConflictingAttrTy>(D, TCBName)) {
8511a0747c9fSpatrick S.Diag(ConflictingAttr->getLoc(), diag::err_tcb_conflicting_attributes)
8512a0747c9fSpatrick << ConflictingAttr->getAttrName()->getName()
8513a0747c9fSpatrick << AL.getAttrName()->getName() << TCBName;
8514a0747c9fSpatrick
8515a0747c9fSpatrick // Add a note so that the user could easily find the conflicting attribute.
8516a0747c9fSpatrick S.Diag(AL.getLoc(), diag::note_conflicting_attribute);
8517a0747c9fSpatrick
8518a0747c9fSpatrick // More error recovery.
8519a0747c9fSpatrick D->dropAttr<EnforceTCBAttr>();
8520a0747c9fSpatrick return nullptr;
8521a0747c9fSpatrick }
8522a0747c9fSpatrick
8523a0747c9fSpatrick ASTContext &Context = S.getASTContext();
8524a0747c9fSpatrick return ::new(Context) AttrTy(Context, AL, AL.getTCBName());
8525a0747c9fSpatrick }
8526a0747c9fSpatrick
mergeEnforceTCBAttr(Decl * D,const EnforceTCBAttr & AL)8527a0747c9fSpatrick EnforceTCBAttr *Sema::mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL) {
8528a0747c9fSpatrick return mergeEnforceTCBAttrImpl<EnforceTCBAttr, EnforceTCBLeafAttr>(
8529a0747c9fSpatrick *this, D, AL);
8530a0747c9fSpatrick }
8531a0747c9fSpatrick
mergeEnforceTCBLeafAttr(Decl * D,const EnforceTCBLeafAttr & AL)8532a0747c9fSpatrick EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr(
8533a0747c9fSpatrick Decl *D, const EnforceTCBLeafAttr &AL) {
8534a0747c9fSpatrick return mergeEnforceTCBAttrImpl<EnforceTCBLeafAttr, EnforceTCBAttr>(
8535a0747c9fSpatrick *this, D, AL);
8536a0747c9fSpatrick }
8537a0747c9fSpatrick
8538e5dd7070Spatrick //===----------------------------------------------------------------------===//
8539e5dd7070Spatrick // Top Level Sema Entry Points
8540e5dd7070Spatrick //===----------------------------------------------------------------------===//
8541e5dd7070Spatrick
8542*7a9b00ceSrobert // Returns true if the attribute must delay setting its arguments until after
8543*7a9b00ceSrobert // template instantiation, and false otherwise.
MustDelayAttributeArguments(const ParsedAttr & AL)8544*7a9b00ceSrobert static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
8545*7a9b00ceSrobert // Only attributes that accept expression parameter packs can delay arguments.
8546*7a9b00ceSrobert if (!AL.acceptsExprPack())
8547*7a9b00ceSrobert return false;
8548*7a9b00ceSrobert
8549*7a9b00ceSrobert bool AttrHasVariadicArg = AL.hasVariadicArg();
8550*7a9b00ceSrobert unsigned AttrNumArgs = AL.getNumArgMembers();
8551*7a9b00ceSrobert for (size_t I = 0; I < std::min(AL.getNumArgs(), AttrNumArgs); ++I) {
8552*7a9b00ceSrobert bool IsLastAttrArg = I == (AttrNumArgs - 1);
8553*7a9b00ceSrobert // If the argument is the last argument and it is variadic it can contain
8554*7a9b00ceSrobert // any expression.
8555*7a9b00ceSrobert if (IsLastAttrArg && AttrHasVariadicArg)
8556*7a9b00ceSrobert return false;
8557*7a9b00ceSrobert Expr *E = AL.getArgAsExpr(I);
8558*7a9b00ceSrobert bool ArgMemberCanHoldExpr = AL.isParamExpr(I);
8559*7a9b00ceSrobert // If the expression is a pack expansion then arguments must be delayed
8560*7a9b00ceSrobert // unless the argument is an expression and it is the last argument of the
8561*7a9b00ceSrobert // attribute.
8562*7a9b00ceSrobert if (isa<PackExpansionExpr>(E))
8563*7a9b00ceSrobert return !(IsLastAttrArg && ArgMemberCanHoldExpr);
8564*7a9b00ceSrobert // Last case is if the expression is value dependent then it must delay
8565*7a9b00ceSrobert // arguments unless the corresponding argument is able to hold the
8566*7a9b00ceSrobert // expression.
8567*7a9b00ceSrobert if (E->isValueDependent() && !ArgMemberCanHoldExpr)
8568*7a9b00ceSrobert return true;
8569*7a9b00ceSrobert }
8570*7a9b00ceSrobert return false;
8571*7a9b00ceSrobert }
8572*7a9b00ceSrobert
8573e5dd7070Spatrick /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
8574e5dd7070Spatrick /// the attribute applies to decls. If the attribute is a type attribute, just
8575e5dd7070Spatrick /// silently ignore it if a GNU attribute.
8576*7a9b00ceSrobert static void
ProcessDeclAttribute(Sema & S,Scope * scope,Decl * D,const ParsedAttr & AL,const Sema::ProcessDeclAttributeOptions & Options)8577*7a9b00ceSrobert ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
8578*7a9b00ceSrobert const Sema::ProcessDeclAttributeOptions &Options) {
8579e5dd7070Spatrick if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
8580e5dd7070Spatrick return;
8581e5dd7070Spatrick
8582e5dd7070Spatrick // Ignore C++11 attributes on declarator chunks: they appertain to the type
8583e5dd7070Spatrick // instead.
8584*7a9b00ceSrobert // FIXME: We currently check the attribute syntax directly instead of using
8585*7a9b00ceSrobert // isCXX11Attribute(), which currently erroneously classifies the C11
8586*7a9b00ceSrobert // `_Alignas` attribute as a C++11 attribute. `_Alignas` can appear on the
8587*7a9b00ceSrobert // `DeclSpec`, so we need to let it through here to make sure it is processed
8588*7a9b00ceSrobert // appropriately. Once the behavior of isCXX11Attribute() is fixed, we can
8589*7a9b00ceSrobert // go back to using that here.
8590*7a9b00ceSrobert if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes)
8591e5dd7070Spatrick return;
8592e5dd7070Spatrick
8593e5dd7070Spatrick // Unknown attributes are automatically warned on. Target-specific attributes
8594e5dd7070Spatrick // which do not apply to the current target architecture are treated as
8595e5dd7070Spatrick // though they were unknown attributes.
8596e5dd7070Spatrick if (AL.getKind() == ParsedAttr::UnknownAttribute ||
8597e5dd7070Spatrick !AL.existsInTarget(S.Context.getTargetInfo())) {
8598e5dd7070Spatrick S.Diag(AL.getLoc(),
8599e5dd7070Spatrick AL.isDeclspecAttribute()
8600e5dd7070Spatrick ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
8601e5dd7070Spatrick : (unsigned)diag::warn_unknown_attribute_ignored)
8602a0747c9fSpatrick << AL << AL.getRange();
8603e5dd7070Spatrick return;
8604e5dd7070Spatrick }
8605e5dd7070Spatrick
8606*7a9b00ceSrobert // Check if argument population must delayed to after template instantiation.
8607*7a9b00ceSrobert bool MustDelayArgs = MustDelayAttributeArguments(AL);
8608*7a9b00ceSrobert
8609*7a9b00ceSrobert // Argument number check must be skipped if arguments are delayed.
8610*7a9b00ceSrobert if (S.checkCommonAttributeFeatures(D, AL, MustDelayArgs))
8611e5dd7070Spatrick return;
8612e5dd7070Spatrick
8613*7a9b00ceSrobert if (MustDelayArgs) {
8614*7a9b00ceSrobert AL.handleAttrWithDelayedArgs(S, D);
8615*7a9b00ceSrobert return;
8616*7a9b00ceSrobert }
8617*7a9b00ceSrobert
8618e5dd7070Spatrick switch (AL.getKind()) {
8619e5dd7070Spatrick default:
8620ec727ea7Spatrick if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled)
8621ec727ea7Spatrick break;
8622e5dd7070Spatrick if (!AL.isStmtAttr()) {
8623e5dd7070Spatrick assert(AL.isTypeAttr() && "Non-type attribute not handled");
8624*7a9b00ceSrobert }
8625*7a9b00ceSrobert if (AL.isTypeAttr()) {
8626*7a9b00ceSrobert if (Options.IgnoreTypeAttributes)
8627e5dd7070Spatrick break;
8628*7a9b00ceSrobert if (!AL.isStandardAttributeSyntax()) {
8629*7a9b00ceSrobert // Non-[[]] type attributes are handled in processTypeAttrs(); silently
8630*7a9b00ceSrobert // move on.
8631*7a9b00ceSrobert break;
8632*7a9b00ceSrobert }
8633*7a9b00ceSrobert
8634*7a9b00ceSrobert // According to the C and C++ standards, we should never see a
8635*7a9b00ceSrobert // [[]] type attribute on a declaration. However, we have in the past
8636*7a9b00ceSrobert // allowed some type attributes to "slide" to the `DeclSpec`, so we need
8637*7a9b00ceSrobert // to continue to support this legacy behavior. We only do this, however,
8638*7a9b00ceSrobert // if
8639*7a9b00ceSrobert // - we actually have a `DeclSpec`, i.e. if we're looking at a
8640*7a9b00ceSrobert // `DeclaratorDecl`, or
8641*7a9b00ceSrobert // - we are looking at an alias-declaration, where historically we have
8642*7a9b00ceSrobert // allowed type attributes after the identifier to slide to the type.
8643*7a9b00ceSrobert if (AL.slidesFromDeclToDeclSpecLegacyBehavior() &&
8644*7a9b00ceSrobert isa<DeclaratorDecl, TypeAliasDecl>(D)) {
8645*7a9b00ceSrobert // Suggest moving the attribute to the type instead, but only for our
8646*7a9b00ceSrobert // own vendor attributes; moving other vendors' attributes might hurt
8647*7a9b00ceSrobert // portability.
8648*7a9b00ceSrobert if (AL.isClangScope()) {
8649*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
8650*7a9b00ceSrobert << AL << D->getLocation();
8651*7a9b00ceSrobert }
8652*7a9b00ceSrobert
8653*7a9b00ceSrobert // Allow this type attribute to be handled in processTypeAttrs();
8654*7a9b00ceSrobert // silently move on.
8655*7a9b00ceSrobert break;
8656*7a9b00ceSrobert }
8657*7a9b00ceSrobert
8658*7a9b00ceSrobert if (AL.getKind() == ParsedAttr::AT_Regparm) {
8659*7a9b00ceSrobert // `regparm` is a special case: It's a type attribute but we still want
8660*7a9b00ceSrobert // to treat it as if it had been written on the declaration because that
8661*7a9b00ceSrobert // way we'll be able to handle it directly in `processTypeAttr()`.
8662*7a9b00ceSrobert // If we treated `regparm` it as if it had been written on the
8663*7a9b00ceSrobert // `DeclSpec`, the logic in `distributeFunctionTypeAttrFromDeclSepc()`
8664*7a9b00ceSrobert // would try to move it to the declarator, but that doesn't work: We
8665*7a9b00ceSrobert // can't remove the attribute from the list of declaration attributes
8666*7a9b00ceSrobert // because it might be needed by other declarators in the same
8667*7a9b00ceSrobert // declaration.
8668*7a9b00ceSrobert break;
8669*7a9b00ceSrobert }
8670*7a9b00ceSrobert
8671*7a9b00ceSrobert if (AL.getKind() == ParsedAttr::AT_VectorSize) {
8672*7a9b00ceSrobert // `vector_size` is a special case: It's a type attribute semantically,
8673*7a9b00ceSrobert // but GCC expects the [[]] syntax to be written on the declaration (and
8674*7a9b00ceSrobert // warns that the attribute has no effect if it is placed on the
8675*7a9b00ceSrobert // decl-specifier-seq).
8676*7a9b00ceSrobert // Silently move on and allow the attribute to be handled in
8677*7a9b00ceSrobert // processTypeAttr().
8678*7a9b00ceSrobert break;
8679*7a9b00ceSrobert }
8680*7a9b00ceSrobert
8681*7a9b00ceSrobert if (AL.getKind() == ParsedAttr::AT_NoDeref) {
8682*7a9b00ceSrobert // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
8683*7a9b00ceSrobert // See https://github.com/llvm/llvm-project/issues/55790 for details.
8684*7a9b00ceSrobert // We allow processTypeAttrs() to emit a warning and silently move on.
8685*7a9b00ceSrobert break;
8686*7a9b00ceSrobert }
8687e5dd7070Spatrick }
8688a0747c9fSpatrick // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
8689a0747c9fSpatrick // statement attribute is not written on a declaration, but this code is
8690*7a9b00ceSrobert // needed for type attributes as well as statement attributes in Attr.td
8691*7a9b00ceSrobert // that do not list any subjects.
8692*7a9b00ceSrobert S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)
8693e5dd7070Spatrick << AL << D->getLocation();
8694e5dd7070Spatrick break;
8695e5dd7070Spatrick case ParsedAttr::AT_Interrupt:
8696e5dd7070Spatrick handleInterruptAttr(S, D, AL);
8697e5dd7070Spatrick break;
8698e5dd7070Spatrick case ParsedAttr::AT_X86ForceAlignArgPointer:
8699e5dd7070Spatrick handleX86ForceAlignArgPointerAttr(S, D, AL);
8700e5dd7070Spatrick break;
8701*7a9b00ceSrobert case ParsedAttr::AT_ReadOnlyPlacement:
8702*7a9b00ceSrobert handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL);
8703*7a9b00ceSrobert break;
8704e5dd7070Spatrick case ParsedAttr::AT_DLLExport:
8705e5dd7070Spatrick case ParsedAttr::AT_DLLImport:
8706e5dd7070Spatrick handleDLLAttr(S, D, AL);
8707e5dd7070Spatrick break;
8708e5dd7070Spatrick case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:
8709e5dd7070Spatrick handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL);
8710e5dd7070Spatrick break;
8711e5dd7070Spatrick case ParsedAttr::AT_AMDGPUWavesPerEU:
8712e5dd7070Spatrick handleAMDGPUWavesPerEUAttr(S, D, AL);
8713e5dd7070Spatrick break;
8714e5dd7070Spatrick case ParsedAttr::AT_AMDGPUNumSGPR:
8715e5dd7070Spatrick handleAMDGPUNumSGPRAttr(S, D, AL);
8716e5dd7070Spatrick break;
8717e5dd7070Spatrick case ParsedAttr::AT_AMDGPUNumVGPR:
8718e5dd7070Spatrick handleAMDGPUNumVGPRAttr(S, D, AL);
8719e5dd7070Spatrick break;
8720e5dd7070Spatrick case ParsedAttr::AT_AVRSignal:
8721e5dd7070Spatrick handleAVRSignalAttr(S, D, AL);
8722e5dd7070Spatrick break;
8723e5dd7070Spatrick case ParsedAttr::AT_BPFPreserveAccessIndex:
8724e5dd7070Spatrick handleBPFPreserveAccessIndexAttr(S, D, AL);
8725e5dd7070Spatrick break;
8726*7a9b00ceSrobert case ParsedAttr::AT_BTFDeclTag:
8727*7a9b00ceSrobert handleBTFDeclTagAttr(S, D, AL);
8728*7a9b00ceSrobert break;
8729e5dd7070Spatrick case ParsedAttr::AT_WebAssemblyExportName:
8730e5dd7070Spatrick handleWebAssemblyExportNameAttr(S, D, AL);
8731e5dd7070Spatrick break;
8732e5dd7070Spatrick case ParsedAttr::AT_WebAssemblyImportModule:
8733e5dd7070Spatrick handleWebAssemblyImportModuleAttr(S, D, AL);
8734e5dd7070Spatrick break;
8735e5dd7070Spatrick case ParsedAttr::AT_WebAssemblyImportName:
8736e5dd7070Spatrick handleWebAssemblyImportNameAttr(S, D, AL);
8737e5dd7070Spatrick break;
8738e5dd7070Spatrick case ParsedAttr::AT_IBOutlet:
8739e5dd7070Spatrick handleIBOutlet(S, D, AL);
8740e5dd7070Spatrick break;
8741e5dd7070Spatrick case ParsedAttr::AT_IBOutletCollection:
8742e5dd7070Spatrick handleIBOutletCollection(S, D, AL);
8743e5dd7070Spatrick break;
8744e5dd7070Spatrick case ParsedAttr::AT_IFunc:
8745e5dd7070Spatrick handleIFuncAttr(S, D, AL);
8746e5dd7070Spatrick break;
8747e5dd7070Spatrick case ParsedAttr::AT_Alias:
8748e5dd7070Spatrick handleAliasAttr(S, D, AL);
8749e5dd7070Spatrick break;
8750e5dd7070Spatrick case ParsedAttr::AT_Aligned:
8751e5dd7070Spatrick handleAlignedAttr(S, D, AL);
8752e5dd7070Spatrick break;
8753e5dd7070Spatrick case ParsedAttr::AT_AlignValue:
8754e5dd7070Spatrick handleAlignValueAttr(S, D, AL);
8755e5dd7070Spatrick break;
8756e5dd7070Spatrick case ParsedAttr::AT_AllocSize:
8757e5dd7070Spatrick handleAllocSizeAttr(S, D, AL);
8758e5dd7070Spatrick break;
8759e5dd7070Spatrick case ParsedAttr::AT_AlwaysInline:
8760e5dd7070Spatrick handleAlwaysInlineAttr(S, D, AL);
8761e5dd7070Spatrick break;
8762e5dd7070Spatrick case ParsedAttr::AT_AnalyzerNoReturn:
8763e5dd7070Spatrick handleAnalyzerNoReturnAttr(S, D, AL);
8764e5dd7070Spatrick break;
8765e5dd7070Spatrick case ParsedAttr::AT_TLSModel:
8766e5dd7070Spatrick handleTLSModelAttr(S, D, AL);
8767e5dd7070Spatrick break;
8768e5dd7070Spatrick case ParsedAttr::AT_Annotate:
8769e5dd7070Spatrick handleAnnotateAttr(S, D, AL);
8770e5dd7070Spatrick break;
8771e5dd7070Spatrick case ParsedAttr::AT_Availability:
8772e5dd7070Spatrick handleAvailabilityAttr(S, D, AL);
8773e5dd7070Spatrick break;
8774e5dd7070Spatrick case ParsedAttr::AT_CarriesDependency:
8775e5dd7070Spatrick handleDependencyAttr(S, scope, D, AL);
8776e5dd7070Spatrick break;
8777e5dd7070Spatrick case ParsedAttr::AT_CPUDispatch:
8778e5dd7070Spatrick case ParsedAttr::AT_CPUSpecific:
8779e5dd7070Spatrick handleCPUSpecificAttr(S, D, AL);
8780e5dd7070Spatrick break;
8781e5dd7070Spatrick case ParsedAttr::AT_Common:
8782e5dd7070Spatrick handleCommonAttr(S, D, AL);
8783e5dd7070Spatrick break;
8784e5dd7070Spatrick case ParsedAttr::AT_CUDAConstant:
8785e5dd7070Spatrick handleConstantAttr(S, D, AL);
8786e5dd7070Spatrick break;
8787e5dd7070Spatrick case ParsedAttr::AT_PassObjectSize:
8788e5dd7070Spatrick handlePassObjectSizeAttr(S, D, AL);
8789e5dd7070Spatrick break;
8790e5dd7070Spatrick case ParsedAttr::AT_Constructor:
8791e5dd7070Spatrick handleConstructorAttr(S, D, AL);
8792e5dd7070Spatrick break;
8793e5dd7070Spatrick case ParsedAttr::AT_Deprecated:
8794e5dd7070Spatrick handleDeprecatedAttr(S, D, AL);
8795e5dd7070Spatrick break;
8796e5dd7070Spatrick case ParsedAttr::AT_Destructor:
8797e5dd7070Spatrick handleDestructorAttr(S, D, AL);
8798e5dd7070Spatrick break;
8799e5dd7070Spatrick case ParsedAttr::AT_EnableIf:
8800e5dd7070Spatrick handleEnableIfAttr(S, D, AL);
8801e5dd7070Spatrick break;
8802*7a9b00ceSrobert case ParsedAttr::AT_Error:
8803*7a9b00ceSrobert handleErrorAttr(S, D, AL);
8804*7a9b00ceSrobert break;
8805e5dd7070Spatrick case ParsedAttr::AT_DiagnoseIf:
8806e5dd7070Spatrick handleDiagnoseIfAttr(S, D, AL);
8807e5dd7070Spatrick break;
8808*7a9b00ceSrobert case ParsedAttr::AT_DiagnoseAsBuiltin:
8809*7a9b00ceSrobert handleDiagnoseAsBuiltinAttr(S, D, AL);
8810*7a9b00ceSrobert break;
8811e5dd7070Spatrick case ParsedAttr::AT_NoBuiltin:
8812e5dd7070Spatrick handleNoBuiltinAttr(S, D, AL);
8813e5dd7070Spatrick break;
8814e5dd7070Spatrick case ParsedAttr::AT_ExtVectorType:
8815e5dd7070Spatrick handleExtVectorTypeAttr(S, D, AL);
8816e5dd7070Spatrick break;
8817e5dd7070Spatrick case ParsedAttr::AT_ExternalSourceSymbol:
8818e5dd7070Spatrick handleExternalSourceSymbolAttr(S, D, AL);
8819e5dd7070Spatrick break;
8820e5dd7070Spatrick case ParsedAttr::AT_MinSize:
8821e5dd7070Spatrick handleMinSizeAttr(S, D, AL);
8822e5dd7070Spatrick break;
8823e5dd7070Spatrick case ParsedAttr::AT_OptimizeNone:
8824e5dd7070Spatrick handleOptimizeNoneAttr(S, D, AL);
8825e5dd7070Spatrick break;
8826e5dd7070Spatrick case ParsedAttr::AT_EnumExtensibility:
8827e5dd7070Spatrick handleEnumExtensibilityAttr(S, D, AL);
8828e5dd7070Spatrick break;
8829e5dd7070Spatrick case ParsedAttr::AT_SYCLKernel:
8830e5dd7070Spatrick handleSYCLKernelAttr(S, D, AL);
8831e5dd7070Spatrick break;
8832*7a9b00ceSrobert case ParsedAttr::AT_SYCLSpecialClass:
8833*7a9b00ceSrobert handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
8834*7a9b00ceSrobert break;
8835e5dd7070Spatrick case ParsedAttr::AT_Format:
8836e5dd7070Spatrick handleFormatAttr(S, D, AL);
8837e5dd7070Spatrick break;
8838e5dd7070Spatrick case ParsedAttr::AT_FormatArg:
8839e5dd7070Spatrick handleFormatArgAttr(S, D, AL);
8840e5dd7070Spatrick break;
8841e5dd7070Spatrick case ParsedAttr::AT_Callback:
8842e5dd7070Spatrick handleCallbackAttr(S, D, AL);
8843e5dd7070Spatrick break;
8844a0747c9fSpatrick case ParsedAttr::AT_CalledOnce:
8845a0747c9fSpatrick handleCalledOnceAttr(S, D, AL);
8846a0747c9fSpatrick break;
8847e5dd7070Spatrick case ParsedAttr::AT_CUDAGlobal:
8848e5dd7070Spatrick handleGlobalAttr(S, D, AL);
8849e5dd7070Spatrick break;
8850e5dd7070Spatrick case ParsedAttr::AT_CUDADevice:
8851a0747c9fSpatrick handleDeviceAttr(S, D, AL);
8852e5dd7070Spatrick break;
8853a0747c9fSpatrick case ParsedAttr::AT_HIPManaged:
8854a0747c9fSpatrick handleManagedAttr(S, D, AL);
8855e5dd7070Spatrick break;
8856e5dd7070Spatrick case ParsedAttr::AT_GNUInline:
8857e5dd7070Spatrick handleGNUInlineAttr(S, D, AL);
8858e5dd7070Spatrick break;
8859e5dd7070Spatrick case ParsedAttr::AT_CUDALaunchBounds:
8860e5dd7070Spatrick handleLaunchBoundsAttr(S, D, AL);
8861e5dd7070Spatrick break;
8862e5dd7070Spatrick case ParsedAttr::AT_Restrict:
8863e5dd7070Spatrick handleRestrictAttr(S, D, AL);
8864e5dd7070Spatrick break;
8865e5dd7070Spatrick case ParsedAttr::AT_Mode:
8866e5dd7070Spatrick handleModeAttr(S, D, AL);
8867e5dd7070Spatrick break;
8868e5dd7070Spatrick case ParsedAttr::AT_NonNull:
8869e5dd7070Spatrick if (auto *PVD = dyn_cast<ParmVarDecl>(D))
8870e5dd7070Spatrick handleNonNullAttrParameter(S, PVD, AL);
8871e5dd7070Spatrick else
8872e5dd7070Spatrick handleNonNullAttr(S, D, AL);
8873e5dd7070Spatrick break;
8874e5dd7070Spatrick case ParsedAttr::AT_ReturnsNonNull:
8875e5dd7070Spatrick handleReturnsNonNullAttr(S, D, AL);
8876e5dd7070Spatrick break;
8877e5dd7070Spatrick case ParsedAttr::AT_NoEscape:
8878e5dd7070Spatrick handleNoEscapeAttr(S, D, AL);
8879e5dd7070Spatrick break;
8880*7a9b00ceSrobert case ParsedAttr::AT_MaybeUndef:
8881*7a9b00ceSrobert handleSimpleAttribute<MaybeUndefAttr>(S, D, AL);
8882*7a9b00ceSrobert break;
8883e5dd7070Spatrick case ParsedAttr::AT_AssumeAligned:
8884e5dd7070Spatrick handleAssumeAlignedAttr(S, D, AL);
8885e5dd7070Spatrick break;
8886e5dd7070Spatrick case ParsedAttr::AT_AllocAlign:
8887e5dd7070Spatrick handleAllocAlignAttr(S, D, AL);
8888e5dd7070Spatrick break;
8889e5dd7070Spatrick case ParsedAttr::AT_Ownership:
8890e5dd7070Spatrick handleOwnershipAttr(S, D, AL);
8891e5dd7070Spatrick break;
8892e5dd7070Spatrick case ParsedAttr::AT_Naked:
8893e5dd7070Spatrick handleNakedAttr(S, D, AL);
8894e5dd7070Spatrick break;
8895e5dd7070Spatrick case ParsedAttr::AT_NoReturn:
8896e5dd7070Spatrick handleNoReturnAttr(S, D, AL);
8897e5dd7070Spatrick break;
8898*7a9b00ceSrobert case ParsedAttr::AT_CXX11NoReturn:
8899*7a9b00ceSrobert handleStandardNoReturnAttr(S, D, AL);
8900*7a9b00ceSrobert break;
8901e5dd7070Spatrick case ParsedAttr::AT_AnyX86NoCfCheck:
8902e5dd7070Spatrick handleNoCfCheckAttr(S, D, AL);
8903e5dd7070Spatrick break;
8904e5dd7070Spatrick case ParsedAttr::AT_NoThrow:
8905e5dd7070Spatrick if (!AL.isUsedAsTypeAttr())
8906e5dd7070Spatrick handleSimpleAttribute<NoThrowAttr>(S, D, AL);
8907e5dd7070Spatrick break;
8908e5dd7070Spatrick case ParsedAttr::AT_CUDAShared:
8909e5dd7070Spatrick handleSharedAttr(S, D, AL);
8910e5dd7070Spatrick break;
8911e5dd7070Spatrick case ParsedAttr::AT_VecReturn:
8912e5dd7070Spatrick handleVecReturnAttr(S, D, AL);
8913e5dd7070Spatrick break;
8914e5dd7070Spatrick case ParsedAttr::AT_ObjCOwnership:
8915e5dd7070Spatrick handleObjCOwnershipAttr(S, D, AL);
8916e5dd7070Spatrick break;
8917e5dd7070Spatrick case ParsedAttr::AT_ObjCPreciseLifetime:
8918e5dd7070Spatrick handleObjCPreciseLifetimeAttr(S, D, AL);
8919e5dd7070Spatrick break;
8920e5dd7070Spatrick case ParsedAttr::AT_ObjCReturnsInnerPointer:
8921e5dd7070Spatrick handleObjCReturnsInnerPointerAttr(S, D, AL);
8922e5dd7070Spatrick break;
8923e5dd7070Spatrick case ParsedAttr::AT_ObjCRequiresSuper:
8924e5dd7070Spatrick handleObjCRequiresSuperAttr(S, D, AL);
8925e5dd7070Spatrick break;
8926e5dd7070Spatrick case ParsedAttr::AT_ObjCBridge:
8927e5dd7070Spatrick handleObjCBridgeAttr(S, D, AL);
8928e5dd7070Spatrick break;
8929e5dd7070Spatrick case ParsedAttr::AT_ObjCBridgeMutable:
8930e5dd7070Spatrick handleObjCBridgeMutableAttr(S, D, AL);
8931e5dd7070Spatrick break;
8932e5dd7070Spatrick case ParsedAttr::AT_ObjCBridgeRelated:
8933e5dd7070Spatrick handleObjCBridgeRelatedAttr(S, D, AL);
8934e5dd7070Spatrick break;
8935e5dd7070Spatrick case ParsedAttr::AT_ObjCDesignatedInitializer:
8936e5dd7070Spatrick handleObjCDesignatedInitializer(S, D, AL);
8937e5dd7070Spatrick break;
8938e5dd7070Spatrick case ParsedAttr::AT_ObjCRuntimeName:
8939e5dd7070Spatrick handleObjCRuntimeName(S, D, AL);
8940e5dd7070Spatrick break;
8941e5dd7070Spatrick case ParsedAttr::AT_ObjCBoxable:
8942e5dd7070Spatrick handleObjCBoxable(S, D, AL);
8943e5dd7070Spatrick break;
8944a0747c9fSpatrick case ParsedAttr::AT_NSErrorDomain:
8945a0747c9fSpatrick handleNSErrorDomain(S, D, AL);
8946e5dd7070Spatrick break;
8947e5dd7070Spatrick case ParsedAttr::AT_CFConsumed:
8948e5dd7070Spatrick case ParsedAttr::AT_NSConsumed:
8949e5dd7070Spatrick case ParsedAttr::AT_OSConsumed:
8950e5dd7070Spatrick S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
8951e5dd7070Spatrick /*IsTemplateInstantiation=*/false);
8952e5dd7070Spatrick break;
8953e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetainedOnZero:
8954e5dd7070Spatrick handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>(
8955e5dd7070Spatrick S, D, AL, isValidOSObjectOutParameter(D),
8956e5dd7070Spatrick diag::warn_ns_attribute_wrong_parameter_type,
8957e5dd7070Spatrick /*Extra Args=*/AL, /*pointer-to-OSObject-pointer*/ 3, AL.getRange());
8958e5dd7070Spatrick break;
8959e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
8960e5dd7070Spatrick handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnNonZeroAttr>(
8961e5dd7070Spatrick S, D, AL, isValidOSObjectOutParameter(D),
8962e5dd7070Spatrick diag::warn_ns_attribute_wrong_parameter_type,
8963e5dd7070Spatrick /*Extra Args=*/AL, /*pointer-to-OSObject-poointer*/ 3, AL.getRange());
8964e5dd7070Spatrick break;
8965e5dd7070Spatrick case ParsedAttr::AT_NSReturnsAutoreleased:
8966e5dd7070Spatrick case ParsedAttr::AT_NSReturnsNotRetained:
8967e5dd7070Spatrick case ParsedAttr::AT_NSReturnsRetained:
8968e5dd7070Spatrick case ParsedAttr::AT_CFReturnsNotRetained:
8969e5dd7070Spatrick case ParsedAttr::AT_CFReturnsRetained:
8970e5dd7070Spatrick case ParsedAttr::AT_OSReturnsNotRetained:
8971e5dd7070Spatrick case ParsedAttr::AT_OSReturnsRetained:
8972e5dd7070Spatrick handleXReturnsXRetainedAttr(S, D, AL);
8973e5dd7070Spatrick break;
8974e5dd7070Spatrick case ParsedAttr::AT_WorkGroupSizeHint:
8975e5dd7070Spatrick handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL);
8976e5dd7070Spatrick break;
8977e5dd7070Spatrick case ParsedAttr::AT_ReqdWorkGroupSize:
8978e5dd7070Spatrick handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL);
8979e5dd7070Spatrick break;
8980e5dd7070Spatrick case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize:
8981e5dd7070Spatrick handleSubGroupSize(S, D, AL);
8982e5dd7070Spatrick break;
8983e5dd7070Spatrick case ParsedAttr::AT_VecTypeHint:
8984e5dd7070Spatrick handleVecTypeHint(S, D, AL);
8985e5dd7070Spatrick break;
8986e5dd7070Spatrick case ParsedAttr::AT_InitPriority:
8987e5dd7070Spatrick handleInitPriorityAttr(S, D, AL);
8988e5dd7070Spatrick break;
8989e5dd7070Spatrick case ParsedAttr::AT_Packed:
8990e5dd7070Spatrick handlePackedAttr(S, D, AL);
8991e5dd7070Spatrick break;
8992a0747c9fSpatrick case ParsedAttr::AT_PreferredName:
8993a0747c9fSpatrick handlePreferredName(S, D, AL);
8994a0747c9fSpatrick break;
8995e5dd7070Spatrick case ParsedAttr::AT_Section:
8996e5dd7070Spatrick handleSectionAttr(S, D, AL);
8997e5dd7070Spatrick break;
8998*7a9b00ceSrobert case ParsedAttr::AT_RandomizeLayout:
8999*7a9b00ceSrobert handleRandomizeLayoutAttr(S, D, AL);
9000*7a9b00ceSrobert break;
9001*7a9b00ceSrobert case ParsedAttr::AT_NoRandomizeLayout:
9002*7a9b00ceSrobert handleNoRandomizeLayoutAttr(S, D, AL);
9003*7a9b00ceSrobert break;
9004e5dd7070Spatrick case ParsedAttr::AT_CodeSeg:
9005e5dd7070Spatrick handleCodeSegAttr(S, D, AL);
9006e5dd7070Spatrick break;
9007e5dd7070Spatrick case ParsedAttr::AT_Target:
9008e5dd7070Spatrick handleTargetAttr(S, D, AL);
9009e5dd7070Spatrick break;
9010*7a9b00ceSrobert case ParsedAttr::AT_TargetVersion:
9011*7a9b00ceSrobert handleTargetVersionAttr(S, D, AL);
9012*7a9b00ceSrobert break;
9013*7a9b00ceSrobert case ParsedAttr::AT_TargetClones:
9014*7a9b00ceSrobert handleTargetClonesAttr(S, D, AL);
9015*7a9b00ceSrobert break;
9016e5dd7070Spatrick case ParsedAttr::AT_MinVectorWidth:
9017e5dd7070Spatrick handleMinVectorWidthAttr(S, D, AL);
9018e5dd7070Spatrick break;
9019e5dd7070Spatrick case ParsedAttr::AT_Unavailable:
9020e5dd7070Spatrick handleAttrWithMessage<UnavailableAttr>(S, D, AL);
9021e5dd7070Spatrick break;
9022a0747c9fSpatrick case ParsedAttr::AT_Assumption:
9023a0747c9fSpatrick handleAssumumptionAttr(S, D, AL);
9024a0747c9fSpatrick break;
9025e5dd7070Spatrick case ParsedAttr::AT_ObjCDirect:
9026e5dd7070Spatrick handleObjCDirectAttr(S, D, AL);
9027e5dd7070Spatrick break;
9028e5dd7070Spatrick case ParsedAttr::AT_ObjCDirectMembers:
9029e5dd7070Spatrick handleObjCDirectMembersAttr(S, D, AL);
9030e5dd7070Spatrick handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
9031e5dd7070Spatrick break;
9032e5dd7070Spatrick case ParsedAttr::AT_ObjCExplicitProtocolImpl:
9033e5dd7070Spatrick handleObjCSuppresProtocolAttr(S, D, AL);
9034e5dd7070Spatrick break;
9035e5dd7070Spatrick case ParsedAttr::AT_Unused:
9036e5dd7070Spatrick handleUnusedAttr(S, D, AL);
9037e5dd7070Spatrick break;
9038e5dd7070Spatrick case ParsedAttr::AT_Visibility:
9039e5dd7070Spatrick handleVisibilityAttr(S, D, AL, false);
9040e5dd7070Spatrick break;
9041e5dd7070Spatrick case ParsedAttr::AT_TypeVisibility:
9042e5dd7070Spatrick handleVisibilityAttr(S, D, AL, true);
9043e5dd7070Spatrick break;
9044e5dd7070Spatrick case ParsedAttr::AT_WarnUnusedResult:
9045e5dd7070Spatrick handleWarnUnusedResult(S, D, AL);
9046e5dd7070Spatrick break;
9047e5dd7070Spatrick case ParsedAttr::AT_WeakRef:
9048e5dd7070Spatrick handleWeakRefAttr(S, D, AL);
9049e5dd7070Spatrick break;
9050e5dd7070Spatrick case ParsedAttr::AT_WeakImport:
9051e5dd7070Spatrick handleWeakImportAttr(S, D, AL);
9052e5dd7070Spatrick break;
9053e5dd7070Spatrick case ParsedAttr::AT_TransparentUnion:
9054e5dd7070Spatrick handleTransparentUnionAttr(S, D, AL);
9055e5dd7070Spatrick break;
9056e5dd7070Spatrick case ParsedAttr::AT_ObjCMethodFamily:
9057e5dd7070Spatrick handleObjCMethodFamilyAttr(S, D, AL);
9058e5dd7070Spatrick break;
9059e5dd7070Spatrick case ParsedAttr::AT_ObjCNSObject:
9060e5dd7070Spatrick handleObjCNSObject(S, D, AL);
9061e5dd7070Spatrick break;
9062e5dd7070Spatrick case ParsedAttr::AT_ObjCIndependentClass:
9063e5dd7070Spatrick handleObjCIndependentClass(S, D, AL);
9064e5dd7070Spatrick break;
9065e5dd7070Spatrick case ParsedAttr::AT_Blocks:
9066e5dd7070Spatrick handleBlocksAttr(S, D, AL);
9067e5dd7070Spatrick break;
9068e5dd7070Spatrick case ParsedAttr::AT_Sentinel:
9069e5dd7070Spatrick handleSentinelAttr(S, D, AL);
9070e5dd7070Spatrick break;
9071e5dd7070Spatrick case ParsedAttr::AT_Cleanup:
9072e5dd7070Spatrick handleCleanupAttr(S, D, AL);
9073e5dd7070Spatrick break;
9074e5dd7070Spatrick case ParsedAttr::AT_NoDebug:
9075e5dd7070Spatrick handleNoDebugAttr(S, D, AL);
9076e5dd7070Spatrick break;
9077ec727ea7Spatrick case ParsedAttr::AT_CmseNSEntry:
9078ec727ea7Spatrick handleCmseNSEntryAttr(S, D, AL);
9079e5dd7070Spatrick break;
9080e5dd7070Spatrick case ParsedAttr::AT_StdCall:
9081e5dd7070Spatrick case ParsedAttr::AT_CDecl:
9082e5dd7070Spatrick case ParsedAttr::AT_FastCall:
9083e5dd7070Spatrick case ParsedAttr::AT_ThisCall:
9084e5dd7070Spatrick case ParsedAttr::AT_Pascal:
9085e5dd7070Spatrick case ParsedAttr::AT_RegCall:
9086e5dd7070Spatrick case ParsedAttr::AT_SwiftCall:
9087a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncCall:
9088e5dd7070Spatrick case ParsedAttr::AT_VectorCall:
9089e5dd7070Spatrick case ParsedAttr::AT_MSABI:
9090e5dd7070Spatrick case ParsedAttr::AT_SysVABI:
9091e5dd7070Spatrick case ParsedAttr::AT_Pcs:
9092e5dd7070Spatrick case ParsedAttr::AT_IntelOclBicc:
9093e5dd7070Spatrick case ParsedAttr::AT_PreserveMost:
9094e5dd7070Spatrick case ParsedAttr::AT_PreserveAll:
9095e5dd7070Spatrick case ParsedAttr::AT_AArch64VectorPcs:
9096*7a9b00ceSrobert case ParsedAttr::AT_AArch64SVEPcs:
9097*7a9b00ceSrobert case ParsedAttr::AT_AMDGPUKernelCall:
9098e5dd7070Spatrick handleCallConvAttr(S, D, AL);
9099e5dd7070Spatrick break;
9100e5dd7070Spatrick case ParsedAttr::AT_Suppress:
9101e5dd7070Spatrick handleSuppressAttr(S, D, AL);
9102e5dd7070Spatrick break;
9103e5dd7070Spatrick case ParsedAttr::AT_Owner:
9104e5dd7070Spatrick case ParsedAttr::AT_Pointer:
9105e5dd7070Spatrick handleLifetimeCategoryAttr(S, D, AL);
9106e5dd7070Spatrick break;
9107e5dd7070Spatrick case ParsedAttr::AT_OpenCLAccess:
9108e5dd7070Spatrick handleOpenCLAccessAttr(S, D, AL);
9109e5dd7070Spatrick break;
9110e5dd7070Spatrick case ParsedAttr::AT_OpenCLNoSVM:
9111e5dd7070Spatrick handleOpenCLNoSVMAttr(S, D, AL);
9112e5dd7070Spatrick break;
9113e5dd7070Spatrick case ParsedAttr::AT_SwiftContext:
9114e5dd7070Spatrick S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
9115e5dd7070Spatrick break;
9116a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncContext:
9117a0747c9fSpatrick S.AddParameterABIAttr(D, AL, ParameterABI::SwiftAsyncContext);
9118a0747c9fSpatrick break;
9119e5dd7070Spatrick case ParsedAttr::AT_SwiftErrorResult:
9120e5dd7070Spatrick S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
9121e5dd7070Spatrick break;
9122e5dd7070Spatrick case ParsedAttr::AT_SwiftIndirectResult:
9123e5dd7070Spatrick S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
9124e5dd7070Spatrick break;
9125e5dd7070Spatrick case ParsedAttr::AT_InternalLinkage:
9126e5dd7070Spatrick handleInternalLinkageAttr(S, D, AL);
9127e5dd7070Spatrick break;
9128*7a9b00ceSrobert case ParsedAttr::AT_ZeroCallUsedRegs:
9129*7a9b00ceSrobert handleZeroCallUsedRegsAttr(S, D, AL);
9130*7a9b00ceSrobert break;
9131*7a9b00ceSrobert case ParsedAttr::AT_FunctionReturnThunks:
9132*7a9b00ceSrobert handleFunctionReturnThunksAttr(S, D, AL);
9133*7a9b00ceSrobert break;
9134e5dd7070Spatrick
9135e5dd7070Spatrick // Microsoft attributes:
9136e5dd7070Spatrick case ParsedAttr::AT_LayoutVersion:
9137e5dd7070Spatrick handleLayoutVersion(S, D, AL);
9138e5dd7070Spatrick break;
9139e5dd7070Spatrick case ParsedAttr::AT_Uuid:
9140e5dd7070Spatrick handleUuidAttr(S, D, AL);
9141e5dd7070Spatrick break;
9142e5dd7070Spatrick case ParsedAttr::AT_MSInheritance:
9143e5dd7070Spatrick handleMSInheritanceAttr(S, D, AL);
9144e5dd7070Spatrick break;
9145e5dd7070Spatrick case ParsedAttr::AT_Thread:
9146e5dd7070Spatrick handleDeclspecThreadAttr(S, D, AL);
9147e5dd7070Spatrick break;
9148e5dd7070Spatrick
9149*7a9b00ceSrobert // HLSL attributes:
9150*7a9b00ceSrobert case ParsedAttr::AT_HLSLNumThreads:
9151*7a9b00ceSrobert handleHLSLNumThreadsAttr(S, D, AL);
9152*7a9b00ceSrobert break;
9153*7a9b00ceSrobert case ParsedAttr::AT_HLSLSV_GroupIndex:
9154*7a9b00ceSrobert handleHLSLSVGroupIndexAttr(S, D, AL);
9155*7a9b00ceSrobert break;
9156*7a9b00ceSrobert case ParsedAttr::AT_HLSLSV_DispatchThreadID:
9157*7a9b00ceSrobert handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
9158*7a9b00ceSrobert break;
9159*7a9b00ceSrobert case ParsedAttr::AT_HLSLShader:
9160*7a9b00ceSrobert handleHLSLShaderAttr(S, D, AL);
9161*7a9b00ceSrobert break;
9162*7a9b00ceSrobert case ParsedAttr::AT_HLSLResourceBinding:
9163*7a9b00ceSrobert handleHLSLResourceBindingAttr(S, D, AL);
9164*7a9b00ceSrobert break;
9165*7a9b00ceSrobert
9166e5dd7070Spatrick case ParsedAttr::AT_AbiTag:
9167e5dd7070Spatrick handleAbiTagAttr(S, D, AL);
9168e5dd7070Spatrick break;
9169e5dd7070Spatrick case ParsedAttr::AT_CFGuard:
9170e5dd7070Spatrick handleCFGuardAttr(S, D, AL);
9171e5dd7070Spatrick break;
9172e5dd7070Spatrick
9173e5dd7070Spatrick // Thread safety attributes:
9174e5dd7070Spatrick case ParsedAttr::AT_AssertExclusiveLock:
9175e5dd7070Spatrick handleAssertExclusiveLockAttr(S, D, AL);
9176e5dd7070Spatrick break;
9177e5dd7070Spatrick case ParsedAttr::AT_AssertSharedLock:
9178e5dd7070Spatrick handleAssertSharedLockAttr(S, D, AL);
9179e5dd7070Spatrick break;
9180e5dd7070Spatrick case ParsedAttr::AT_PtGuardedVar:
9181e5dd7070Spatrick handlePtGuardedVarAttr(S, D, AL);
9182e5dd7070Spatrick break;
9183e5dd7070Spatrick case ParsedAttr::AT_NoSanitize:
9184e5dd7070Spatrick handleNoSanitizeAttr(S, D, AL);
9185e5dd7070Spatrick break;
9186e5dd7070Spatrick case ParsedAttr::AT_NoSanitizeSpecific:
9187e5dd7070Spatrick handleNoSanitizeSpecificAttr(S, D, AL);
9188e5dd7070Spatrick break;
9189e5dd7070Spatrick case ParsedAttr::AT_GuardedBy:
9190e5dd7070Spatrick handleGuardedByAttr(S, D, AL);
9191e5dd7070Spatrick break;
9192e5dd7070Spatrick case ParsedAttr::AT_PtGuardedBy:
9193e5dd7070Spatrick handlePtGuardedByAttr(S, D, AL);
9194e5dd7070Spatrick break;
9195e5dd7070Spatrick case ParsedAttr::AT_ExclusiveTrylockFunction:
9196e5dd7070Spatrick handleExclusiveTrylockFunctionAttr(S, D, AL);
9197e5dd7070Spatrick break;
9198e5dd7070Spatrick case ParsedAttr::AT_LockReturned:
9199e5dd7070Spatrick handleLockReturnedAttr(S, D, AL);
9200e5dd7070Spatrick break;
9201e5dd7070Spatrick case ParsedAttr::AT_LocksExcluded:
9202e5dd7070Spatrick handleLocksExcludedAttr(S, D, AL);
9203e5dd7070Spatrick break;
9204e5dd7070Spatrick case ParsedAttr::AT_SharedTrylockFunction:
9205e5dd7070Spatrick handleSharedTrylockFunctionAttr(S, D, AL);
9206e5dd7070Spatrick break;
9207e5dd7070Spatrick case ParsedAttr::AT_AcquiredBefore:
9208e5dd7070Spatrick handleAcquiredBeforeAttr(S, D, AL);
9209e5dd7070Spatrick break;
9210e5dd7070Spatrick case ParsedAttr::AT_AcquiredAfter:
9211e5dd7070Spatrick handleAcquiredAfterAttr(S, D, AL);
9212e5dd7070Spatrick break;
9213e5dd7070Spatrick
9214e5dd7070Spatrick // Capability analysis attributes.
9215e5dd7070Spatrick case ParsedAttr::AT_Capability:
9216e5dd7070Spatrick case ParsedAttr::AT_Lockable:
9217e5dd7070Spatrick handleCapabilityAttr(S, D, AL);
9218e5dd7070Spatrick break;
9219e5dd7070Spatrick case ParsedAttr::AT_RequiresCapability:
9220e5dd7070Spatrick handleRequiresCapabilityAttr(S, D, AL);
9221e5dd7070Spatrick break;
9222e5dd7070Spatrick
9223e5dd7070Spatrick case ParsedAttr::AT_AssertCapability:
9224e5dd7070Spatrick handleAssertCapabilityAttr(S, D, AL);
9225e5dd7070Spatrick break;
9226e5dd7070Spatrick case ParsedAttr::AT_AcquireCapability:
9227e5dd7070Spatrick handleAcquireCapabilityAttr(S, D, AL);
9228e5dd7070Spatrick break;
9229e5dd7070Spatrick case ParsedAttr::AT_ReleaseCapability:
9230e5dd7070Spatrick handleReleaseCapabilityAttr(S, D, AL);
9231e5dd7070Spatrick break;
9232e5dd7070Spatrick case ParsedAttr::AT_TryAcquireCapability:
9233e5dd7070Spatrick handleTryAcquireCapabilityAttr(S, D, AL);
9234e5dd7070Spatrick break;
9235e5dd7070Spatrick
9236e5dd7070Spatrick // Consumed analysis attributes.
9237e5dd7070Spatrick case ParsedAttr::AT_Consumable:
9238e5dd7070Spatrick handleConsumableAttr(S, D, AL);
9239e5dd7070Spatrick break;
9240e5dd7070Spatrick case ParsedAttr::AT_CallableWhen:
9241e5dd7070Spatrick handleCallableWhenAttr(S, D, AL);
9242e5dd7070Spatrick break;
9243e5dd7070Spatrick case ParsedAttr::AT_ParamTypestate:
9244e5dd7070Spatrick handleParamTypestateAttr(S, D, AL);
9245e5dd7070Spatrick break;
9246e5dd7070Spatrick case ParsedAttr::AT_ReturnTypestate:
9247e5dd7070Spatrick handleReturnTypestateAttr(S, D, AL);
9248e5dd7070Spatrick break;
9249e5dd7070Spatrick case ParsedAttr::AT_SetTypestate:
9250e5dd7070Spatrick handleSetTypestateAttr(S, D, AL);
9251e5dd7070Spatrick break;
9252e5dd7070Spatrick case ParsedAttr::AT_TestTypestate:
9253e5dd7070Spatrick handleTestTypestateAttr(S, D, AL);
9254e5dd7070Spatrick break;
9255e5dd7070Spatrick
9256e5dd7070Spatrick // Type safety attributes.
9257e5dd7070Spatrick case ParsedAttr::AT_ArgumentWithTypeTag:
9258e5dd7070Spatrick handleArgumentWithTypeTagAttr(S, D, AL);
9259e5dd7070Spatrick break;
9260e5dd7070Spatrick case ParsedAttr::AT_TypeTagForDatatype:
9261e5dd7070Spatrick handleTypeTagForDatatypeAttr(S, D, AL);
9262e5dd7070Spatrick break;
9263ec727ea7Spatrick
9264a0747c9fSpatrick // Swift attributes.
9265a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncName:
9266a0747c9fSpatrick handleSwiftAsyncName(S, D, AL);
9267a0747c9fSpatrick break;
9268a0747c9fSpatrick case ParsedAttr::AT_SwiftAttr:
9269a0747c9fSpatrick handleSwiftAttrAttr(S, D, AL);
9270a0747c9fSpatrick break;
9271a0747c9fSpatrick case ParsedAttr::AT_SwiftBridge:
9272a0747c9fSpatrick handleSwiftBridge(S, D, AL);
9273a0747c9fSpatrick break;
9274a0747c9fSpatrick case ParsedAttr::AT_SwiftError:
9275a0747c9fSpatrick handleSwiftError(S, D, AL);
9276a0747c9fSpatrick break;
9277a0747c9fSpatrick case ParsedAttr::AT_SwiftName:
9278a0747c9fSpatrick handleSwiftName(S, D, AL);
9279a0747c9fSpatrick break;
9280a0747c9fSpatrick case ParsedAttr::AT_SwiftNewType:
9281a0747c9fSpatrick handleSwiftNewType(S, D, AL);
9282a0747c9fSpatrick break;
9283a0747c9fSpatrick case ParsedAttr::AT_SwiftAsync:
9284a0747c9fSpatrick handleSwiftAsyncAttr(S, D, AL);
9285a0747c9fSpatrick break;
9286a0747c9fSpatrick case ParsedAttr::AT_SwiftAsyncError:
9287a0747c9fSpatrick handleSwiftAsyncError(S, D, AL);
9288a0747c9fSpatrick break;
9289a0747c9fSpatrick
9290e5dd7070Spatrick // XRay attributes.
9291e5dd7070Spatrick case ParsedAttr::AT_XRayLogArgs:
9292e5dd7070Spatrick handleXRayLogArgsAttr(S, D, AL);
9293e5dd7070Spatrick break;
9294e5dd7070Spatrick
9295e5dd7070Spatrick case ParsedAttr::AT_PatchableFunctionEntry:
9296e5dd7070Spatrick handlePatchableFunctionEntryAttr(S, D, AL);
9297e5dd7070Spatrick break;
9298e5dd7070Spatrick
9299e5dd7070Spatrick case ParsedAttr::AT_AlwaysDestroy:
9300e5dd7070Spatrick case ParsedAttr::AT_NoDestroy:
9301e5dd7070Spatrick handleDestroyAttr(S, D, AL);
9302e5dd7070Spatrick break;
9303e5dd7070Spatrick
9304e5dd7070Spatrick case ParsedAttr::AT_Uninitialized:
9305e5dd7070Spatrick handleUninitializedAttr(S, D, AL);
9306e5dd7070Spatrick break;
9307e5dd7070Spatrick
9308e5dd7070Spatrick case ParsedAttr::AT_ObjCExternallyRetained:
9309e5dd7070Spatrick handleObjCExternallyRetainedAttr(S, D, AL);
9310e5dd7070Spatrick break;
9311e5dd7070Spatrick
9312e5dd7070Spatrick case ParsedAttr::AT_MIGServerRoutine:
9313e5dd7070Spatrick handleMIGServerRoutineAttr(S, D, AL);
9314e5dd7070Spatrick break;
9315e5dd7070Spatrick
9316e5dd7070Spatrick case ParsedAttr::AT_MSAllocator:
9317e5dd7070Spatrick handleMSAllocatorAttr(S, D, AL);
9318e5dd7070Spatrick break;
9319e5dd7070Spatrick
9320ec727ea7Spatrick case ParsedAttr::AT_ArmBuiltinAlias:
9321ec727ea7Spatrick handleArmBuiltinAliasAttr(S, D, AL);
9322e5dd7070Spatrick break;
9323e5dd7070Spatrick
9324e5dd7070Spatrick case ParsedAttr::AT_AcquireHandle:
9325ec727ea7Spatrick handleAcquireHandleAttr(S, D, AL);
9326e5dd7070Spatrick break;
9327e5dd7070Spatrick
9328e5dd7070Spatrick case ParsedAttr::AT_ReleaseHandle:
9329e5dd7070Spatrick handleHandleAttr<ReleaseHandleAttr>(S, D, AL);
9330e5dd7070Spatrick break;
9331e5dd7070Spatrick
9332e5dd7070Spatrick case ParsedAttr::AT_UseHandle:
9333e5dd7070Spatrick handleHandleAttr<UseHandleAttr>(S, D, AL);
9334e5dd7070Spatrick break;
9335a0747c9fSpatrick
9336a0747c9fSpatrick case ParsedAttr::AT_EnforceTCB:
9337a0747c9fSpatrick handleEnforceTCBAttr<EnforceTCBAttr, EnforceTCBLeafAttr>(S, D, AL);
9338a0747c9fSpatrick break;
9339a0747c9fSpatrick
9340a0747c9fSpatrick case ParsedAttr::AT_EnforceTCBLeaf:
9341a0747c9fSpatrick handleEnforceTCBAttr<EnforceTCBLeafAttr, EnforceTCBAttr>(S, D, AL);
9342a0747c9fSpatrick break;
9343a0747c9fSpatrick
9344a0747c9fSpatrick case ParsedAttr::AT_BuiltinAlias:
9345a0747c9fSpatrick handleBuiltinAliasAttr(S, D, AL);
9346a0747c9fSpatrick break;
9347a0747c9fSpatrick
9348a0747c9fSpatrick case ParsedAttr::AT_UsingIfExists:
9349a0747c9fSpatrick handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
9350a0747c9fSpatrick break;
9351e5dd7070Spatrick }
9352e5dd7070Spatrick }
9353e5dd7070Spatrick
9354e5dd7070Spatrick /// ProcessDeclAttributeList - Apply all the decl attributes in the specified
9355e5dd7070Spatrick /// attribute list to the specified decl, ignoring any type attributes.
ProcessDeclAttributeList(Scope * S,Decl * D,const ParsedAttributesView & AttrList,const ProcessDeclAttributeOptions & Options)9356*7a9b00ceSrobert void Sema::ProcessDeclAttributeList(
9357*7a9b00ceSrobert Scope *S, Decl *D, const ParsedAttributesView &AttrList,
9358*7a9b00ceSrobert const ProcessDeclAttributeOptions &Options) {
9359e5dd7070Spatrick if (AttrList.empty())
9360e5dd7070Spatrick return;
9361e5dd7070Spatrick
9362e5dd7070Spatrick for (const ParsedAttr &AL : AttrList)
9363*7a9b00ceSrobert ProcessDeclAttribute(*this, S, D, AL, Options);
9364e5dd7070Spatrick
9365e5dd7070Spatrick // FIXME: We should be able to handle these cases in TableGen.
9366e5dd7070Spatrick // GCC accepts
9367e5dd7070Spatrick // static int a9 __attribute__((weakref));
9368e5dd7070Spatrick // but that looks really pointless. We reject it.
9369e5dd7070Spatrick if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
9370e5dd7070Spatrick Diag(AttrList.begin()->getLoc(), diag::err_attribute_weakref_without_alias)
9371e5dd7070Spatrick << cast<NamedDecl>(D);
9372e5dd7070Spatrick D->dropAttr<WeakRefAttr>();
9373e5dd7070Spatrick return;
9374e5dd7070Spatrick }
9375e5dd7070Spatrick
9376e5dd7070Spatrick // FIXME: We should be able to handle this in TableGen as well. It would be
9377e5dd7070Spatrick // good to have a way to specify "these attributes must appear as a group",
9378e5dd7070Spatrick // for these. Additionally, it would be good to have a way to specify "these
9379e5dd7070Spatrick // attribute must never appear as a group" for attributes like cold and hot.
9380e5dd7070Spatrick if (!D->hasAttr<OpenCLKernelAttr>()) {
9381e5dd7070Spatrick // These attributes cannot be applied to a non-kernel function.
9382e5dd7070Spatrick if (const auto *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
9383e5dd7070Spatrick // FIXME: This emits a different error message than
9384e5dd7070Spatrick // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction.
9385e5dd7070Spatrick Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
9386e5dd7070Spatrick D->setInvalidDecl();
9387e5dd7070Spatrick } else if (const auto *A = D->getAttr<WorkGroupSizeHintAttr>()) {
9388e5dd7070Spatrick Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
9389e5dd7070Spatrick D->setInvalidDecl();
9390e5dd7070Spatrick } else if (const auto *A = D->getAttr<VecTypeHintAttr>()) {
9391e5dd7070Spatrick Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
9392e5dd7070Spatrick D->setInvalidDecl();
9393e5dd7070Spatrick } else if (const auto *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) {
9394e5dd7070Spatrick Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
9395e5dd7070Spatrick D->setInvalidDecl();
9396e5dd7070Spatrick } else if (!D->hasAttr<CUDAGlobalAttr>()) {
9397e5dd7070Spatrick if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
9398e5dd7070Spatrick Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
9399e5dd7070Spatrick << A << ExpectedKernelFunction;
9400e5dd7070Spatrick D->setInvalidDecl();
9401e5dd7070Spatrick } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) {
9402e5dd7070Spatrick Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
9403e5dd7070Spatrick << A << ExpectedKernelFunction;
9404e5dd7070Spatrick D->setInvalidDecl();
9405e5dd7070Spatrick } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) {
9406e5dd7070Spatrick Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
9407e5dd7070Spatrick << A << ExpectedKernelFunction;
9408e5dd7070Spatrick D->setInvalidDecl();
9409e5dd7070Spatrick } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) {
9410e5dd7070Spatrick Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
9411e5dd7070Spatrick << A << ExpectedKernelFunction;
9412e5dd7070Spatrick D->setInvalidDecl();
9413e5dd7070Spatrick }
9414e5dd7070Spatrick }
9415e5dd7070Spatrick }
9416e5dd7070Spatrick
9417e5dd7070Spatrick // Do this check after processing D's attributes because the attribute
9418e5dd7070Spatrick // objc_method_family can change whether the given method is in the init
9419e5dd7070Spatrick // family, and it can be applied after objc_designated_initializer. This is a
9420e5dd7070Spatrick // bit of a hack, but we need it to be compatible with versions of clang that
9421e5dd7070Spatrick // processed the attribute list in the wrong order.
9422e5dd7070Spatrick if (D->hasAttr<ObjCDesignatedInitializerAttr>() &&
9423e5dd7070Spatrick cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) {
9424e5dd7070Spatrick Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
9425e5dd7070Spatrick D->dropAttr<ObjCDesignatedInitializerAttr>();
9426e5dd7070Spatrick }
9427e5dd7070Spatrick }
9428e5dd7070Spatrick
9429e5dd7070Spatrick // Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr
9430e5dd7070Spatrick // attribute.
ProcessDeclAttributeDelayed(Decl * D,const ParsedAttributesView & AttrList)9431e5dd7070Spatrick void Sema::ProcessDeclAttributeDelayed(Decl *D,
9432e5dd7070Spatrick const ParsedAttributesView &AttrList) {
9433e5dd7070Spatrick for (const ParsedAttr &AL : AttrList)
9434e5dd7070Spatrick if (AL.getKind() == ParsedAttr::AT_TransparentUnion) {
9435e5dd7070Spatrick handleTransparentUnionAttr(*this, D, AL);
9436e5dd7070Spatrick break;
9437e5dd7070Spatrick }
9438e5dd7070Spatrick
9439e5dd7070Spatrick // For BPFPreserveAccessIndexAttr, we want to populate the attributes
9440e5dd7070Spatrick // to fields and inner records as well.
9441e5dd7070Spatrick if (D && D->hasAttr<BPFPreserveAccessIndexAttr>())
9442e5dd7070Spatrick handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D));
9443e5dd7070Spatrick }
9444e5dd7070Spatrick
9445e5dd7070Spatrick // Annotation attributes are the only attributes allowed after an access
9446e5dd7070Spatrick // specifier.
ProcessAccessDeclAttributeList(AccessSpecDecl * ASDecl,const ParsedAttributesView & AttrList)9447e5dd7070Spatrick bool Sema::ProcessAccessDeclAttributeList(
9448e5dd7070Spatrick AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
9449e5dd7070Spatrick for (const ParsedAttr &AL : AttrList) {
9450e5dd7070Spatrick if (AL.getKind() == ParsedAttr::AT_Annotate) {
9451*7a9b00ceSrobert ProcessDeclAttribute(*this, nullptr, ASDecl, AL,
9452*7a9b00ceSrobert ProcessDeclAttributeOptions());
9453e5dd7070Spatrick } else {
9454e5dd7070Spatrick Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
9455e5dd7070Spatrick return true;
9456e5dd7070Spatrick }
9457e5dd7070Spatrick }
9458e5dd7070Spatrick return false;
9459e5dd7070Spatrick }
9460e5dd7070Spatrick
9461e5dd7070Spatrick /// checkUnusedDeclAttributes - Check a list of attributes to see if it
9462e5dd7070Spatrick /// contains any decl attributes that we should warn about.
checkUnusedDeclAttributes(Sema & S,const ParsedAttributesView & A)9463e5dd7070Spatrick static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
9464e5dd7070Spatrick for (const ParsedAttr &AL : A) {
9465e5dd7070Spatrick // Only warn if the attribute is an unignored, non-type attribute.
9466e5dd7070Spatrick if (AL.isUsedAsTypeAttr() || AL.isInvalid())
9467e5dd7070Spatrick continue;
9468e5dd7070Spatrick if (AL.getKind() == ParsedAttr::IgnoredAttribute)
9469e5dd7070Spatrick continue;
9470e5dd7070Spatrick
9471e5dd7070Spatrick if (AL.getKind() == ParsedAttr::UnknownAttribute) {
9472e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
9473e5dd7070Spatrick << AL << AL.getRange();
9474e5dd7070Spatrick } else {
9475e5dd7070Spatrick S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL
9476e5dd7070Spatrick << AL.getRange();
9477e5dd7070Spatrick }
9478e5dd7070Spatrick }
9479e5dd7070Spatrick }
9480e5dd7070Spatrick
9481e5dd7070Spatrick /// checkUnusedDeclAttributes - Given a declarator which is not being
9482e5dd7070Spatrick /// used to build a declaration, complain about any decl attributes
9483e5dd7070Spatrick /// which might be lying around on it.
checkUnusedDeclAttributes(Declarator & D)9484e5dd7070Spatrick void Sema::checkUnusedDeclAttributes(Declarator &D) {
9485*7a9b00ceSrobert ::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
9486e5dd7070Spatrick ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
9487e5dd7070Spatrick ::checkUnusedDeclAttributes(*this, D.getAttributes());
9488e5dd7070Spatrick for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
9489e5dd7070Spatrick ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs());
9490e5dd7070Spatrick }
9491e5dd7070Spatrick
9492e5dd7070Spatrick /// DeclClonePragmaWeak - clone existing decl (maybe definition),
9493e5dd7070Spatrick /// \#pragma weak needs a non-definition decl and source may not have one.
DeclClonePragmaWeak(NamedDecl * ND,const IdentifierInfo * II,SourceLocation Loc)9494*7a9b00ceSrobert NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
9495e5dd7070Spatrick SourceLocation Loc) {
9496e5dd7070Spatrick assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
9497e5dd7070Spatrick NamedDecl *NewD = nullptr;
9498e5dd7070Spatrick if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
9499e5dd7070Spatrick FunctionDecl *NewFD;
9500e5dd7070Spatrick // FIXME: Missing call to CheckFunctionDeclaration().
9501e5dd7070Spatrick // FIXME: Mangling?
9502e5dd7070Spatrick // FIXME: Is the qualifier info correct?
9503e5dd7070Spatrick // FIXME: Is the DeclContext correct?
9504e5dd7070Spatrick NewFD = FunctionDecl::Create(
9505e5dd7070Spatrick FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
9506e5dd7070Spatrick DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
9507*7a9b00ceSrobert getCurFPFeatures().isFPConstrained(), false /*isInlineSpecified*/,
9508*7a9b00ceSrobert FD->hasPrototype(), ConstexprSpecKind::Unspecified,
9509*7a9b00ceSrobert FD->getTrailingRequiresClause());
9510e5dd7070Spatrick NewD = NewFD;
9511e5dd7070Spatrick
9512e5dd7070Spatrick if (FD->getQualifier())
9513e5dd7070Spatrick NewFD->setQualifierInfo(FD->getQualifierLoc());
9514e5dd7070Spatrick
9515e5dd7070Spatrick // Fake up parameter variables; they are declared as if this were
9516e5dd7070Spatrick // a typedef.
9517e5dd7070Spatrick QualType FDTy = FD->getType();
9518e5dd7070Spatrick if (const auto *FT = FDTy->getAs<FunctionProtoType>()) {
9519e5dd7070Spatrick SmallVector<ParmVarDecl*, 16> Params;
9520e5dd7070Spatrick for (const auto &AI : FT->param_types()) {
9521e5dd7070Spatrick ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI);
9522e5dd7070Spatrick Param->setScopeInfo(0, Params.size());
9523e5dd7070Spatrick Params.push_back(Param);
9524e5dd7070Spatrick }
9525e5dd7070Spatrick NewFD->setParams(Params);
9526e5dd7070Spatrick }
9527e5dd7070Spatrick } else if (auto *VD = dyn_cast<VarDecl>(ND)) {
9528e5dd7070Spatrick NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
9529e5dd7070Spatrick VD->getInnerLocStart(), VD->getLocation(), II,
9530e5dd7070Spatrick VD->getType(), VD->getTypeSourceInfo(),
9531e5dd7070Spatrick VD->getStorageClass());
9532e5dd7070Spatrick if (VD->getQualifier())
9533e5dd7070Spatrick cast<VarDecl>(NewD)->setQualifierInfo(VD->getQualifierLoc());
9534e5dd7070Spatrick }
9535e5dd7070Spatrick return NewD;
9536e5dd7070Spatrick }
9537e5dd7070Spatrick
9538e5dd7070Spatrick /// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
9539e5dd7070Spatrick /// applied to it, possibly with an alias.
DeclApplyPragmaWeak(Scope * S,NamedDecl * ND,const WeakInfo & W)9540*7a9b00ceSrobert void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) {
9541e5dd7070Spatrick if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
9542e5dd7070Spatrick IdentifierInfo *NDId = ND->getIdentifier();
9543e5dd7070Spatrick NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
9544e5dd7070Spatrick NewD->addAttr(
9545e5dd7070Spatrick AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation()));
9546e5dd7070Spatrick NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
9547e5dd7070Spatrick AttributeCommonInfo::AS_Pragma));
9548e5dd7070Spatrick WeakTopLevelDecl.push_back(NewD);
9549e5dd7070Spatrick // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
9550e5dd7070Spatrick // to insert Decl at TU scope, sorry.
9551e5dd7070Spatrick DeclContext *SavedContext = CurContext;
9552e5dd7070Spatrick CurContext = Context.getTranslationUnitDecl();
9553e5dd7070Spatrick NewD->setDeclContext(CurContext);
9554e5dd7070Spatrick NewD->setLexicalDeclContext(CurContext);
9555e5dd7070Spatrick PushOnScopeChains(NewD, S);
9556e5dd7070Spatrick CurContext = SavedContext;
9557e5dd7070Spatrick } else { // just add weak to existing
9558e5dd7070Spatrick ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
9559e5dd7070Spatrick AttributeCommonInfo::AS_Pragma));
9560e5dd7070Spatrick }
9561e5dd7070Spatrick }
9562e5dd7070Spatrick
ProcessPragmaWeak(Scope * S,Decl * D)9563e5dd7070Spatrick void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
9564e5dd7070Spatrick // It's valid to "forward-declare" #pragma weak, in which case we
9565e5dd7070Spatrick // have to do this.
9566e5dd7070Spatrick LoadExternalWeakUndeclaredIdentifiers();
9567*7a9b00ceSrobert if (WeakUndeclaredIdentifiers.empty())
9568*7a9b00ceSrobert return;
9569e5dd7070Spatrick NamedDecl *ND = nullptr;
9570e5dd7070Spatrick if (auto *VD = dyn_cast<VarDecl>(D))
9571e5dd7070Spatrick if (VD->isExternC())
9572e5dd7070Spatrick ND = VD;
9573e5dd7070Spatrick if (auto *FD = dyn_cast<FunctionDecl>(D))
9574e5dd7070Spatrick if (FD->isExternC())
9575e5dd7070Spatrick ND = FD;
9576*7a9b00ceSrobert if (!ND)
9577*7a9b00ceSrobert return;
9578e5dd7070Spatrick if (IdentifierInfo *Id = ND->getIdentifier()) {
9579e5dd7070Spatrick auto I = WeakUndeclaredIdentifiers.find(Id);
9580e5dd7070Spatrick if (I != WeakUndeclaredIdentifiers.end()) {
9581*7a9b00ceSrobert auto &WeakInfos = I->second;
9582*7a9b00ceSrobert for (const auto &W : WeakInfos)
9583e5dd7070Spatrick DeclApplyPragmaWeak(S, ND, W);
9584*7a9b00ceSrobert std::remove_reference_t<decltype(WeakInfos)> EmptyWeakInfos;
9585*7a9b00ceSrobert WeakInfos.swap(EmptyWeakInfos);
9586e5dd7070Spatrick }
9587e5dd7070Spatrick }
9588e5dd7070Spatrick }
9589e5dd7070Spatrick
9590e5dd7070Spatrick /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
9591e5dd7070Spatrick /// it, apply them to D. This is a bit tricky because PD can have attributes
9592e5dd7070Spatrick /// specified in many different places, and we need to find and apply them all.
ProcessDeclAttributes(Scope * S,Decl * D,const Declarator & PD)9593e5dd7070Spatrick void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
9594*7a9b00ceSrobert // Ordering of attributes can be important, so we take care to process
9595*7a9b00ceSrobert // attributes in the order in which they appeared in the source code.
9596*7a9b00ceSrobert
9597*7a9b00ceSrobert // First, process attributes that appeared on the declaration itself (but
9598*7a9b00ceSrobert // only if they don't have the legacy behavior of "sliding" to the DeclSepc).
9599*7a9b00ceSrobert ParsedAttributesView NonSlidingAttrs;
9600*7a9b00ceSrobert for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
9601*7a9b00ceSrobert if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
9602*7a9b00ceSrobert // Skip processing the attribute, but do check if it appertains to the
9603*7a9b00ceSrobert // declaration. This is needed for the `MatrixType` attribute, which,
9604*7a9b00ceSrobert // despite being a type attribute, defines a `SubjectList` that only
9605*7a9b00ceSrobert // allows it to be used on typedef declarations.
9606*7a9b00ceSrobert AL.diagnoseAppertainsTo(*this, D);
9607*7a9b00ceSrobert } else {
9608*7a9b00ceSrobert NonSlidingAttrs.addAtEnd(&AL);
9609*7a9b00ceSrobert }
9610*7a9b00ceSrobert }
9611*7a9b00ceSrobert ProcessDeclAttributeList(S, D, NonSlidingAttrs);
9612*7a9b00ceSrobert
9613e5dd7070Spatrick // Apply decl attributes from the DeclSpec if present.
9614*7a9b00ceSrobert if (!PD.getDeclSpec().getAttributes().empty()) {
9615*7a9b00ceSrobert ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes(),
9616*7a9b00ceSrobert ProcessDeclAttributeOptions()
9617*7a9b00ceSrobert .WithIncludeCXX11Attributes(false)
9618*7a9b00ceSrobert .WithIgnoreTypeAttributes(true));
9619*7a9b00ceSrobert }
9620e5dd7070Spatrick
9621e5dd7070Spatrick // Walk the declarator structure, applying decl attributes that were in a type
9622e5dd7070Spatrick // position to the decl itself. This handles cases like:
9623e5dd7070Spatrick // int *__attr__(x)** D;
9624e5dd7070Spatrick // when X is a decl attribute.
9625*7a9b00ceSrobert for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) {
9626e5dd7070Spatrick ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(),
9627*7a9b00ceSrobert ProcessDeclAttributeOptions()
9628*7a9b00ceSrobert .WithIncludeCXX11Attributes(false)
9629*7a9b00ceSrobert .WithIgnoreTypeAttributes(true));
9630*7a9b00ceSrobert }
9631e5dd7070Spatrick
9632e5dd7070Spatrick // Finally, apply any attributes on the decl itself.
9633e5dd7070Spatrick ProcessDeclAttributeList(S, D, PD.getAttributes());
9634e5dd7070Spatrick
9635e5dd7070Spatrick // Apply additional attributes specified by '#pragma clang attribute'.
9636e5dd7070Spatrick AddPragmaAttributes(S, D);
9637e5dd7070Spatrick }
9638e5dd7070Spatrick
9639e5dd7070Spatrick /// Is the given declaration allowed to use a forbidden type?
9640e5dd7070Spatrick /// If so, it'll still be annotated with an attribute that makes it
9641e5dd7070Spatrick /// illegal to actually use.
isForbiddenTypeAllowed(Sema & S,Decl * D,const DelayedDiagnostic & diag,UnavailableAttr::ImplicitReason & reason)9642e5dd7070Spatrick static bool isForbiddenTypeAllowed(Sema &S, Decl *D,
9643e5dd7070Spatrick const DelayedDiagnostic &diag,
9644e5dd7070Spatrick UnavailableAttr::ImplicitReason &reason) {
9645e5dd7070Spatrick // Private ivars are always okay. Unfortunately, people don't
9646e5dd7070Spatrick // always properly make their ivars private, even in system headers.
9647e5dd7070Spatrick // Plus we need to make fields okay, too.
9648e5dd7070Spatrick if (!isa<FieldDecl>(D) && !isa<ObjCPropertyDecl>(D) &&
9649e5dd7070Spatrick !isa<FunctionDecl>(D))
9650e5dd7070Spatrick return false;
9651e5dd7070Spatrick
9652e5dd7070Spatrick // Silently accept unsupported uses of __weak in both user and system
9653e5dd7070Spatrick // declarations when it's been disabled, for ease of integration with
9654e5dd7070Spatrick // -fno-objc-arc files. We do have to take some care against attempts
9655e5dd7070Spatrick // to define such things; for now, we've only done that for ivars
9656e5dd7070Spatrick // and properties.
9657e5dd7070Spatrick if ((isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) {
9658e5dd7070Spatrick if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled ||
9659e5dd7070Spatrick diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) {
9660e5dd7070Spatrick reason = UnavailableAttr::IR_ForbiddenWeak;
9661e5dd7070Spatrick return true;
9662e5dd7070Spatrick }
9663e5dd7070Spatrick }
9664e5dd7070Spatrick
9665e5dd7070Spatrick // Allow all sorts of things in system headers.
9666e5dd7070Spatrick if (S.Context.getSourceManager().isInSystemHeader(D->getLocation())) {
9667e5dd7070Spatrick // Currently, all the failures dealt with this way are due to ARC
9668e5dd7070Spatrick // restrictions.
9669e5dd7070Spatrick reason = UnavailableAttr::IR_ARCForbiddenType;
9670e5dd7070Spatrick return true;
9671e5dd7070Spatrick }
9672e5dd7070Spatrick
9673e5dd7070Spatrick return false;
9674e5dd7070Spatrick }
9675e5dd7070Spatrick
9676e5dd7070Spatrick /// Handle a delayed forbidden-type diagnostic.
handleDelayedForbiddenType(Sema & S,DelayedDiagnostic & DD,Decl * D)9677e5dd7070Spatrick static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD,
9678e5dd7070Spatrick Decl *D) {
9679e5dd7070Spatrick auto Reason = UnavailableAttr::IR_None;
9680e5dd7070Spatrick if (D && isForbiddenTypeAllowed(S, D, DD, Reason)) {
9681e5dd7070Spatrick assert(Reason && "didn't set reason?");
9682e5dd7070Spatrick D->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", Reason, DD.Loc));
9683e5dd7070Spatrick return;
9684e5dd7070Spatrick }
9685e5dd7070Spatrick if (S.getLangOpts().ObjCAutoRefCount)
9686e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
9687e5dd7070Spatrick // FIXME: we may want to suppress diagnostics for all
9688e5dd7070Spatrick // kind of forbidden type messages on unavailable functions.
9689e5dd7070Spatrick if (FD->hasAttr<UnavailableAttr>() &&
9690e5dd7070Spatrick DD.getForbiddenTypeDiagnostic() ==
9691e5dd7070Spatrick diag::err_arc_array_param_no_ownership) {
9692e5dd7070Spatrick DD.Triggered = true;
9693e5dd7070Spatrick return;
9694e5dd7070Spatrick }
9695e5dd7070Spatrick }
9696e5dd7070Spatrick
9697e5dd7070Spatrick S.Diag(DD.Loc, DD.getForbiddenTypeDiagnostic())
9698e5dd7070Spatrick << DD.getForbiddenTypeOperand() << DD.getForbiddenTypeArgument();
9699e5dd7070Spatrick DD.Triggered = true;
9700e5dd7070Spatrick }
9701e5dd7070Spatrick
9702e5dd7070Spatrick
PopParsingDeclaration(ParsingDeclState state,Decl * decl)9703e5dd7070Spatrick void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
9704e5dd7070Spatrick assert(DelayedDiagnostics.getCurrentPool());
9705e5dd7070Spatrick DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
9706e5dd7070Spatrick DelayedDiagnostics.popWithoutEmitting(state);
9707e5dd7070Spatrick
9708e5dd7070Spatrick // When delaying diagnostics to run in the context of a parsed
9709e5dd7070Spatrick // declaration, we only want to actually emit anything if parsing
9710e5dd7070Spatrick // succeeds.
9711e5dd7070Spatrick if (!decl) return;
9712e5dd7070Spatrick
9713e5dd7070Spatrick // We emit all the active diagnostics in this pool or any of its
9714e5dd7070Spatrick // parents. In general, we'll get one pool for the decl spec
9715e5dd7070Spatrick // and a child pool for each declarator; in a decl group like:
9716e5dd7070Spatrick // deprecated_typedef foo, *bar, baz();
9717e5dd7070Spatrick // only the declarator pops will be passed decls. This is correct;
9718e5dd7070Spatrick // we really do need to consider delayed diagnostics from the decl spec
9719e5dd7070Spatrick // for each of the different declarations.
9720e5dd7070Spatrick const DelayedDiagnosticPool *pool = &poppedPool;
9721e5dd7070Spatrick do {
9722e5dd7070Spatrick bool AnyAccessFailures = false;
9723e5dd7070Spatrick for (DelayedDiagnosticPool::pool_iterator
9724e5dd7070Spatrick i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
9725e5dd7070Spatrick // This const_cast is a bit lame. Really, Triggered should be mutable.
9726e5dd7070Spatrick DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
9727e5dd7070Spatrick if (diag.Triggered)
9728e5dd7070Spatrick continue;
9729e5dd7070Spatrick
9730e5dd7070Spatrick switch (diag.Kind) {
9731e5dd7070Spatrick case DelayedDiagnostic::Availability:
9732e5dd7070Spatrick // Don't bother giving deprecation/unavailable diagnostics if
9733e5dd7070Spatrick // the decl is invalid.
9734e5dd7070Spatrick if (!decl->isInvalidDecl())
9735ec727ea7Spatrick handleDelayedAvailabilityCheck(diag, decl);
9736e5dd7070Spatrick break;
9737e5dd7070Spatrick
9738e5dd7070Spatrick case DelayedDiagnostic::Access:
9739e5dd7070Spatrick // Only produce one access control diagnostic for a structured binding
9740e5dd7070Spatrick // declaration: we don't need to tell the user that all the fields are
9741e5dd7070Spatrick // inaccessible one at a time.
9742e5dd7070Spatrick if (AnyAccessFailures && isa<DecompositionDecl>(decl))
9743e5dd7070Spatrick continue;
9744e5dd7070Spatrick HandleDelayedAccessCheck(diag, decl);
9745e5dd7070Spatrick if (diag.Triggered)
9746e5dd7070Spatrick AnyAccessFailures = true;
9747e5dd7070Spatrick break;
9748e5dd7070Spatrick
9749e5dd7070Spatrick case DelayedDiagnostic::ForbiddenType:
9750e5dd7070Spatrick handleDelayedForbiddenType(*this, diag, decl);
9751e5dd7070Spatrick break;
9752e5dd7070Spatrick }
9753e5dd7070Spatrick }
9754e5dd7070Spatrick } while ((pool = pool->getParent()));
9755e5dd7070Spatrick }
9756e5dd7070Spatrick
9757e5dd7070Spatrick /// Given a set of delayed diagnostics, re-emit them as if they had
9758e5dd7070Spatrick /// been delayed in the current context instead of in the given pool.
9759e5dd7070Spatrick /// Essentially, this just moves them to the current pool.
redelayDiagnostics(DelayedDiagnosticPool & pool)9760e5dd7070Spatrick void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
9761e5dd7070Spatrick DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
9762e5dd7070Spatrick assert(curPool && "re-emitting in undelayed context not supported");
9763e5dd7070Spatrick curPool->steal(pool);
9764e5dd7070Spatrick }
9765