clang  5.0.0
SemaStmtAttr.cpp
Go to the documentation of this file.
1 //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements stmt-related attribute processing.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "clang/AST/ASTContext.h"
18 #include "clang/Sema/Lookup.h"
19 #include "clang/Sema/LoopHint.h"
20 #include "clang/Sema/ScopeInfo.h"
21 #include "llvm/ADT/StringExtras.h"
22 
23 using namespace clang;
24 using namespace sema;
25 
27  SourceRange Range) {
28  FallThroughAttr Attr(A.getRange(), S.Context,
30  if (!isa<NullStmt>(St)) {
31  S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
32  << Attr.getSpelling() << St->getLocStart();
33  if (isa<SwitchCase>(St)) {
35  S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
36  << FixItHint::CreateInsertion(L, ";");
37  }
38  return nullptr;
39  }
40  auto *FnScope = S.getCurFunction();
41  if (FnScope->SwitchStack.empty()) {
42  S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
43  return nullptr;
44  }
45 
46  // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
47  // about using it as an extension.
48  if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
49  !A.getScopeName())
50  S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
51 
52  FnScope->setHasFallthroughStmt();
53  return ::new (S.Context) auto(Attr);
54 }
55 
56 static Attr *handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A,
57  SourceRange Range) {
58  if (A.getNumArgs() < 1) {
59  S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments)
60  << A.getName() << 1;
61  return nullptr;
62  }
63 
64  std::vector<StringRef> DiagnosticIdentifiers;
65  for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) {
66  StringRef RuleName;
67 
68  if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr))
69  return nullptr;
70 
71  // FIXME: Warn if the rule name is unknown. This is tricky because only
72  // clang-tidy knows about available rules.
73  DiagnosticIdentifiers.push_back(RuleName);
74  }
75 
76  return ::new (S.Context) SuppressAttr(
77  A.getRange(), S.Context, DiagnosticIdentifiers.data(),
78  DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex());
79 }
80 
81 static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
82  SourceRange) {
83  IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
84  IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
85  IdentifierLoc *StateLoc = A.getArgAsIdent(2);
86  Expr *ValueExpr = A.getArgAsExpr(3);
87 
88  bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
89  bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
90  if (St->getStmtClass() != Stmt::DoStmtClass &&
91  St->getStmtClass() != Stmt::ForStmtClass &&
92  St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
93  St->getStmtClass() != Stmt::WhileStmtClass) {
94  const char *Pragma =
95  llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
96  .Case("unroll", "#pragma unroll")
97  .Case("nounroll", "#pragma nounroll")
98  .Default("#pragma clang loop");
99  S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
100  return nullptr;
101  }
102 
103  LoopHintAttr::Spelling Spelling;
104  LoopHintAttr::OptionType Option;
105  LoopHintAttr::LoopHintState State;
106  if (PragmaNoUnroll) {
107  // #pragma nounroll
108  Spelling = LoopHintAttr::Pragma_nounroll;
109  Option = LoopHintAttr::Unroll;
110  State = LoopHintAttr::Disable;
111  } else if (PragmaUnroll) {
112  Spelling = LoopHintAttr::Pragma_unroll;
113  if (ValueExpr) {
114  // #pragma unroll N
115  Option = LoopHintAttr::UnrollCount;
116  State = LoopHintAttr::Numeric;
117  } else {
118  // #pragma unroll
119  Option = LoopHintAttr::Unroll;
120  State = LoopHintAttr::Enable;
121  }
122  } else {
123  // #pragma clang loop ...
124  Spelling = LoopHintAttr::Pragma_clang_loop;
125  assert(OptionLoc && OptionLoc->Ident &&
126  "Attribute must have valid option info.");
127  Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
128  OptionLoc->Ident->getName())
129  .Case("vectorize", LoopHintAttr::Vectorize)
130  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
131  .Case("interleave", LoopHintAttr::Interleave)
132  .Case("interleave_count", LoopHintAttr::InterleaveCount)
133  .Case("unroll", LoopHintAttr::Unroll)
134  .Case("unroll_count", LoopHintAttr::UnrollCount)
135  .Case("distribute", LoopHintAttr::Distribute)
136  .Default(LoopHintAttr::Vectorize);
137  if (Option == LoopHintAttr::VectorizeWidth ||
138  Option == LoopHintAttr::InterleaveCount ||
139  Option == LoopHintAttr::UnrollCount) {
140  assert(ValueExpr && "Attribute must have a valid value expression.");
141  if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
142  return nullptr;
143  State = LoopHintAttr::Numeric;
144  } else if (Option == LoopHintAttr::Vectorize ||
145  Option == LoopHintAttr::Interleave ||
146  Option == LoopHintAttr::Unroll ||
147  Option == LoopHintAttr::Distribute) {
148  assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
149  if (StateLoc->Ident->isStr("disable"))
150  State = LoopHintAttr::Disable;
151  else if (StateLoc->Ident->isStr("assume_safety"))
152  State = LoopHintAttr::AssumeSafety;
153  else if (StateLoc->Ident->isStr("full"))
154  State = LoopHintAttr::Full;
155  else if (StateLoc->Ident->isStr("enable"))
156  State = LoopHintAttr::Enable;
157  else
158  llvm_unreachable("bad loop hint argument");
159  } else
160  llvm_unreachable("bad loop hint");
161  }
162 
163  return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
164  ValueExpr, A.getRange());
165 }
166 
167 static void
169  const SmallVectorImpl<const Attr *> &Attrs) {
170  // There are 4 categories of loop hints attributes: vectorize, interleave,
171  // unroll and distribute. Except for distribute they come in two variants: a
172  // state form and a numeric form. The state form selectively
173  // defaults/enables/disables the transformation for the loop (for unroll,
174  // default indicates full unrolling rather than enabling the transformation).
175  // The numeric form form provides an integer hint (for example, unroll count)
176  // to the transformer. The following array accumulates the hints encountered
177  // while iterating through the attributes to check for compatibility.
178  struct {
179  const LoopHintAttr *StateAttr;
180  const LoopHintAttr *NumericAttr;
181  } HintAttrs[] = {{nullptr, nullptr},
182  {nullptr, nullptr},
183  {nullptr, nullptr},
184  {nullptr, nullptr}};
185 
186  for (const auto *I : Attrs) {
187  const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
188 
189  // Skip non loop hint attributes
190  if (!LH)
191  continue;
192 
193  LoopHintAttr::OptionType Option = LH->getOption();
194  enum { Vectorize, Interleave, Unroll, Distribute } Category;
195  switch (Option) {
196  case LoopHintAttr::Vectorize:
197  case LoopHintAttr::VectorizeWidth:
198  Category = Vectorize;
199  break;
200  case LoopHintAttr::Interleave:
201  case LoopHintAttr::InterleaveCount:
202  Category = Interleave;
203  break;
204  case LoopHintAttr::Unroll:
205  case LoopHintAttr::UnrollCount:
206  Category = Unroll;
207  break;
208  case LoopHintAttr::Distribute:
209  // Perform the check for duplicated 'distribute' hints.
210  Category = Distribute;
211  break;
212  };
213 
214  auto &CategoryState = HintAttrs[Category];
215  const LoopHintAttr *PrevAttr;
216  if (Option == LoopHintAttr::Vectorize ||
217  Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
218  Option == LoopHintAttr::Distribute) {
219  // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
220  PrevAttr = CategoryState.StateAttr;
221  CategoryState.StateAttr = LH;
222  } else {
223  // Numeric hint. For example, vectorize_width(8).
224  PrevAttr = CategoryState.NumericAttr;
225  CategoryState.NumericAttr = LH;
226  }
227 
228  PrintingPolicy Policy(S.Context.getLangOpts());
229  SourceLocation OptionLoc = LH->getRange().getBegin();
230  if (PrevAttr)
231  // Cannot specify same type of attribute twice.
232  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
233  << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
234  << LH->getDiagnosticName(Policy);
235 
236  if (CategoryState.StateAttr && CategoryState.NumericAttr &&
237  (Category == Unroll ||
238  CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
239  // Disable hints are not compatible with numeric hints of the same
240  // category. As a special case, numeric unroll hints are also not
241  // compatible with enable or full form of the unroll pragma because these
242  // directives indicate full unrolling.
243  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
244  << /*Duplicate=*/false
245  << CategoryState.StateAttr->getDiagnosticName(Policy)
246  << CategoryState.NumericAttr->getDiagnosticName(Policy);
247  }
248  }
249 }
250 
252  SourceRange Range) {
253  // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
254  // useful for OpenCL 1.x too and doesn't require HW support.
255  // opencl_unroll_hint can have 0 arguments (compiler
256  // determines unrolling factor) or 1 argument (the unroll factor provided
257  // by the user).
258 
259  unsigned NumArgs = A.getNumArgs();
260 
261  if (NumArgs > 1) {
262  S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
263  << 1;
264  return nullptr;
265  }
266 
267  unsigned UnrollFactor = 0;
268 
269  if (NumArgs == 1) {
270  Expr *E = A.getArgAsExpr(0);
271  llvm::APSInt ArgVal(32);
272 
273  if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
274  S.Diag(A.getLoc(), diag::err_attribute_argument_type)
276  return nullptr;
277  }
278 
279  int Val = ArgVal.getSExtValue();
280 
281  if (Val <= 0) {
282  S.Diag(A.getRange().getBegin(),
283  diag::err_attribute_requires_positive_integer)
284  << A.getName();
285  return nullptr;
286  }
287  UnrollFactor = Val;
288  }
289 
290  return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
291 }
292 
294  SourceRange Range) {
295  switch (A.getKind()) {
297  S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
298  diag::warn_unhandled_ms_attribute_ignored :
299  diag::warn_unknown_attribute_ignored) << A.getName();
300  return nullptr;
301  case AttributeList::AT_FallThrough:
302  return handleFallThroughAttr(S, St, A, Range);
303  case AttributeList::AT_LoopHint:
304  return handleLoopHintAttr(S, St, A, Range);
305  case AttributeList::AT_OpenCLUnrollHint:
306  return handleOpenCLUnrollHint(S, St, A, Range);
307  case AttributeList::AT_Suppress:
308  return handleSuppressAttr(S, St, A, Range);
309  default:
310  // if we're here, then we parsed a known attribute, but didn't recognize
311  // it as a statement attribute => it is declaration attribute
312  S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
313  << A.getName() << St->getLocStart();
314  return nullptr;
315  }
316 }
317 
319  SourceRange Range) {
321  for (const AttributeList* l = AttrList; l; l = l->getNext()) {
322  if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
323  Attrs.push_back(a);
324  }
325 
326  CheckForIncompatibleAttributes(*this, Attrs);
327 
328  if (Attrs.empty())
329  return S;
330 
331  return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
332 }
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
StmtClass getStmtClass() const
Definition: Stmt.h:361
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc)
Definition: SemaExpr.cpp:3166
const LangOptions & getLangOpts() const
Definition: Sema.h:1166
Stmt - This represents one statement.
Definition: Stmt.h:60
Defines the SourceManager interface.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition: Sema.h:1243
SourceRange getRange() const
IdentifierInfo * Ident
Definition: AttributeList.h:75
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:45
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:38
LineState State
int Category
Definition: Format.cpp:1304
const LangOptions & getLangOpts() const
Definition: ASTContext.h:659
static Attr * handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
detail::InMemoryDirectory::const_iterator I
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:269
Kind getKind() const
Expr - This represents one expression.
Definition: Expr.h:105
StringRef getName() const
Return the actual identifier string.
static Attr * handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
Defines the classes clang::DelayedDiagnostic and clang::AccessedEntity.
Wraps an identifier and optional source location for the identifier.
Definition: AttributeList.h:73
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, SourceRange Range)
Stmt attributes - this routine is the top level dispatcher.
unsigned getAttributeSpellingListIndex() const
Get an index into the attribute spelling list defined in Attr.td.
const char * getSpelling() const
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
Definition: Ownership.h:145
Encodes a location in the source.
static Attr * handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl< const Attr * > &Attrs)
bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx, SourceLocation *Loc=nullptr, bool isEvaluated=true) const
isIntegerConstantExpr - Return true if this expression is a valid integer constant expression...
static Attr * ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
SourceLocation getBegin() const
IdentifierInfo * getScopeName() const
IdentifierLoc * getArgAsIdent(unsigned Arg) const
sema::FunctionScopeInfo * getCurFunction() const
Definition: Sema.h:1293
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation=nullptr)
Check if the argument ArgNum of Attr is a ASCII string literal.
Expr * getArgAsExpr(unsigned Arg) const
detail::InMemoryDirectory::const_iterator E
IdentifierInfo * getName() const
SourceLocation getLoc() const
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Definition: Diagnostic.h:90
bool isCXX11Attribute() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:245
bool isDeclspecAttribute() const
static Attr * handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange)
AttributeList * getNext() const
A trivial tuple used to represent a source range.
ASTContext & Context
Definition: Sema.h:305
SourceLocation getLocStart() const LLVM_READONLY
Definition: Stmt.cpp:257
Attr - This represents one attribute.
Definition: Attr.h:43
AttributeList - Represents a syntactic attribute.
Definition: AttributeList.h:95