clang  6.0.0svn
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 
26 static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
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_cxx17_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::Spelling(A.getAttributeSpellingListIndex());
105  LoopHintAttr::OptionType Option;
106  LoopHintAttr::LoopHintState State;
107  if (PragmaNoUnroll) {
108  // #pragma nounroll
109  Option = LoopHintAttr::Unroll;
110  State = LoopHintAttr::Disable;
111  } else if (PragmaUnroll) {
112  if (ValueExpr) {
113  // #pragma unroll N
114  Option = LoopHintAttr::UnrollCount;
115  State = LoopHintAttr::Numeric;
116  } else {
117  // #pragma unroll
118  Option = LoopHintAttr::Unroll;
119  State = LoopHintAttr::Enable;
120  }
121  } else {
122  // #pragma clang loop ...
123  assert(OptionLoc && OptionLoc->Ident &&
124  "Attribute must have valid option info.");
125  Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
126  OptionLoc->Ident->getName())
127  .Case("vectorize", LoopHintAttr::Vectorize)
128  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
129  .Case("interleave", LoopHintAttr::Interleave)
130  .Case("interleave_count", LoopHintAttr::InterleaveCount)
131  .Case("unroll", LoopHintAttr::Unroll)
132  .Case("unroll_count", LoopHintAttr::UnrollCount)
133  .Case("distribute", LoopHintAttr::Distribute)
134  .Default(LoopHintAttr::Vectorize);
135  if (Option == LoopHintAttr::VectorizeWidth ||
136  Option == LoopHintAttr::InterleaveCount ||
137  Option == LoopHintAttr::UnrollCount) {
138  assert(ValueExpr && "Attribute must have a valid value expression.");
139  if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
140  return nullptr;
141  State = LoopHintAttr::Numeric;
142  } else if (Option == LoopHintAttr::Vectorize ||
143  Option == LoopHintAttr::Interleave ||
144  Option == LoopHintAttr::Unroll ||
145  Option == LoopHintAttr::Distribute) {
146  assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
147  if (StateLoc->Ident->isStr("disable"))
148  State = LoopHintAttr::Disable;
149  else if (StateLoc->Ident->isStr("assume_safety"))
150  State = LoopHintAttr::AssumeSafety;
151  else if (StateLoc->Ident->isStr("full"))
152  State = LoopHintAttr::Full;
153  else if (StateLoc->Ident->isStr("enable"))
154  State = LoopHintAttr::Enable;
155  else
156  llvm_unreachable("bad loop hint argument");
157  } else
158  llvm_unreachable("bad loop hint");
159  }
160 
161  return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
162  ValueExpr, A.getRange());
163 }
164 
165 static void
167  const SmallVectorImpl<const Attr *> &Attrs) {
168  // There are 4 categories of loop hints attributes: vectorize, interleave,
169  // unroll and distribute. Except for distribute they come in two variants: a
170  // state form and a numeric form. The state form selectively
171  // defaults/enables/disables the transformation for the loop (for unroll,
172  // default indicates full unrolling rather than enabling the transformation).
173  // The numeric form form provides an integer hint (for example, unroll count)
174  // to the transformer. The following array accumulates the hints encountered
175  // while iterating through the attributes to check for compatibility.
176  struct {
177  const LoopHintAttr *StateAttr;
178  const LoopHintAttr *NumericAttr;
179  } HintAttrs[] = {{nullptr, nullptr},
180  {nullptr, nullptr},
181  {nullptr, nullptr},
182  {nullptr, nullptr}};
183 
184  for (const auto *I : Attrs) {
185  const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
186 
187  // Skip non loop hint attributes
188  if (!LH)
189  continue;
190 
191  LoopHintAttr::OptionType Option = LH->getOption();
192  enum { Vectorize, Interleave, Unroll, Distribute } Category;
193  switch (Option) {
194  case LoopHintAttr::Vectorize:
195  case LoopHintAttr::VectorizeWidth:
196  Category = Vectorize;
197  break;
198  case LoopHintAttr::Interleave:
199  case LoopHintAttr::InterleaveCount:
200  Category = Interleave;
201  break;
202  case LoopHintAttr::Unroll:
203  case LoopHintAttr::UnrollCount:
204  Category = Unroll;
205  break;
206  case LoopHintAttr::Distribute:
207  // Perform the check for duplicated 'distribute' hints.
208  Category = Distribute;
209  break;
210  };
211 
212  auto &CategoryState = HintAttrs[Category];
213  const LoopHintAttr *PrevAttr;
214  if (Option == LoopHintAttr::Vectorize ||
215  Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
216  Option == LoopHintAttr::Distribute) {
217  // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
218  PrevAttr = CategoryState.StateAttr;
219  CategoryState.StateAttr = LH;
220  } else {
221  // Numeric hint. For example, vectorize_width(8).
222  PrevAttr = CategoryState.NumericAttr;
223  CategoryState.NumericAttr = LH;
224  }
225 
226  PrintingPolicy Policy(S.Context.getLangOpts());
227  SourceLocation OptionLoc = LH->getRange().getBegin();
228  if (PrevAttr)
229  // Cannot specify same type of attribute twice.
230  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
231  << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
232  << LH->getDiagnosticName(Policy);
233 
234  if (CategoryState.StateAttr && CategoryState.NumericAttr &&
235  (Category == Unroll ||
236  CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
237  // Disable hints are not compatible with numeric hints of the same
238  // category. As a special case, numeric unroll hints are also not
239  // compatible with enable or full form of the unroll pragma because these
240  // directives indicate full unrolling.
241  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
242  << /*Duplicate=*/false
243  << CategoryState.StateAttr->getDiagnosticName(Policy)
244  << CategoryState.NumericAttr->getDiagnosticName(Policy);
245  }
246  }
247 }
248 
250  SourceRange Range) {
251  // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
252  // useful for OpenCL 1.x too and doesn't require HW support.
253  // opencl_unroll_hint can have 0 arguments (compiler
254  // determines unrolling factor) or 1 argument (the unroll factor provided
255  // by the user).
256 
257  unsigned NumArgs = A.getNumArgs();
258 
259  if (NumArgs > 1) {
260  S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
261  << 1;
262  return nullptr;
263  }
264 
265  unsigned UnrollFactor = 0;
266 
267  if (NumArgs == 1) {
268  Expr *E = A.getArgAsExpr(0);
269  llvm::APSInt ArgVal(32);
270 
271  if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
272  S.Diag(A.getLoc(), diag::err_attribute_argument_type)
274  return nullptr;
275  }
276 
277  int Val = ArgVal.getSExtValue();
278 
279  if (Val <= 0) {
280  S.Diag(A.getRange().getBegin(),
281  diag::err_attribute_requires_positive_integer)
282  << A.getName();
283  return nullptr;
284  }
285  UnrollFactor = Val;
286  }
287 
288  return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
289 }
290 
291 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
292  SourceRange Range) {
293  switch (A.getKind()) {
295  S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
296  diag::warn_unhandled_ms_attribute_ignored :
297  diag::warn_unknown_attribute_ignored) << A.getName();
298  return nullptr;
299  case AttributeList::AT_FallThrough:
300  return handleFallThroughAttr(S, St, A, Range);
301  case AttributeList::AT_LoopHint:
302  return handleLoopHintAttr(S, St, A, Range);
303  case AttributeList::AT_OpenCLUnrollHint:
304  return handleOpenCLUnrollHint(S, St, A, Range);
305  case AttributeList::AT_Suppress:
306  return handleSuppressAttr(S, St, A, Range);
307  default:
308  // if we're here, then we parsed a known attribute, but didn't recognize
309  // it as a statement attribute => it is declaration attribute
310  S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
311  << A.getName() << St->getLocStart();
312  return nullptr;
313  }
314 }
315 
317  SourceRange Range) {
319  for (const AttributeList* l = AttrList; l; l = l->getNext()) {
320  if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
321  Attrs.push_back(a);
322  }
323 
324  CheckForIncompatibleAttributes(*this, Attrs);
325 
326  if (Attrs.empty())
327  return S;
328 
329  return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
330 }
Defines the clang::ASTContext interface.
const char * getSpelling() const
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc)
Definition: SemaExpr.cpp:3166
AttributeList * getNext() const
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl< const Attr *> &Attrs)
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:1270
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
SourceLocation getLoc() const
Kind getKind() const
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
LineState State
int Category
Definition: Format.cpp:1319
static Attr * handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
IdentifierLoc * getArgAsIdent(unsigned Arg) const
unsigned getAttributeSpellingListIndex() const
Get an index into the attribute spelling list defined in Attr.td.
const LangOptions & getLangOpts() const
Definition: Sema.h:1193
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:274
Expr - This represents one expression.
Definition: Expr.h:106
static Attr * handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
Defines the classes clang::DelayedDiagnostic and clang::AccessedEntity.
SourceLocation getEnd() const
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.
bool isCXX11Attribute() const
SourceRange getRange() const
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
Definition: Ownership.h:144
Encodes a location in the source.
IdentifierInfo * getScopeName() const
static Attr * handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
static Attr * ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
bool isDeclspecAttribute() const
StringRef getName() const
Return the actual identifier 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.
Dataflow Directional Tag Classes.
Expr * getArgAsExpr(unsigned Arg) const
StmtClass getStmtClass() const
Definition: Stmt.h:361
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...
IdentifierInfo * getName() 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
sema::FunctionScopeInfo * getCurFunction() const
Definition: Sema.h:1320
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:245
static Attr * handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange)
A trivial tuple used to represent a source range.
ASTContext & Context
Definition: Sema.h:316
SourceLocation getLocStart() const LLVM_READONLY
Definition: Stmt.cpp:257
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
Definition: ASTContext.h:661
Attr - This represents one attribute.
Definition: Attr.h:43
AttributeList - Represents a syntactic attribute.
Definition: AttributeList.h:95