clang  3.8.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  if (!isa<NullStmt>(St)) {
29  S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
30  << St->getLocStart();
31  if (isa<SwitchCase>(St)) {
33  S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
34  << FixItHint::CreateInsertion(L, ";");
35  }
36  return nullptr;
37  }
38  if (S.getCurFunction()->SwitchStack.empty()) {
39  S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
40  return nullptr;
41  }
42  return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
44 }
45 
46 static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
47  SourceRange) {
48  IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
49  IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
50  IdentifierLoc *StateLoc = A.getArgAsIdent(2);
51  Expr *ValueExpr = A.getArgAsExpr(3);
52 
53  bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
54  bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
55  if (St->getStmtClass() != Stmt::DoStmtClass &&
56  St->getStmtClass() != Stmt::ForStmtClass &&
57  St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
58  St->getStmtClass() != Stmt::WhileStmtClass) {
59  const char *Pragma =
60  llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
61  .Case("unroll", "#pragma unroll")
62  .Case("nounroll", "#pragma nounroll")
63  .Default("#pragma clang loop");
64  S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
65  return nullptr;
66  }
67 
68  LoopHintAttr::Spelling Spelling;
69  LoopHintAttr::OptionType Option;
70  LoopHintAttr::LoopHintState State;
71  if (PragmaNoUnroll) {
72  // #pragma nounroll
73  Spelling = LoopHintAttr::Pragma_nounroll;
74  Option = LoopHintAttr::Unroll;
75  State = LoopHintAttr::Disable;
76  } else if (PragmaUnroll) {
77  Spelling = LoopHintAttr::Pragma_unroll;
78  if (ValueExpr) {
79  // #pragma unroll N
80  Option = LoopHintAttr::UnrollCount;
81  State = LoopHintAttr::Numeric;
82  } else {
83  // #pragma unroll
84  Option = LoopHintAttr::Unroll;
85  State = LoopHintAttr::Enable;
86  }
87  } else {
88  // #pragma clang loop ...
89  Spelling = LoopHintAttr::Pragma_clang_loop;
90  assert(OptionLoc && OptionLoc->Ident &&
91  "Attribute must have valid option info.");
92  Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
93  OptionLoc->Ident->getName())
94  .Case("vectorize", LoopHintAttr::Vectorize)
95  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
96  .Case("interleave", LoopHintAttr::Interleave)
97  .Case("interleave_count", LoopHintAttr::InterleaveCount)
98  .Case("unroll", LoopHintAttr::Unroll)
99  .Case("unroll_count", LoopHintAttr::UnrollCount)
100  .Default(LoopHintAttr::Vectorize);
101  if (Option == LoopHintAttr::VectorizeWidth ||
102  Option == LoopHintAttr::InterleaveCount ||
103  Option == LoopHintAttr::UnrollCount) {
104  assert(ValueExpr && "Attribute must have a valid value expression.");
105  if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
106  return nullptr;
107  State = LoopHintAttr::Numeric;
108  } else if (Option == LoopHintAttr::Vectorize ||
109  Option == LoopHintAttr::Interleave ||
110  Option == LoopHintAttr::Unroll) {
111  assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
112  if (StateLoc->Ident->isStr("disable"))
113  State = LoopHintAttr::Disable;
114  else if (StateLoc->Ident->isStr("assume_safety"))
115  State = LoopHintAttr::AssumeSafety;
116  else if (StateLoc->Ident->isStr("full"))
117  State = LoopHintAttr::Full;
118  else if (StateLoc->Ident->isStr("enable"))
119  State = LoopHintAttr::Enable;
120  else
121  llvm_unreachable("bad loop hint argument");
122  } else
123  llvm_unreachable("bad loop hint");
124  }
125 
126  return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
127  ValueExpr, A.getRange());
128 }
129 
130 static void
132  const SmallVectorImpl<const Attr *> &Attrs) {
133  // There are 3 categories of loop hints attributes: vectorize, interleave,
134  // and unroll. Each comes in two variants: a state form and a numeric form.
135  // The state form selectively defaults/enables/disables the transformation
136  // for the loop (for unroll, default indicates full unrolling rather than
137  // enabling the transformation). The numeric form form provides an integer
138  // hint (for example, unroll count) to the transformer. The following array
139  // accumulates the hints encountered while iterating through the attributes
140  // to check for compatibility.
141  struct {
142  const LoopHintAttr *StateAttr;
143  const LoopHintAttr *NumericAttr;
144  } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
145 
146  for (const auto *I : Attrs) {
147  const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
148 
149  // Skip non loop hint attributes
150  if (!LH)
151  continue;
152 
153  LoopHintAttr::OptionType Option = LH->getOption();
154  enum { Vectorize, Interleave, Unroll } Category;
155  switch (Option) {
156  case LoopHintAttr::Vectorize:
157  case LoopHintAttr::VectorizeWidth:
158  Category = Vectorize;
159  break;
160  case LoopHintAttr::Interleave:
161  case LoopHintAttr::InterleaveCount:
162  Category = Interleave;
163  break;
164  case LoopHintAttr::Unroll:
165  case LoopHintAttr::UnrollCount:
166  Category = Unroll;
167  break;
168  };
169 
170  auto &CategoryState = HintAttrs[Category];
171  const LoopHintAttr *PrevAttr;
172  if (Option == LoopHintAttr::Vectorize ||
173  Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
174  // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
175  PrevAttr = CategoryState.StateAttr;
176  CategoryState.StateAttr = LH;
177  } else {
178  // Numeric hint. For example, vectorize_width(8).
179  PrevAttr = CategoryState.NumericAttr;
180  CategoryState.NumericAttr = LH;
181  }
182 
183  PrintingPolicy Policy(S.Context.getLangOpts());
184  SourceLocation OptionLoc = LH->getRange().getBegin();
185  if (PrevAttr)
186  // Cannot specify same type of attribute twice.
187  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
188  << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
189  << LH->getDiagnosticName(Policy);
190 
191  if (CategoryState.StateAttr && CategoryState.NumericAttr &&
192  (Category == Unroll ||
193  CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
194  // Disable hints are not compatible with numeric hints of the same
195  // category. As a special case, numeric unroll hints are also not
196  // compatible with enable or full form of the unroll pragma because these
197  // directives indicate full unrolling.
198  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
199  << /*Duplicate=*/false
200  << CategoryState.StateAttr->getDiagnosticName(Policy)
201  << CategoryState.NumericAttr->getDiagnosticName(Policy);
202  }
203  }
204 }
205 
207  SourceRange Range) {
208  switch (A.getKind()) {
210  S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
211  diag::warn_unhandled_ms_attribute_ignored :
212  diag::warn_unknown_attribute_ignored) << A.getName();
213  return nullptr;
214  case AttributeList::AT_FallThrough:
215  return handleFallThroughAttr(S, St, A, Range);
216  case AttributeList::AT_LoopHint:
217  return handleLoopHintAttr(S, St, A, Range);
218  default:
219  // if we're here, then we parsed a known attribute, but didn't recognize
220  // it as a statement attribute => it is declaration attribute
221  S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
222  << A.getName() << St->getLocStart();
223  return nullptr;
224  }
225 }
226 
228  SourceRange Range) {
230  for (const AttributeList* l = AttrList; l; l = l->getNext()) {
231  if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
232  Attrs.push_back(a);
233  }
234 
235  CheckForIncompatibleAttributes(*this, Attrs);
236 
237  if (Attrs.empty())
238  return S;
239 
240  return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
241 }
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc)
Definition: SemaExpr.cpp:3152
Defines the SourceManager interface.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition: Sema.h:1118
SourceRange getRange() const
IdentifierInfo * Ident
Definition: AttributeList.h:52
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:46
SmallVector< SwitchStmt *, 8 > SwitchStack
SwitchStack - This is the current set of active switch statements in the block.
Definition: ScopeInfo.h:141
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:35
LineState State
int Category
Definition: Format.cpp:1726
const LangOptions & getLangOpts() const
Definition: ASTContext.h:596
detail::InMemoryDirectory::const_iterator I
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:259
Kind getKind() const
Expr - This represents one expression.
Definition: Expr.h:104
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:50
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.
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
Definition: Ownership.h:145
Encodes a location in the source.
static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl< const Attr * > &Attrs)
static Attr * ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range)
SourceLocation getBegin() const
IdentifierLoc * getArgAsIdent(unsigned Arg) const
sema::FunctionScopeInfo * getCurFunction() const
Definition: Sema.h:1167
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Expr * getArgAsExpr(unsigned Arg) const
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 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:295
Attr - This represents one attribute.
Definition: Attr.h:44
AttributeList - Represents a syntactic attribute.
Definition: AttributeList.h:72