clang  3.9.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 *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
57  SourceRange) {
58  IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
59  IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
60  IdentifierLoc *StateLoc = A.getArgAsIdent(2);
61  Expr *ValueExpr = A.getArgAsExpr(3);
62 
63  bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
64  bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
65  if (St->getStmtClass() != Stmt::DoStmtClass &&
66  St->getStmtClass() != Stmt::ForStmtClass &&
67  St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
68  St->getStmtClass() != Stmt::WhileStmtClass) {
69  const char *Pragma =
70  llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
71  .Case("unroll", "#pragma unroll")
72  .Case("nounroll", "#pragma nounroll")
73  .Default("#pragma clang loop");
74  S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
75  return nullptr;
76  }
77 
78  LoopHintAttr::Spelling Spelling;
79  LoopHintAttr::OptionType Option;
80  LoopHintAttr::LoopHintState State;
81  if (PragmaNoUnroll) {
82  // #pragma nounroll
83  Spelling = LoopHintAttr::Pragma_nounroll;
84  Option = LoopHintAttr::Unroll;
85  State = LoopHintAttr::Disable;
86  } else if (PragmaUnroll) {
87  Spelling = LoopHintAttr::Pragma_unroll;
88  if (ValueExpr) {
89  // #pragma unroll N
90  Option = LoopHintAttr::UnrollCount;
91  State = LoopHintAttr::Numeric;
92  } else {
93  // #pragma unroll
94  Option = LoopHintAttr::Unroll;
95  State = LoopHintAttr::Enable;
96  }
97  } else {
98  // #pragma clang loop ...
99  Spelling = LoopHintAttr::Pragma_clang_loop;
100  assert(OptionLoc && OptionLoc->Ident &&
101  "Attribute must have valid option info.");
102  Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
103  OptionLoc->Ident->getName())
104  .Case("vectorize", LoopHintAttr::Vectorize)
105  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
106  .Case("interleave", LoopHintAttr::Interleave)
107  .Case("interleave_count", LoopHintAttr::InterleaveCount)
108  .Case("unroll", LoopHintAttr::Unroll)
109  .Case("unroll_count", LoopHintAttr::UnrollCount)
110  .Case("distribute", LoopHintAttr::Distribute)
111  .Default(LoopHintAttr::Vectorize);
112  if (Option == LoopHintAttr::VectorizeWidth ||
113  Option == LoopHintAttr::InterleaveCount ||
114  Option == LoopHintAttr::UnrollCount) {
115  assert(ValueExpr && "Attribute must have a valid value expression.");
116  if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
117  return nullptr;
118  State = LoopHintAttr::Numeric;
119  } else if (Option == LoopHintAttr::Vectorize ||
120  Option == LoopHintAttr::Interleave ||
121  Option == LoopHintAttr::Unroll ||
122  Option == LoopHintAttr::Distribute) {
123  assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
124  if (StateLoc->Ident->isStr("disable"))
125  State = LoopHintAttr::Disable;
126  else if (StateLoc->Ident->isStr("assume_safety"))
127  State = LoopHintAttr::AssumeSafety;
128  else if (StateLoc->Ident->isStr("full"))
129  State = LoopHintAttr::Full;
130  else if (StateLoc->Ident->isStr("enable"))
131  State = LoopHintAttr::Enable;
132  else
133  llvm_unreachable("bad loop hint argument");
134  } else
135  llvm_unreachable("bad loop hint");
136  }
137 
138  return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
139  ValueExpr, A.getRange());
140 }
141 
142 static void
144  const SmallVectorImpl<const Attr *> &Attrs) {
145  // There are 4 categories of loop hints attributes: vectorize, interleave,
146  // unroll and distribute. Except for distribute they come in two variants: a
147  // state form and a numeric form. The state form selectively
148  // defaults/enables/disables the transformation for the loop (for unroll,
149  // default indicates full unrolling rather than enabling the transformation).
150  // The numeric form form provides an integer hint (for example, unroll count)
151  // to the transformer. The following array accumulates the hints encountered
152  // while iterating through the attributes to check for compatibility.
153  struct {
154  const LoopHintAttr *StateAttr;
155  const LoopHintAttr *NumericAttr;
156  } HintAttrs[] = {{nullptr, nullptr},
157  {nullptr, nullptr},
158  {nullptr, nullptr},
159  {nullptr, nullptr}};
160 
161  for (const auto *I : Attrs) {
162  const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
163 
164  // Skip non loop hint attributes
165  if (!LH)
166  continue;
167 
168  LoopHintAttr::OptionType Option = LH->getOption();
169  enum { Vectorize, Interleave, Unroll, Distribute } Category;
170  switch (Option) {
171  case LoopHintAttr::Vectorize:
172  case LoopHintAttr::VectorizeWidth:
173  Category = Vectorize;
174  break;
175  case LoopHintAttr::Interleave:
176  case LoopHintAttr::InterleaveCount:
177  Category = Interleave;
178  break;
179  case LoopHintAttr::Unroll:
180  case LoopHintAttr::UnrollCount:
181  Category = Unroll;
182  break;
183  case LoopHintAttr::Distribute:
184  // Perform the check for duplicated 'distribute' hints.
185  Category = Distribute;
186  break;
187  };
188 
189  auto &CategoryState = HintAttrs[Category];
190  const LoopHintAttr *PrevAttr;
191  if (Option == LoopHintAttr::Vectorize ||
192  Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
193  Option == LoopHintAttr::Distribute) {
194  // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
195  PrevAttr = CategoryState.StateAttr;
196  CategoryState.StateAttr = LH;
197  } else {
198  // Numeric hint. For example, vectorize_width(8).
199  PrevAttr = CategoryState.NumericAttr;
200  CategoryState.NumericAttr = LH;
201  }
202 
203  PrintingPolicy Policy(S.Context.getLangOpts());
204  SourceLocation OptionLoc = LH->getRange().getBegin();
205  if (PrevAttr)
206  // Cannot specify same type of attribute twice.
207  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
208  << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
209  << LH->getDiagnosticName(Policy);
210 
211  if (CategoryState.StateAttr && CategoryState.NumericAttr &&
212  (Category == Unroll ||
213  CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
214  // Disable hints are not compatible with numeric hints of the same
215  // category. As a special case, numeric unroll hints are also not
216  // compatible with enable or full form of the unroll pragma because these
217  // directives indicate full unrolling.
218  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
219  << /*Duplicate=*/false
220  << CategoryState.StateAttr->getDiagnosticName(Policy)
221  << CategoryState.NumericAttr->getDiagnosticName(Policy);
222  }
223  }
224 }
225 
227  SourceRange Range) {
228  // OpenCL v2.0 s6.11.5 - opencl_unroll_hint can have 0 arguments (compiler
229  // determines unrolling factor) or 1 argument (the unroll factor provided
230  // by the user).
231 
232  if (S.getLangOpts().OpenCLVersion < 200) {
233  S.Diag(A.getLoc(), diag::err_attribute_requires_opencl_version)
234  << A.getName() << "2.0" << 1;
235  return nullptr;
236  }
237 
238  unsigned NumArgs = A.getNumArgs();
239 
240  if (NumArgs > 1) {
241  S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
242  << 1;
243  return nullptr;
244  }
245 
246  unsigned UnrollFactor = 0;
247 
248  if (NumArgs == 1) {
249  Expr *E = A.getArgAsExpr(0);
250  llvm::APSInt ArgVal(32);
251 
252  if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
253  S.Diag(A.getLoc(), diag::err_attribute_argument_type)
254  << A.getName() << AANT_ArgumentIntegerConstant << E->getSourceRange();
255  return nullptr;
256  }
257 
258  int Val = ArgVal.getSExtValue();
259 
260  if (Val <= 0) {
261  S.Diag(A.getRange().getBegin(),
262  diag::err_attribute_requires_positive_integer)
263  << A.getName();
264  return nullptr;
265  }
266  UnrollFactor = Val;
267  }
268 
269  return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
270 }
271 
273  SourceRange Range) {
274  switch (A.getKind()) {
276  S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
277  diag::warn_unhandled_ms_attribute_ignored :
278  diag::warn_unknown_attribute_ignored) << A.getName();
279  return nullptr;
280  case AttributeList::AT_FallThrough:
281  return handleFallThroughAttr(S, St, A, Range);
282  case AttributeList::AT_LoopHint:
283  return handleLoopHintAttr(S, St, A, Range);
284  case AttributeList::AT_OpenCLUnrollHint:
285  return handleOpenCLUnrollHint(S, St, A, Range);
286  default:
287  // if we're here, then we parsed a known attribute, but didn't recognize
288  // it as a statement attribute => it is declaration attribute
289  S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
290  << A.getName() << St->getLocStart();
291  return nullptr;
292  }
293 }
294 
296  SourceRange Range) {
298  for (const AttributeList* l = AttrList; l; l = l->getNext()) {
299  if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
300  Attrs.push_back(a);
301  }
302 
303  CheckForIncompatibleAttributes(*this, Attrs);
304 
305  if (Attrs.empty())
306  return S;
307 
308  return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
309 }
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc)
Definition: SemaExpr.cpp:3215
const LangOptions & getLangOpts() const
Definition: Sema.h:1062
Defines the SourceManager interface.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition: Sema.h:1139
SourceRange getRange() const
IdentifierInfo * Ident
Definition: AttributeList.h:74
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:46
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:38
LineState State
int Category
Definition: Format.cpp:1197
const LangOptions & getLangOpts() const
Definition: ASTContext.h:604
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:263
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.
class LLVM_ALIGNAS(8) TemplateSpecializationType unsigned NumArgs
Represents a type template specialization; the template must be a class template, a type alias templa...
Definition: Type.h:4154
Wraps an identifier and optional source location for the identifier.
Definition: AttributeList.h:72
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:146
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:1188
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
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:78
bool isCXX11Attribute() const
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:299
Attr - This represents one attribute.
Definition: Attr.h:45
AttributeList - Represents a syntactic attribute.
Definition: AttributeList.h:94