]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
Merge xz 5.2.0.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Sema / SemaStmtAttr.cpp
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
14 #include "clang/Sema/SemaInternal.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Sema/DelayedDiagnostic.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   if (!isa<NullStmt>(St)) {
29     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
30         << St->getLocStart();
31     if (isa<SwitchCase>(St)) {
32       SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
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,
43                                            A.getAttributeSpellingListIndex());
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   IdentifierInfo *OptionInfo = OptionLoc->Ident;
51   IdentifierLoc *ValueLoc = A.getArgAsIdent(2);
52   IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;
53   Expr *ValueExpr = A.getArgAsExpr(3);
54
55   assert(OptionInfo && "Attribute must have valid option info.");
56
57   if (St->getStmtClass() != Stmt::DoStmtClass &&
58       St->getStmtClass() != Stmt::ForStmtClass &&
59       St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
60       St->getStmtClass() != Stmt::WhileStmtClass) {
61     const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll"
62                              ? "#pragma unroll"
63                              : "#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 (PragmaNameLoc->Ident->getName() == "unroll") {
71     Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
72     Spelling = LoopHintAttr::Pragma_unroll;
73   } else {
74     Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
75                  .Case("vectorize", LoopHintAttr::Vectorize)
76                  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
77                  .Case("interleave", LoopHintAttr::Interleave)
78                  .Case("interleave_count", LoopHintAttr::InterleaveCount)
79                  .Case("unroll", LoopHintAttr::Unroll)
80                  .Case("unroll_count", LoopHintAttr::UnrollCount)
81                  .Default(LoopHintAttr::Vectorize);
82     Spelling = LoopHintAttr::Pragma_clang_loop;
83   }
84
85   int ValueInt;
86   if (Option == LoopHintAttr::Unroll &&
87       Spelling == LoopHintAttr::Pragma_unroll) {
88     ValueInt = 1;
89   } else if (Option == LoopHintAttr::Vectorize ||
90              Option == LoopHintAttr::Interleave ||
91              Option == LoopHintAttr::Unroll) {
92     if (!ValueInfo) {
93       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
94       return nullptr;
95     }
96     if (ValueInfo->isStr("disable"))
97       ValueInt = 0;
98     else if (ValueInfo->isStr("enable"))
99       ValueInt = 1;
100     else {
101       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
102       return nullptr;
103     }
104   } else if (Option == LoopHintAttr::VectorizeWidth ||
105              Option == LoopHintAttr::InterleaveCount ||
106              Option == LoopHintAttr::UnrollCount) {
107     // FIXME: We should support template parameters for the loop hint value.
108     // See bug report #19610.
109     llvm::APSInt ValueAPS;
110     if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
111         (ValueInt = ValueAPS.getSExtValue()) < 1) {
112       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value);
113       return nullptr;
114     }
115   } else
116     llvm_unreachable("Unknown loop hint option");
117
118   return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt,
119                                       A.getRange());
120 }
121
122 static void CheckForIncompatibleAttributes(
123     Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
124   // There are 3 categories of loop hints: vectorize, interleave, and
125   // unroll. Each comes in two variants: an enable/disable form and a
126   // form which takes a numeric argument. For example:
127   // unroll(enable|disable) and unroll_count(N). The following array
128   // accumulate the hints encountered while iterating through the
129   // attributes to check for compatibility.
130   struct {
131     const LoopHintAttr *EnableAttr;
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     switch (Option) {
145     case LoopHintAttr::Vectorize:
146     case LoopHintAttr::VectorizeWidth:
147       Category = 0;
148       break;
149     case LoopHintAttr::Interleave:
150     case LoopHintAttr::InterleaveCount:
151       Category = 1;
152       break;
153     case LoopHintAttr::Unroll:
154     case LoopHintAttr::UnrollCount:
155       Category = 2;
156       break;
157     };
158
159     auto &CategoryState = HintAttrs[Category];
160     SourceLocation OptionLoc = LH->getRange().getBegin();
161     const LoopHintAttr *PrevAttr;
162     if (Option == LoopHintAttr::Vectorize ||
163         Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
164       // Enable|disable hint.  For example, vectorize(enable).
165       PrevAttr = CategoryState.EnableAttr;
166       CategoryState.EnableAttr = LH;
167     } else {
168       // Numeric hint.  For example, vectorize_width(8).
169       PrevAttr = CategoryState.NumericAttr;
170       CategoryState.NumericAttr = LH;
171     }
172
173     if (PrevAttr)
174       // Cannot specify same type of attribute twice.
175       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
176           << /*Duplicate=*/true << PrevAttr->getDiagnosticName()
177           << LH->getDiagnosticName();
178
179     if (CategoryState.EnableAttr && !CategoryState.EnableAttr->getValue() &&
180         CategoryState.NumericAttr) {
181       // Disable hints are not compatible with numeric hints of the
182       // same category.
183       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
184           << /*Duplicate=*/false
185           << CategoryState.EnableAttr->getDiagnosticName()
186           << CategoryState.NumericAttr->getDiagnosticName();
187     }
188   }
189 }
190
191 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
192                                   SourceRange Range) {
193   switch (A.getKind()) {
194   case AttributeList::UnknownAttribute:
195     S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
196            diag::warn_unhandled_ms_attribute_ignored :
197            diag::warn_unknown_attribute_ignored) << A.getName();
198     return nullptr;
199   case AttributeList::AT_FallThrough:
200     return handleFallThroughAttr(S, St, A, Range);
201   case AttributeList::AT_LoopHint:
202     return handleLoopHintAttr(S, St, A, Range);
203   default:
204     // if we're here, then we parsed a known attribute, but didn't recognize
205     // it as a statement attribute => it is declaration attribute
206     S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
207         << A.getName() << St->getLocStart();
208     return nullptr;
209   }
210 }
211
212 StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
213                                        SourceRange Range) {
214   SmallVector<const Attr*, 8> Attrs;
215   for (const AttributeList* l = AttrList; l; l = l->getNext()) {
216     if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
217       Attrs.push_back(a);
218   }
219
220   CheckForIncompatibleAttributes(*this, Attrs);
221
222   if (Attrs.empty())
223     return S;
224
225   return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
226 }