diff options
author | George Burgess IV <george.burgess.iv@gmail.com> | 2017-01-09 04:12:14 +0000 |
---|---|---|
committer | George Burgess IV <george.burgess.iv@gmail.com> | 2017-01-09 04:12:14 +0000 |
commit | 177399e2277c3dbecfc00d83f94784cc7bfdd4d6 (patch) | |
tree | fd3bdd091ba2ff8942eec3c67d793d6afc236b67 /clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | ff567a8ba200e05cd92015403302983510959766 (diff) | |
download | bcm5719-llvm-177399e2277c3dbecfc00d83f94784cc7bfdd4d6.tar.gz bcm5719-llvm-177399e2277c3dbecfc00d83f94784cc7bfdd4d6.zip |
Add the diagnose_if attribute to clang.
`diagnose_if` can be used to have clang emit either warnings or errors
for function calls that meet user-specified conditions. For example:
```
constexpr int foo(int a)
__attribute__((diagnose_if(a > 10, "configurations with a > 10 are "
"expensive.", "warning")));
int f1 = foo(9);
int f2 = foo(10); // warning: configuration with a > 10 are expensive.
int f3 = foo(f2);
```
It currently only emits diagnostics in cases where the condition is
guaranteed to always be true. So, the following code will emit no
warnings:
```
constexpr int bar(int a) {
foo(a);
return 0;
}
constexpr int i = bar(10);
```
We hope to support optionally emitting diagnostics for cases like that
(and emitting runtime checks) in the future.
Release notes will appear shortly. :)
Differential Revision: https://reviews.llvm.org/D27424
llvm-svn: 291418
Diffstat (limited to 'clang/lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ffe35662303..d2a5e5cb531 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -168,40 +168,59 @@ static void instantiateDependentAlignValueAttr( Aligned->getSpellingListIndex()); } -static void instantiateDependentEnableIfAttr( +static Expr *instantiateDependentFunctionAttrCondition( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const EnableIfAttr *A, const Decl *Tmpl, Decl *New) { + const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) { Expr *Cond = nullptr; { - Sema::ContextRAII SwitchContext(S, cast<FunctionDecl>(New)); + Sema::ContextRAII SwitchContext(S, New); EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated); - ExprResult Result = S.SubstExpr(A->getCond(), TemplateArgs); + ExprResult Result = S.SubstExpr(OldCond, TemplateArgs); if (Result.isInvalid()) - return; + return nullptr; Cond = Result.getAs<Expr>(); } if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) - return; + return nullptr; Cond = Converted.get(); } SmallVector<PartialDiagnosticAt, 8> Diags; - if (A->getCond()->isValueDependent() && !Cond->isValueDependent() && - !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New), - Diags)) { - S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr); - for (int I = 0, N = Diags.size(); I != N; ++I) - S.Diag(Diags[I].first, Diags[I].second); - return; + if (OldCond->isValueDependent() && !Cond->isValueDependent() && + !Expr::isPotentialConstantExprUnevaluated(Cond, New, Diags)) { + S.Diag(A->getLocation(), diag::err_attr_cond_never_constant_expr) << A; + for (const auto &P : Diags) + S.Diag(P.first, P.second); + return nullptr; } + return Cond; +} - EnableIfAttr *EIA = new (S.getASTContext()) - EnableIfAttr(A->getLocation(), S.getASTContext(), Cond, - A->getMessage(), - A->getSpellingListIndex()); - New->addAttr(EIA); +static void instantiateDependentEnableIfAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const EnableIfAttr *EIA, const Decl *Tmpl, FunctionDecl *New) { + Expr *Cond = instantiateDependentFunctionAttrCondition( + S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New); + + if (Cond) + New->addAttr(new (S.getASTContext()) EnableIfAttr( + EIA->getLocation(), S.getASTContext(), Cond, EIA->getMessage(), + EIA->getSpellingListIndex())); +} + +static void instantiateDependentDiagnoseIfAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const DiagnoseIfAttr *DIA, const Decl *Tmpl, FunctionDecl *New) { + Expr *Cond = instantiateDependentFunctionAttrCondition( + S, TemplateArgs, DIA, DIA->getCond(), Tmpl, New); + + if (Cond) + New->addAttr(new (S.getASTContext()) DiagnoseIfAttr( + DIA->getLocation(), S.getASTContext(), Cond, DIA->getMessage(), + DIA->getDiagnosticType(), DIA->getArgDependent(), New, + DIA->getSpellingListIndex())); } // Constructs and adds to New a new instance of CUDALaunchBoundsAttr using @@ -335,7 +354,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) { instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl, - New); + cast<FunctionDecl>(New)); + continue; + } + + if (const auto *DiagnoseIf = dyn_cast<DiagnoseIfAttr>(TmplAttr)) { + instantiateDependentDiagnoseIfAttr(*this, TemplateArgs, DiagnoseIf, Tmpl, + cast<FunctionDecl>(New)); continue; } |