clang  3.7.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::OptionType Option;
69  LoopHintAttr::Spelling Spelling;
70  if (PragmaUnroll) {
71  Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
72  Spelling = LoopHintAttr::Pragma_unroll;
73  } else if (PragmaNoUnroll) {
74  Option = LoopHintAttr::Unroll;
75  Spelling = LoopHintAttr::Pragma_nounroll;
76  } else {
77  assert(OptionLoc && OptionLoc->Ident &&
78  "Attribute must have valid option info.");
79  IdentifierInfo *OptionInfo = OptionLoc->Ident;
80  Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
81  .Case("vectorize", LoopHintAttr::Vectorize)
82  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
83  .Case("interleave", LoopHintAttr::Interleave)
84  .Case("interleave_count", LoopHintAttr::InterleaveCount)
85  .Case("unroll", LoopHintAttr::Unroll)
86  .Case("unroll_count", LoopHintAttr::UnrollCount)
87  .Default(LoopHintAttr::Vectorize);
88  Spelling = LoopHintAttr::Pragma_clang_loop;
89  }
90 
91  LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
92  if (PragmaNoUnroll) {
93  State = LoopHintAttr::Disable;
94  } else if (Option == LoopHintAttr::VectorizeWidth ||
95  Option == LoopHintAttr::InterleaveCount ||
96  Option == LoopHintAttr::UnrollCount) {
97  assert(ValueExpr && "Attribute must have a valid value expression.");
98  if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
99  return nullptr;
100  } else if (Option == LoopHintAttr::Vectorize ||
101  Option == LoopHintAttr::Interleave ||
102  Option == LoopHintAttr::Unroll) {
103  // Default state is assumed if StateLoc is not specified, such as with
104  // '#pragma unroll'.
105  if (StateLoc && StateLoc->Ident) {
106  if (StateLoc->Ident->isStr("disable"))
107  State = LoopHintAttr::Disable;
108  else if (StateLoc->Ident->isStr("assume_safety"))
109  State = LoopHintAttr::AssumeSafety;
110  else
111  State = LoopHintAttr::Enable;
112  }
113  }
114 
115  return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
116  ValueExpr, A.getRange());
117 }
118 
119 static void
121  const SmallVectorImpl<const Attr *> &Attrs) {
122  // There are 3 categories of loop hints attributes: vectorize, interleave,
123  // and unroll. Each comes in two variants: a state form and a numeric form.
124  // The state form selectively defaults/enables/disables the transformation
125  // for the loop (for unroll, default indicates full unrolling rather than
126  // enabling the transformation). The numeric form form provides an integer
127  // hint (for example, unroll count) to the transformer. The following array
128  // accumulates the hints encountered while iterating through the attributes
129  // to check for compatibility.
130  struct {
131  const LoopHintAttr *StateAttr;
132  const LoopHintAttr *NumericAttr;
133  } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
134 
135  for (const auto *I : Attrs) {
136  const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
137 
138  // Skip non loop hint attributes
139  if (!LH)
140  continue;
141 
142  int Option = LH->getOption();
143  int Category;
144  enum { Vectorize, Interleave, Unroll };
145  switch (Option) {
146  case LoopHintAttr::Vectorize:
147  case LoopHintAttr::VectorizeWidth:
148  Category = Vectorize;
149  break;
150  case LoopHintAttr::Interleave:
151  case LoopHintAttr::InterleaveCount:
152  Category = Interleave;
153  break;
154  case LoopHintAttr::Unroll:
155  case LoopHintAttr::UnrollCount:
156  Category = Unroll;
157  break;
158  };
159 
160  auto &CategoryState = HintAttrs[Category];
161  const LoopHintAttr *PrevAttr;
162  if (Option == LoopHintAttr::Vectorize ||
163  Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
164  // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
165  PrevAttr = CategoryState.StateAttr;
166  CategoryState.StateAttr = LH;
167  } else {
168  // Numeric hint. For example, vectorize_width(8).
169  PrevAttr = CategoryState.NumericAttr;
170  CategoryState.NumericAttr = LH;
171  }
172 
173  PrintingPolicy Policy(S.Context.getLangOpts());
174  SourceLocation OptionLoc = LH->getRange().getBegin();
175  if (PrevAttr)
176  // Cannot specify same type of attribute twice.
177  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
178  << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
179  << LH->getDiagnosticName(Policy);
180 
181  if (CategoryState.StateAttr && CategoryState.NumericAttr &&
182  (Category == Unroll ||
183  CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
184  // Disable hints are not compatible with numeric hints of the same
185  // category. As a special case, numeric unroll hints are also not
186  // compatible with "enable" form of the unroll pragma, unroll(full).
187  S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
188  << /*Duplicate=*/false
189  << CategoryState.StateAttr->getDiagnosticName(Policy)
190  << CategoryState.NumericAttr->getDiagnosticName(Policy);
191  }
192  }
193 }
194 
196  SourceRange Range) {
197  switch (A.getKind()) {
199  S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
200  diag::warn_unhandled_ms_attribute_ignored :
201  diag::warn_unknown_attribute_ignored) << A.getName();
202  return nullptr;
203  case AttributeList::AT_FallThrough:
204  return handleFallThroughAttr(S, St, A, Range);
205  case AttributeList::AT_LoopHint:
206  return handleLoopHintAttr(S, St, A, Range);
207  default:
208  // if we're here, then we parsed a known attribute, but didn't recognize
209  // it as a statement attribute => it is declaration attribute
210  S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
211  << A.getName() << St->getLocStart();
212  return nullptr;
213  }
214 }
215 
217  SourceRange Range) {
219  for (const AttributeList* l = AttrList; l; l = l->getNext()) {
220  if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
221  Attrs.push_back(a);
222  }
223 
224  CheckForIncompatibleAttributes(*this, Attrs);
225 
226  if (Attrs.empty())
227  return S;
228 
229  return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
230 }
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc)
Definition: SemaExpr.cpp:3174
Defines the SourceManager interface.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition: Sema.h:1088
SourceRange getRange() const
IdentifierInfo * Ident
Definition: AttributeList.h:52
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:47
SmallVector< SwitchStmt *, 8 > SwitchStack
Definition: ScopeInfo.h:138
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:35
LineState State
const LangOptions & getLangOpts() const
Definition: ASTContext.h:533
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:258
Kind getKind() const
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. This index is used by an attribute ...
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
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:1137
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