Home | History | Annotate | Download | only in Sema
      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           .Case("unroll", LoopHintAttr::Unroll)
     71           .Case("unroll_count", LoopHintAttr::UnrollCount)
     72           .Default(LoopHintAttr::Vectorize);
     73 
     74   int ValueInt;
     75   if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave ||
     76       Option == LoopHintAttr::Unroll) {
     77     if (!ValueInfo) {
     78       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
     79       return nullptr;
     80     }
     81     if (ValueInfo->isStr("disable"))
     82       ValueInt = 0;
     83     else if (ValueInfo->isStr("enable"))
     84       ValueInt = 1;
     85     else {
     86       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
     87       return nullptr;
     88     }
     89   } else if (Option == LoopHintAttr::VectorizeWidth ||
     90              Option == LoopHintAttr::InterleaveCount ||
     91              Option == LoopHintAttr::UnrollCount) {
     92     // FIXME: We should support template parameters for the loop hint value.
     93     // See bug report #19610.
     94     llvm::APSInt ValueAPS;
     95     if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
     96         (ValueInt = ValueAPS.getSExtValue()) < 1) {
     97       S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value);
     98       return nullptr;
     99     }
    100   } else
    101     llvm_unreachable("Unknown loop hint option");
    102 
    103   return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt,
    104                                       A.getRange());
    105 }
    106 
    107 static void
    108 CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
    109   // There are 3 categories of loop hints: vectorize, interleave, and
    110   // unroll. Each comes in two variants: an enable/disable form and a
    111   // form which takes a numeric argument. For example:
    112   // unroll(enable|disable) and unroll_count(N). The following array
    113   // accumulate the hints encountered while iterating through the
    114   // attributes to check for compatibility.
    115   struct {
    116     int EnableOptionId;
    117     int NumericOptionId;
    118     bool EnabledIsSet;
    119     bool ValueIsSet;
    120     bool Enabled;
    121     int Value;
    122   } Options[] = {{LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth, false,
    123                   false, false, 0},
    124                  {LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount,
    125                   false, false, false, 0},
    126                  {LoopHintAttr::Unroll, LoopHintAttr::UnrollCount, false, false,
    127                   false, 0}};
    128 
    129   for (const auto *I : Attrs) {
    130     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
    131 
    132     // Skip non loop hint attributes
    133     if (!LH)
    134       continue;
    135 
    136     int Option = LH->getOption();
    137     int ValueInt = LH->getValue();
    138 
    139     int Category;
    140     switch (Option) {
    141     case LoopHintAttr::Vectorize:
    142     case LoopHintAttr::VectorizeWidth:
    143       Category = 0;
    144       break;
    145     case LoopHintAttr::Interleave:
    146     case LoopHintAttr::InterleaveCount:
    147       Category = 1;
    148       break;
    149     case LoopHintAttr::Unroll:
    150     case LoopHintAttr::UnrollCount:
    151       Category = 2;
    152       break;
    153     };
    154 
    155     auto &CategoryState = Options[Category];
    156     SourceLocation ValueLoc = LH->getRange().getEnd();
    157     if (Option == LoopHintAttr::Vectorize ||
    158         Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
    159       // Enable|disable hint.  For example, vectorize(enable).
    160       if (CategoryState.EnabledIsSet) {
    161         // Cannot specify enable/disable state twice.
    162         S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
    163             << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
    164             << LoopHintAttr::getValueName(CategoryState.Enabled)
    165             << LoopHintAttr::getOptionName(Option)
    166             << LoopHintAttr::getValueName(ValueInt);
    167       }
    168       CategoryState.EnabledIsSet = true;
    169       CategoryState.Enabled = ValueInt;
    170     } else {
    171       // Numeric hint.  For example, unroll_count(8).
    172       if (CategoryState.ValueIsSet) {
    173         // Cannot specify numeric hint twice.
    174         S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
    175             << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
    176             << CategoryState.Value << LoopHintAttr::getOptionName(Option)
    177             << ValueInt;
    178       }
    179       CategoryState.ValueIsSet = true;
    180       CategoryState.Value = ValueInt;
    181     }
    182 
    183     if (CategoryState.EnabledIsSet && !CategoryState.Enabled &&
    184         CategoryState.ValueIsSet) {
    185       // Disable hints are not compatible with numeric hints of the
    186       // same category.
    187       S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
    188           << /*Duplicate=*/false
    189           << LoopHintAttr::getOptionName(CategoryState.EnableOptionId)
    190           << LoopHintAttr::getValueName(CategoryState.Enabled)
    191           << LoopHintAttr::getOptionName(CategoryState.NumericOptionId)
    192           << CategoryState.Value;
    193     }
    194   }
    195 }
    196 
    197 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
    198                                   SourceRange Range) {
    199   switch (A.getKind()) {
    200   case AttributeList::UnknownAttribute:
    201     S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
    202            diag::warn_unhandled_ms_attribute_ignored :
    203            diag::warn_unknown_attribute_ignored) << A.getName();
    204     return nullptr;
    205   case AttributeList::AT_FallThrough:
    206     return handleFallThroughAttr(S, St, A, Range);
    207   case AttributeList::AT_LoopHint:
    208     return handleLoopHintAttr(S, St, A, Range);
    209   default:
    210     // if we're here, then we parsed a known attribute, but didn't recognize
    211     // it as a statement attribute => it is declaration attribute
    212     S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
    213         << A.getName() << St->getLocStart();
    214     return nullptr;
    215   }
    216 }
    217 
    218 StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
    219                                        SourceRange Range) {
    220   SmallVector<const Attr*, 8> Attrs;
    221   for (const AttributeList* l = AttrList; l; l = l->getNext()) {
    222     if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
    223       Attrs.push_back(a);
    224   }
    225 
    226   CheckForIncompatibleAttributes(*this, Attrs);
    227 
    228   if (Attrs.empty())
    229     return S;
    230 
    231   return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
    232 }
    233