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   if (St->getStmtClass() != Stmt::DoStmtClass &&
49       St->getStmtClass() != Stmt::ForStmtClass &&
50       St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
51       St->getStmtClass() != Stmt::WhileStmtClass) {
52     S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop);
53     return nullptr;
54   }
55 
56   IdentifierLoc *OptionLoc = A.getArgAsIdent(0);
57   IdentifierInfo *OptionInfo = OptionLoc->Ident;
58   IdentifierLoc *ValueLoc = A.getArgAsIdent(1);
59   IdentifierInfo *ValueInfo = ValueLoc->Ident;
60   Expr *ValueExpr = A.getArgAsExpr(2);
61 
62   assert(OptionInfo && "Attribute must have valid option info.");
63 
64   LoopHintAttr::OptionType Option =
65       llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
66           .Case("vectorize", LoopHintAttr::Vectorize)
67           .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
68           .Case("interleave", LoopHintAttr::Interleave)
69           .Case("interleave_count", LoopHintAttr::InterleaveCount)
70           .Default(LoopHintAttr::Vectorize);
71 
72   int ValueInt;
73   if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave) {
74     if (!ValueInfo) {
75       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
76           << /*MissingKeyword=*/true << "";
77       return nullptr;
78     }
79 
80     if (ValueInfo->isStr("disable"))
81       ValueInt = 0;
82     else if (ValueInfo->isStr("enable"))
83       ValueInt = 1;
84     else {
85       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
86           << /*MissingKeyword=*/false << ValueInfo;
87       return nullptr;
88     }
89   } else if (Option == LoopHintAttr::VectorizeWidth ||
90              Option == LoopHintAttr::InterleaveCount) {
91     // FIXME: We should support template parameters for the loop hint value.
92     // See bug report #19610.
93     llvm::APSInt ValueAPS;
94     if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context)) {
95       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value)
96           << /*MissingValue=*/true << "";
97       return nullptr;
98     }
99 
100     if ((ValueInt = ValueAPS.getSExtValue()) < 1) {
101       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value)
102           << /*MissingValue=*/false << ValueInt;
103       return nullptr;
104     }
105   } else
106     llvm_unreachable("Unknown loop hint option");
107 
108   return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt,
109                                       A.getRange());
110 }
111 
112 static void
113 CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
114   int PrevOptionValue[4] = {-1, -1, -1, -1};
115   int OptionId[4] = {LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth,
116                      LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount};
117 
118   for (const auto *I : Attrs) {
119     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
120 
121     // Skip non loop hint attributes
122     if (!LH)
123       continue;
124 
125     int State, Value;
126     int Option = LH->getOption();
127     int ValueInt = LH->getValue();
128 
129     switch (Option) {
130     case LoopHintAttr::Vectorize:
131     case LoopHintAttr::VectorizeWidth:
132       State = 0;
133       Value = 1;
134       break;
135     case LoopHintAttr::Interleave:
136     case LoopHintAttr::InterleaveCount:
137       State = 2;
138       Value = 3;
139       break;
140     }
141 
142     SourceLocation ValueLoc = LH->getRange().getEnd();
143 
144     // Compatibility testing is split into two cases.
145     // 1. if the current loop hint sets state (enable/disable) - check against
146     // previous state and value.
147     // 2. if the current loop hint sets a value - check against previous state
148     // and value.
149 
150     if (Option == State) {
151       if (PrevOptionValue[State] != -1) {
152         // Cannot specify state twice.
153         int PrevValue = PrevOptionValue[State];
154         S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
155             << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
156             << LoopHintAttr::getValueName(PrevValue)
157             << LoopHintAttr::getOptionName(Option)
158             << LoopHintAttr::getValueName(Value);
159       }
160 
161       if (PrevOptionValue[Value] != -1) {
162         // Compare state with previous width/count.
163         int PrevOption = OptionId[Value];
164         int PrevValueInt = PrevOptionValue[Value];
165         if ((ValueInt == 0 && PrevValueInt > 1) ||
166             (ValueInt == 1 && PrevValueInt <= 1))
167           S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
168               << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption)
169               << PrevValueInt << LoopHintAttr::getOptionName(Option)
170               << LoopHintAttr::getValueName(ValueInt);
171       }
172     } else {
173       if (PrevOptionValue[State] != -1) {
174         // Compare width/count value with previous state.
175         int PrevOption = OptionId[State];
176         int PrevValueInt = PrevOptionValue[State];
177         if ((ValueInt > 1 && PrevValueInt == 0) ||
178             (ValueInt <= 1 && PrevValueInt == 1))
179           S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
180               << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption)
181               << LoopHintAttr::getValueName(PrevValueInt)
182               << LoopHintAttr::getOptionName(Option) << ValueInt;
183       }
184 
185       if (PrevOptionValue[Value] != -1) {
186         // Cannot specify a width/count twice.
187         int PrevValueInt = PrevOptionValue[Value];
188         S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
189             << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
190             << PrevValueInt << LoopHintAttr::getOptionName(Option) << ValueInt;
191       }
192     }
193 
194     PrevOptionValue[Option] = ValueInt;
195   }
196 }
197 
198 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
199                                   SourceRange Range) {
200   switch (A.getKind()) {
201   case AttributeList::UnknownAttribute:
202     S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
203            diag::warn_unhandled_ms_attribute_ignored :
204            diag::warn_unknown_attribute_ignored) << A.getName();
205     return nullptr;
206   case AttributeList::AT_FallThrough:
207     return handleFallThroughAttr(S, St, A, Range);
208   case AttributeList::AT_LoopHint:
209     return handleLoopHintAttr(S, St, A, Range);
210   default:
211     // if we're here, then we parsed a known attribute, but didn't recognize
212     // it as a statement attribute => it is declaration attribute
213     S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
214         << A.getName() << St->getLocStart();
215     return nullptr;
216   }
217 }
218 
219 StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
220                                        SourceRange Range) {
221   SmallVector<const Attr*, 8> Attrs;
222   for (const AttributeList* l = AttrList; l; l = l->getNext()) {
223     if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
224       Attrs.push_back(a);
225   }
226 
227   CheckForIncompatibleAttributes(*this, Attrs);
228 
229   if (Attrs.empty())
230     return S;
231 
232   return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
233 }
234