diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 109 |
1 files changed, 98 insertions, 11 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f9b6a91a300..c6a5bc74145 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -32,6 +32,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" @@ -890,34 +891,117 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); - - Expr *Cond = Attr.getArgAsExpr(0); +static bool checkFunctionConditionAttr(Sema &S, Decl *D, + const AttributeList &Attr, + Expr *&Cond, StringRef &Msg) { + Cond = Attr.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) - return; + return false; Cond = Converted.get(); } - StringRef Msg; if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg)) - return; + return false; + + if (Msg.empty()) + Msg = "<no message provided>"; SmallVector<PartialDiagnosticAt, 8> Diags; if (!Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { - S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr); + S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) + << Attr.getName(); for (const PartialDiagnosticAt &PDiag : Diags) S.Diag(PDiag.first, PDiag.second); + return false; + } + return true; +} + +static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); + + Expr *Cond; + StringRef Msg; + if (checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + D->addAttr(::new (S.Context) + EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, + Attr.getAttributeSpellingListIndex())); +} + +namespace { +/// Determines if a given Expr references any of the given function's +/// ParmVarDecls, or the function's implicit `this` parameter (if applicable). +class ArgumentDependenceChecker + : public RecursiveASTVisitor<ArgumentDependenceChecker> { +#ifndef NDEBUG + const CXXRecordDecl *ClassType; +#endif + llvm::SmallPtrSet<const ParmVarDecl *, 16> Parms; + bool Result; + +public: + ArgumentDependenceChecker(const FunctionDecl *FD) { +#ifndef NDEBUG + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) + ClassType = MD->getParent(); + else + ClassType = nullptr; +#endif + Parms.insert(FD->param_begin(), FD->param_end()); + } + + bool referencesArgs(Expr *E) { + Result = false; + TraverseStmt(E); + return Result; + } + + bool VisitCXXThisExpr(CXXThisExpr *E) { + assert(E->getType()->getPointeeCXXRecordDecl() == ClassType && + "`this` doesn't refer to the enclosing class?"); + Result = true; + return false; + } + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) + if (Parms.count(PVD)) { + Result = true; + return false; + } + return true; + } +}; +} + +static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.Diag(Attr.getLoc(), diag::ext_clang_diagnose_if); + + Expr *Cond; + StringRef Msg; + if (!checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + return; + + StringRef DiagTypeStr; + if (!S.checkStringLiteralArgumentAttr(Attr, 2, DiagTypeStr)) + return; + + DiagnoseIfAttr::DiagnosticType DiagType; + if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { + S.Diag(Attr.getArgAsExpr(2)->getLocStart(), + diag::err_diagnose_if_invalid_diagnostic_type); return; } - D->addAttr(::new (S.Context) - EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, - Attr.getAttributeSpellingListIndex())); + auto *FD = cast<FunctionDecl>(D); + bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); + D->addAttr(::new (S.Context) DiagnoseIfAttr( + Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD, + Attr.getAttributeSpellingListIndex())); } static void handlePassObjectSizeAttr(Sema &S, Decl *D, @@ -5682,6 +5766,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_EnableIf: handleEnableIfAttr(S, D, Attr); break; + case AttributeList::AT_DiagnoseIf: + handleDiagnoseIfAttr(S, D, Attr); + break; case AttributeList::AT_ExtVectorType: handleExtVectorTypeAttr(S, scope, D, Attr); break; |