|
40 | 40 | #include "clang/Sema/ParsedAttr.h" |
41 | 41 | #include "clang/Sema/Scope.h" |
42 | 42 | #include "clang/Sema/ScopeInfo.h" |
| 43 | +#include "clang/Sema/Sema.h" |
43 | 44 | #include "clang/Sema/SemaAMDGPU.h" |
44 | 45 | #include "clang/Sema/SemaARM.h" |
45 | 46 | #include "clang/Sema/SemaAVR.h" |
@@ -1938,6 +1939,49 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1938 | 1939 | D->addAttr(::new (S.Context) NakedAttr(S.Context, AL)); |
1939 | 1940 | } |
1940 | 1941 |
|
| 1942 | +// FIXME: This is a best-effort heuristic. |
| 1943 | +// Currently only handles single throw expressions (optionally with |
| 1944 | +// ExprWithCleanups). We could expand this to perform control-flow analysis for |
| 1945 | +// more complex patterns. |
| 1946 | +static bool isKnownToAlwaysThrow(const FunctionDecl *FD) { |
| 1947 | + if (!FD->hasBody()) |
| 1948 | + return false; |
| 1949 | + const Stmt *Body = FD->getBody(); |
| 1950 | + const Stmt *OnlyStmt = nullptr; |
| 1951 | + |
| 1952 | + if (const auto *Compound = dyn_cast<CompoundStmt>(Body)) { |
| 1953 | + if (Compound->size() != 1) |
| 1954 | + return false; // More than one statement, can't be known to always throw. |
| 1955 | + OnlyStmt = *Compound->body_begin(); |
| 1956 | + } else { |
| 1957 | + OnlyStmt = Body; |
| 1958 | + } |
| 1959 | + |
| 1960 | + // Unwrap ExprWithCleanups if necessary. |
| 1961 | + if (const auto *EWC = dyn_cast<ExprWithCleanups>(OnlyStmt)) { |
| 1962 | + OnlyStmt = EWC->getSubExpr(); |
| 1963 | + } |
| 1964 | + // Check if the only statement is a throw expression. |
| 1965 | + return isa<CXXThrowExpr>(OnlyStmt); |
| 1966 | +} |
| 1967 | + |
| 1968 | +void clang::inferNoReturnAttr(Sema &S, const Decl *D) { |
| 1969 | + auto *FD = dyn_cast<FunctionDecl>(D); |
| 1970 | + if (!FD) |
| 1971 | + return; |
| 1972 | + |
| 1973 | + auto *NonConstFD = const_cast<FunctionDecl *>(FD); |
| 1974 | + DiagnosticsEngine &Diags = S.getDiagnostics(); |
| 1975 | + if (Diags.isIgnored(diag::warn_falloff_nonvoid, FD->getLocation()) && |
| 1976 | + Diags.isIgnored(diag::warn_suggest_noreturn_function, FD->getLocation())) |
| 1977 | + return; |
| 1978 | + |
| 1979 | + if (!FD->hasAttr<NoReturnAttr>() && !FD->hasAttr<InferredNoReturnAttr>() && |
| 1980 | + isKnownToAlwaysThrow(FD)) { |
| 1981 | + NonConstFD->addAttr(InferredNoReturnAttr::CreateImplicit(S.Context)); |
| 1982 | + } |
| 1983 | +} |
| 1984 | + |
1941 | 1985 | static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { |
1942 | 1986 | if (hasDeclarator(D)) return; |
1943 | 1987 |
|
|
0 commit comments