xref: /aosp_15_r20/external/clang/lib/Sema/SemaStmtAttr.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li //  This file implements stmt-related attribute processing.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li 
14*67e74705SXin Li #include "clang/Sema/SemaInternal.h"
15*67e74705SXin Li #include "clang/AST/ASTContext.h"
16*67e74705SXin Li #include "clang/Basic/SourceManager.h"
17*67e74705SXin Li #include "clang/Sema/DelayedDiagnostic.h"
18*67e74705SXin Li #include "clang/Sema/Lookup.h"
19*67e74705SXin Li #include "clang/Sema/LoopHint.h"
20*67e74705SXin Li #include "clang/Sema/ScopeInfo.h"
21*67e74705SXin Li #include "llvm/ADT/StringExtras.h"
22*67e74705SXin Li 
23*67e74705SXin Li using namespace clang;
24*67e74705SXin Li using namespace sema;
25*67e74705SXin Li 
handleFallThroughAttr(Sema & S,Stmt * St,const AttributeList & A,SourceRange Range)26*67e74705SXin Li static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
27*67e74705SXin Li                                    SourceRange Range) {
28*67e74705SXin Li   FallThroughAttr Attr(A.getRange(), S.Context,
29*67e74705SXin Li                        A.getAttributeSpellingListIndex());
30*67e74705SXin Li   if (!isa<NullStmt>(St)) {
31*67e74705SXin Li     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
32*67e74705SXin Li         << Attr.getSpelling() << St->getLocStart();
33*67e74705SXin Li     if (isa<SwitchCase>(St)) {
34*67e74705SXin Li       SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
35*67e74705SXin Li       S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
36*67e74705SXin Li           << FixItHint::CreateInsertion(L, ";");
37*67e74705SXin Li     }
38*67e74705SXin Li     return nullptr;
39*67e74705SXin Li   }
40*67e74705SXin Li   auto *FnScope = S.getCurFunction();
41*67e74705SXin Li   if (FnScope->SwitchStack.empty()) {
42*67e74705SXin Li     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
43*67e74705SXin Li     return nullptr;
44*67e74705SXin Li   }
45*67e74705SXin Li 
46*67e74705SXin Li   // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
47*67e74705SXin Li   // about using it as an extension.
48*67e74705SXin Li   if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
49*67e74705SXin Li       !A.getScopeName())
50*67e74705SXin Li     S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
51*67e74705SXin Li 
52*67e74705SXin Li   FnScope->setHasFallthroughStmt();
53*67e74705SXin Li   return ::new (S.Context) auto(Attr);
54*67e74705SXin Li }
55*67e74705SXin Li 
handleLoopHintAttr(Sema & S,Stmt * St,const AttributeList & A,SourceRange)56*67e74705SXin Li static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
57*67e74705SXin Li                                 SourceRange) {
58*67e74705SXin Li   IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
59*67e74705SXin Li   IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
60*67e74705SXin Li   IdentifierLoc *StateLoc = A.getArgAsIdent(2);
61*67e74705SXin Li   Expr *ValueExpr = A.getArgAsExpr(3);
62*67e74705SXin Li 
63*67e74705SXin Li   bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
64*67e74705SXin Li   bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
65*67e74705SXin Li   if (St->getStmtClass() != Stmt::DoStmtClass &&
66*67e74705SXin Li       St->getStmtClass() != Stmt::ForStmtClass &&
67*67e74705SXin Li       St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
68*67e74705SXin Li       St->getStmtClass() != Stmt::WhileStmtClass) {
69*67e74705SXin Li     const char *Pragma =
70*67e74705SXin Li         llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
71*67e74705SXin Li             .Case("unroll", "#pragma unroll")
72*67e74705SXin Li             .Case("nounroll", "#pragma nounroll")
73*67e74705SXin Li             .Default("#pragma clang loop");
74*67e74705SXin Li     S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
75*67e74705SXin Li     return nullptr;
76*67e74705SXin Li   }
77*67e74705SXin Li 
78*67e74705SXin Li   LoopHintAttr::Spelling Spelling;
79*67e74705SXin Li   LoopHintAttr::OptionType Option;
80*67e74705SXin Li   LoopHintAttr::LoopHintState State;
81*67e74705SXin Li   if (PragmaNoUnroll) {
82*67e74705SXin Li     // #pragma nounroll
83*67e74705SXin Li     Spelling = LoopHintAttr::Pragma_nounroll;
84*67e74705SXin Li     Option = LoopHintAttr::Unroll;
85*67e74705SXin Li     State = LoopHintAttr::Disable;
86*67e74705SXin Li   } else if (PragmaUnroll) {
87*67e74705SXin Li     Spelling = LoopHintAttr::Pragma_unroll;
88*67e74705SXin Li     if (ValueExpr) {
89*67e74705SXin Li       // #pragma unroll N
90*67e74705SXin Li       Option = LoopHintAttr::UnrollCount;
91*67e74705SXin Li       State = LoopHintAttr::Numeric;
92*67e74705SXin Li     } else {
93*67e74705SXin Li       // #pragma unroll
94*67e74705SXin Li       Option = LoopHintAttr::Unroll;
95*67e74705SXin Li       State = LoopHintAttr::Enable;
96*67e74705SXin Li     }
97*67e74705SXin Li   } else {
98*67e74705SXin Li     // #pragma clang loop ...
99*67e74705SXin Li     Spelling = LoopHintAttr::Pragma_clang_loop;
100*67e74705SXin Li     assert(OptionLoc && OptionLoc->Ident &&
101*67e74705SXin Li            "Attribute must have valid option info.");
102*67e74705SXin Li     Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
103*67e74705SXin Li                  OptionLoc->Ident->getName())
104*67e74705SXin Li                  .Case("vectorize", LoopHintAttr::Vectorize)
105*67e74705SXin Li                  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
106*67e74705SXin Li                  .Case("interleave", LoopHintAttr::Interleave)
107*67e74705SXin Li                  .Case("interleave_count", LoopHintAttr::InterleaveCount)
108*67e74705SXin Li                  .Case("unroll", LoopHintAttr::Unroll)
109*67e74705SXin Li                  .Case("unroll_count", LoopHintAttr::UnrollCount)
110*67e74705SXin Li                  .Case("distribute", LoopHintAttr::Distribute)
111*67e74705SXin Li                  .Default(LoopHintAttr::Vectorize);
112*67e74705SXin Li     if (Option == LoopHintAttr::VectorizeWidth ||
113*67e74705SXin Li         Option == LoopHintAttr::InterleaveCount ||
114*67e74705SXin Li         Option == LoopHintAttr::UnrollCount) {
115*67e74705SXin Li       assert(ValueExpr && "Attribute must have a valid value expression.");
116*67e74705SXin Li       if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
117*67e74705SXin Li         return nullptr;
118*67e74705SXin Li       State = LoopHintAttr::Numeric;
119*67e74705SXin Li     } else if (Option == LoopHintAttr::Vectorize ||
120*67e74705SXin Li                Option == LoopHintAttr::Interleave ||
121*67e74705SXin Li                Option == LoopHintAttr::Unroll ||
122*67e74705SXin Li                Option == LoopHintAttr::Distribute) {
123*67e74705SXin Li       assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
124*67e74705SXin Li       if (StateLoc->Ident->isStr("disable"))
125*67e74705SXin Li         State = LoopHintAttr::Disable;
126*67e74705SXin Li       else if (StateLoc->Ident->isStr("assume_safety"))
127*67e74705SXin Li         State = LoopHintAttr::AssumeSafety;
128*67e74705SXin Li       else if (StateLoc->Ident->isStr("full"))
129*67e74705SXin Li         State = LoopHintAttr::Full;
130*67e74705SXin Li       else if (StateLoc->Ident->isStr("enable"))
131*67e74705SXin Li         State = LoopHintAttr::Enable;
132*67e74705SXin Li       else
133*67e74705SXin Li         llvm_unreachable("bad loop hint argument");
134*67e74705SXin Li     } else
135*67e74705SXin Li       llvm_unreachable("bad loop hint");
136*67e74705SXin Li   }
137*67e74705SXin Li 
138*67e74705SXin Li   return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
139*67e74705SXin Li                                       ValueExpr, A.getRange());
140*67e74705SXin Li }
141*67e74705SXin Li 
142*67e74705SXin Li static void
CheckForIncompatibleAttributes(Sema & S,const SmallVectorImpl<const Attr * > & Attrs)143*67e74705SXin Li CheckForIncompatibleAttributes(Sema &S,
144*67e74705SXin Li                                const SmallVectorImpl<const Attr *> &Attrs) {
145*67e74705SXin Li   // There are 4 categories of loop hints attributes: vectorize, interleave,
146*67e74705SXin Li   // unroll and distribute. Except for distribute they come in two variants: a
147*67e74705SXin Li   // state form and a numeric form.  The state form selectively
148*67e74705SXin Li   // defaults/enables/disables the transformation for the loop (for unroll,
149*67e74705SXin Li   // default indicates full unrolling rather than enabling the transformation).
150*67e74705SXin Li   // The numeric form form provides an integer hint (for example, unroll count)
151*67e74705SXin Li   // to the transformer. The following array accumulates the hints encountered
152*67e74705SXin Li   // while iterating through the attributes to check for compatibility.
153*67e74705SXin Li   struct {
154*67e74705SXin Li     const LoopHintAttr *StateAttr;
155*67e74705SXin Li     const LoopHintAttr *NumericAttr;
156*67e74705SXin Li   } HintAttrs[] = {{nullptr, nullptr},
157*67e74705SXin Li                    {nullptr, nullptr},
158*67e74705SXin Li                    {nullptr, nullptr},
159*67e74705SXin Li                    {nullptr, nullptr}};
160*67e74705SXin Li 
161*67e74705SXin Li   for (const auto *I : Attrs) {
162*67e74705SXin Li     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
163*67e74705SXin Li 
164*67e74705SXin Li     // Skip non loop hint attributes
165*67e74705SXin Li     if (!LH)
166*67e74705SXin Li       continue;
167*67e74705SXin Li 
168*67e74705SXin Li     LoopHintAttr::OptionType Option = LH->getOption();
169*67e74705SXin Li     enum { Vectorize, Interleave, Unroll, Distribute } Category;
170*67e74705SXin Li     switch (Option) {
171*67e74705SXin Li     case LoopHintAttr::Vectorize:
172*67e74705SXin Li     case LoopHintAttr::VectorizeWidth:
173*67e74705SXin Li       Category = Vectorize;
174*67e74705SXin Li       break;
175*67e74705SXin Li     case LoopHintAttr::Interleave:
176*67e74705SXin Li     case LoopHintAttr::InterleaveCount:
177*67e74705SXin Li       Category = Interleave;
178*67e74705SXin Li       break;
179*67e74705SXin Li     case LoopHintAttr::Unroll:
180*67e74705SXin Li     case LoopHintAttr::UnrollCount:
181*67e74705SXin Li       Category = Unroll;
182*67e74705SXin Li       break;
183*67e74705SXin Li     case LoopHintAttr::Distribute:
184*67e74705SXin Li       // Perform the check for duplicated 'distribute' hints.
185*67e74705SXin Li       Category = Distribute;
186*67e74705SXin Li       break;
187*67e74705SXin Li     };
188*67e74705SXin Li 
189*67e74705SXin Li     auto &CategoryState = HintAttrs[Category];
190*67e74705SXin Li     const LoopHintAttr *PrevAttr;
191*67e74705SXin Li     if (Option == LoopHintAttr::Vectorize ||
192*67e74705SXin Li         Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
193*67e74705SXin Li         Option == LoopHintAttr::Distribute) {
194*67e74705SXin Li       // Enable|Disable|AssumeSafety hint.  For example, vectorize(enable).
195*67e74705SXin Li       PrevAttr = CategoryState.StateAttr;
196*67e74705SXin Li       CategoryState.StateAttr = LH;
197*67e74705SXin Li     } else {
198*67e74705SXin Li       // Numeric hint.  For example, vectorize_width(8).
199*67e74705SXin Li       PrevAttr = CategoryState.NumericAttr;
200*67e74705SXin Li       CategoryState.NumericAttr = LH;
201*67e74705SXin Li     }
202*67e74705SXin Li 
203*67e74705SXin Li     PrintingPolicy Policy(S.Context.getLangOpts());
204*67e74705SXin Li     SourceLocation OptionLoc = LH->getRange().getBegin();
205*67e74705SXin Li     if (PrevAttr)
206*67e74705SXin Li       // Cannot specify same type of attribute twice.
207*67e74705SXin Li       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
208*67e74705SXin Li           << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
209*67e74705SXin Li           << LH->getDiagnosticName(Policy);
210*67e74705SXin Li 
211*67e74705SXin Li     if (CategoryState.StateAttr && CategoryState.NumericAttr &&
212*67e74705SXin Li         (Category == Unroll ||
213*67e74705SXin Li          CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
214*67e74705SXin Li       // Disable hints are not compatible with numeric hints of the same
215*67e74705SXin Li       // category.  As a special case, numeric unroll hints are also not
216*67e74705SXin Li       // compatible with enable or full form of the unroll pragma because these
217*67e74705SXin Li       // directives indicate full unrolling.
218*67e74705SXin Li       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
219*67e74705SXin Li           << /*Duplicate=*/false
220*67e74705SXin Li           << CategoryState.StateAttr->getDiagnosticName(Policy)
221*67e74705SXin Li           << CategoryState.NumericAttr->getDiagnosticName(Policy);
222*67e74705SXin Li     }
223*67e74705SXin Li   }
224*67e74705SXin Li }
225*67e74705SXin Li 
handleOpenCLUnrollHint(Sema & S,Stmt * St,const AttributeList & A,SourceRange Range)226*67e74705SXin Li static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A,
227*67e74705SXin Li                                     SourceRange Range) {
228*67e74705SXin Li   // OpenCL v2.0 s6.11.5 - opencl_unroll_hint can have 0 arguments (compiler
229*67e74705SXin Li   // determines unrolling factor) or 1 argument (the unroll factor provided
230*67e74705SXin Li   // by the user).
231*67e74705SXin Li 
232*67e74705SXin Li   if (S.getLangOpts().OpenCLVersion < 200) {
233*67e74705SXin Li     S.Diag(A.getLoc(), diag::err_attribute_requires_opencl_version)
234*67e74705SXin Li         << A.getName() << "2.0" << 1;
235*67e74705SXin Li     return nullptr;
236*67e74705SXin Li   }
237*67e74705SXin Li 
238*67e74705SXin Li   unsigned NumArgs = A.getNumArgs();
239*67e74705SXin Li 
240*67e74705SXin Li   if (NumArgs > 1) {
241*67e74705SXin Li     S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
242*67e74705SXin Li                                                                << 1;
243*67e74705SXin Li     return nullptr;
244*67e74705SXin Li   }
245*67e74705SXin Li 
246*67e74705SXin Li   unsigned UnrollFactor = 0;
247*67e74705SXin Li 
248*67e74705SXin Li   if (NumArgs == 1) {
249*67e74705SXin Li     Expr *E = A.getArgAsExpr(0);
250*67e74705SXin Li     llvm::APSInt ArgVal(32);
251*67e74705SXin Li 
252*67e74705SXin Li     if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
253*67e74705SXin Li       S.Diag(A.getLoc(), diag::err_attribute_argument_type)
254*67e74705SXin Li           << A.getName() << AANT_ArgumentIntegerConstant << E->getSourceRange();
255*67e74705SXin Li       return nullptr;
256*67e74705SXin Li     }
257*67e74705SXin Li 
258*67e74705SXin Li     int Val = ArgVal.getSExtValue();
259*67e74705SXin Li 
260*67e74705SXin Li     if (Val <= 0) {
261*67e74705SXin Li       S.Diag(A.getRange().getBegin(),
262*67e74705SXin Li              diag::err_attribute_requires_positive_integer)
263*67e74705SXin Li           << A.getName();
264*67e74705SXin Li       return nullptr;
265*67e74705SXin Li     }
266*67e74705SXin Li     UnrollFactor = Val;
267*67e74705SXin Li   }
268*67e74705SXin Li 
269*67e74705SXin Li   return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
270*67e74705SXin Li }
271*67e74705SXin Li 
ProcessStmtAttribute(Sema & S,Stmt * St,const AttributeList & A,SourceRange Range)272*67e74705SXin Li static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
273*67e74705SXin Li                                   SourceRange Range) {
274*67e74705SXin Li   switch (A.getKind()) {
275*67e74705SXin Li   case AttributeList::UnknownAttribute:
276*67e74705SXin Li     S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
277*67e74705SXin Li            diag::warn_unhandled_ms_attribute_ignored :
278*67e74705SXin Li            diag::warn_unknown_attribute_ignored) << A.getName();
279*67e74705SXin Li     return nullptr;
280*67e74705SXin Li   case AttributeList::AT_FallThrough:
281*67e74705SXin Li     return handleFallThroughAttr(S, St, A, Range);
282*67e74705SXin Li   case AttributeList::AT_LoopHint:
283*67e74705SXin Li     return handleLoopHintAttr(S, St, A, Range);
284*67e74705SXin Li   case AttributeList::AT_OpenCLUnrollHint:
285*67e74705SXin Li     return handleOpenCLUnrollHint(S, St, A, Range);
286*67e74705SXin Li   default:
287*67e74705SXin Li     // if we're here, then we parsed a known attribute, but didn't recognize
288*67e74705SXin Li     // it as a statement attribute => it is declaration attribute
289*67e74705SXin Li     S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
290*67e74705SXin Li         << A.getName() << St->getLocStart();
291*67e74705SXin Li     return nullptr;
292*67e74705SXin Li   }
293*67e74705SXin Li }
294*67e74705SXin Li 
ProcessStmtAttributes(Stmt * S,AttributeList * AttrList,SourceRange Range)295*67e74705SXin Li StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
296*67e74705SXin Li                                        SourceRange Range) {
297*67e74705SXin Li   SmallVector<const Attr*, 8> Attrs;
298*67e74705SXin Li   for (const AttributeList* l = AttrList; l; l = l->getNext()) {
299*67e74705SXin Li     if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
300*67e74705SXin Li       Attrs.push_back(a);
301*67e74705SXin Li   }
302*67e74705SXin Li 
303*67e74705SXin Li   CheckForIncompatibleAttributes(*this, Attrs);
304*67e74705SXin Li 
305*67e74705SXin Li   if (Attrs.empty())
306*67e74705SXin Li     return S;
307*67e74705SXin Li 
308*67e74705SXin Li   return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
309*67e74705SXin Li }
310