summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp109
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;
OpenPOWER on IntegriCloud