[cfe-commits] r140846 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/Preprocessor.h include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/Lex/PPDirectives.cpp lib/Lex/PPLexerChange.cpp lib/Lex/Pragma.cpp lib/Sema/AttributeList.cpp lib/Sema/SemaAttr.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp test/Sema/Inputs/pragma-arc-cf-code-audited.h test/Sema/pragma-arc-cf-code-audited.c
John McCall
rjmccall at apple.com
Thu Sep 29 22:12:13 PDT 2011
Author: rjmccall
Date: Fri Sep 30 00:12:12 2011
New Revision: 140846
URL: http://llvm.org/viewvc/llvm-project?rev=140846&view=rev
Log:
Add explicit attributes to mark functions as having had their
CoreFoundation object-transfer properties audited, and add a #pragma
to cause them to be automatically applied to functions in a particular
span of code. This has to be implemented largely in the preprocessor
because of the requirement that the region be entirely contained in
a single file; that's hard to impose from the parser without registering
for a ton of callbacks.
Added:
cfe/trunk/test/Sema/Inputs/pragma-arc-cf-code-audited.h
cfe/trunk/test/Sema/pragma-arc-cf-code-audited.c
Modified:
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/include/clang/Sema/AttributeList.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Lex/PPDirectives.cpp
cfe/trunk/lib/Lex/PPLexerChange.cpp
cfe/trunk/lib/Lex/Pragma.cpp
cfe/trunk/lib/Sema/AttributeList.cpp
cfe/trunk/lib/Sema/SemaAttr.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Sep 30 00:12:12 2011
@@ -171,6 +171,23 @@
let Spellings = ["cdecl", "__cdecl"];
}
+// cf_audited_transfer indicates that the given function has been
+// audited and has been marked with the appropriate cf_consumed and
+// cf_returns_retained attributes. It is generally applied by
+// '#pragma clang arc_cf_code_audited' rather than explicitly.
+def CFAuditedTransfer : InheritableAttr {
+ let Spellings = ["cf_audited_transfer"];
+ let Subjects = [Function];
+}
+
+// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer.
+// It indicates that the function has unknown or unautomatable
+// transfer semantics.
+def CFUnknownTransfer : InheritableAttr {
+ let Spellings = ["cf_unknown_transfer"];
+ let Subjects = [Function];
+}
+
def CFReturnsRetained : InheritableAttr {
let Spellings = ["cf_returns_retained"];
let Subjects = [ObjCMethod, Function];
Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Fri Sep 30 00:12:12 2011
@@ -65,6 +65,7 @@
DefaultFatal;
def warn_module_build : Warning<"building module '%0' from source">,
InGroup<ModuleBuild>, DefaultIgnore;
+def note_pragma_entered_here : Note<"#pragma entered here">;
// Sema && Lex
def ext_longlong : Extension<
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Sep 30 00:12:12 2011
@@ -326,4 +326,14 @@
def err_pp_export_non_macro : Error<"no macro named %0 to export">;
+def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">;
+def err_pp_double_begin_of_arc_cf_code_audited : Error<
+ "already inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_unmatched_end_of_arc_cf_code_audited : Error<
+ "not currently inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_include_in_arc_cf_code_audited : Error<
+ "cannot #include files inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_eof_in_arc_cf_code_audited : Error<
+ "'#pragma clang arc_cf_code_audited' was not ended within this file">;
+
}
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Sep 30 00:12:12 2011
@@ -165,6 +165,10 @@
/// \brief The source location of the __import_module__ keyword we just
/// lexed, if any.
SourceLocation ModuleImportLoc;
+
+ /// \brief The source location of the currently-active
+ /// #pragma clang arc_cf_code_audited begin.
+ SourceLocation PragmaARCCFCodeAuditedLoc;
/// \brief True if we hit the code-completion point.
bool CodeCompletionReached;
@@ -720,6 +724,19 @@
getDiagnostics().setSuppressAllDiagnostics(true);
}
+ /// \brief The location of the currently-active #pragma clang
+ /// arc_cf_code_audited begin. Returns an invalid location if there
+ /// is no such pragma active.
+ SourceLocation getPragmaARCCFCodeAuditedLoc() const {
+ return PragmaARCCFCodeAuditedLoc;
+ }
+
+ /// \brief Set the location of the currently-active #pragma clang
+ /// arc_cf_code_audited begin. An invalid location ends the pragma.
+ void setPragmaARCCFCodeAuditedLoc(SourceLocation Loc) {
+ PragmaARCCFCodeAuditedLoc = Loc;
+ }
+
/// \brief Instruct the preprocessor to skip part of the main
/// the main source file.
///
Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Fri Sep 30 00:12:12 2011
@@ -166,10 +166,12 @@
AT_blocks,
AT_carries_dependency,
AT_cdecl,
+ AT_cf_audited_transfer, // Clang-specific.
AT_cf_consumed, // Clang-specific.
AT_cf_returns_autoreleased, // Clang-specific.
AT_cf_returns_not_retained, // Clang-specific.
AT_cf_returns_retained, // Clang-specific.
+ AT_cf_unknown_transfer, // Clang-specific.
AT_cleanup,
AT_common,
AT_const,
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Sep 30 00:12:12 2011
@@ -5403,6 +5403,11 @@
/// FreeVisContext - Deallocate and null out VisContext.
void FreeVisContext();
+ /// AddCFAuditedAttribute - Check whether we're currently within
+ /// '#pragma clang arc_cf_code_audited' and, if so, consider adding
+ /// the appropriate attribute.
+ void AddCFAuditedAttribute(Decl *D);
+
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E);
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T);
Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Sep 30 00:12:12 2011
@@ -1217,6 +1217,15 @@
return;
}
+ // Complain about attempts to #include files in an audit pragma.
+ if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ Diag(HashLoc, diag::err_pp_include_in_arc_cf_code_audited);
+ Diag(PragmaARCCFCodeAuditedLoc, diag::note_pragma_entered_here);
+
+ // Immediately leave the pragma.
+ PragmaARCCFCodeAuditedLoc = SourceLocation();
+ }
+
// Search include directories.
const DirectoryLookup *CurDir;
llvm::SmallString<1024> SearchPath;
Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Fri Sep 30 00:12:12 2011
@@ -216,6 +216,14 @@
}
}
+ // Complain about reaching an EOF within arc_cf_code_audited.
+ if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ Diag(PragmaARCCFCodeAuditedLoc, diag::err_pp_eof_in_arc_cf_code_audited);
+
+ // Recover by leaving immediately.
+ PragmaARCCFCodeAuditedLoc = SourceLocation();
+ }
+
// If this is a #include'd file, pop it off the include stack and continue
// lexing the #includer file.
if (!IncludeMacroStack.empty()) {
Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Fri Sep 30 00:12:12 2011
@@ -1005,6 +1005,60 @@
}
};
+/// PragmaARCCFCodeAuditedHandler -
+/// #pragma clang arc_cf_code_audited begin/end
+struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
+ PragmaARCCFCodeAuditedHandler() : PragmaHandler("arc_cf_code_audited") {}
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) {
+ SourceLocation Loc = NameTok.getLocation();
+ bool IsBegin;
+
+ Token Tok;
+
+ // Lex the 'begin' or 'end'.
+ PP.LexUnexpandedToken(Tok);
+ const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo();
+ if (BeginEnd && BeginEnd->isStr("begin")) {
+ IsBegin = true;
+ } else if (BeginEnd && BeginEnd->isStr("end")) {
+ IsBegin = false;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pp_arc_cf_code_audited_syntax);
+ return;
+ }
+
+ // Verify that this is followed by EOD.
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // The start location of the active audit.
+ SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedLoc();
+
+ // The start location we want after processing this.
+ SourceLocation NewLoc;
+
+ if (IsBegin) {
+ // Complain about attempts to re-enter an audit.
+ if (BeginLoc.isValid()) {
+ PP.Diag(Loc, diag::err_pp_double_begin_of_arc_cf_code_audited);
+ PP.Diag(BeginLoc, diag::note_pragma_entered_here);
+ }
+ NewLoc = Loc;
+ } else {
+ // Complain about attempts to leave an audit that doesn't exist.
+ if (!BeginLoc.isValid()) {
+ PP.Diag(Loc, diag::err_pp_unmatched_end_of_arc_cf_code_audited);
+ return;
+ }
+ NewLoc = SourceLocation();
+ }
+
+ PP.setPragmaARCCFCodeAuditedLoc(NewLoc);
+ }
+};
+
} // end anonymous namespace
@@ -1028,6 +1082,7 @@
AddPragmaHandler("clang", new PragmaDebugHandler());
AddPragmaHandler("clang", new PragmaDependencyHandler());
AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
+ AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Fri Sep 30 00:12:12 2011
@@ -177,10 +177,12 @@
.Case("ns_returns_autoreleased", AT_ns_returns_autoreleased)
.Case("ns_returns_not_retained", AT_ns_returns_not_retained)
.Case("ns_returns_retained", AT_ns_returns_retained)
+ .Case("cf_audited_transfer", AT_cf_audited_transfer)
.Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+ .Case("cf_unknown_transfer", AT_cf_unknown_transfer)
.Case("ns_consumes_self", AT_ns_consumes_self)
.Case("ns_consumed", AT_ns_consumed)
.Case("objc_ownership", AT_objc_ownership)
Modified: cfe/trunk/lib/Sema/SemaAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAttr.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAttr.cpp Fri Sep 30 00:12:12 2011
@@ -300,6 +300,18 @@
VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
}
+void Sema::AddCFAuditedAttribute(Decl *D) {
+ SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc();
+ if (!Loc.isValid()) return;
+
+ // Don't add a redundant or conflicting attribute.
+ if (D->hasAttr<CFAuditedTransferAttr>() ||
+ D->hasAttr<CFUnknownTransferAttr>())
+ return;
+
+ D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context));
+}
+
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
enum { NoVisibility = (unsigned) -1 };
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Sep 30 00:12:12 2011
@@ -5187,6 +5187,10 @@
if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
AddPushedVisibilityAttribute(NewFD);
+ // If there's a #pragma clang arc_cf_code_audited in scope, consider
+ // marking the function.
+ AddCFAuditedAttribute(NewFD);
+
// If this is a locally-scoped extern C function, update the
// map of such names.
if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=140846&r1=140845&r2=140846&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Sep 30 00:12:12 2011
@@ -3263,6 +3263,41 @@
::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
}
+/// Handle cf_audited_transfer and cf_unknown_transfer.
+static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << A.getRange() << A.getName() << 0 /*function*/;
+ return;
+ }
+
+ bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer);
+
+ // Check whether there's a conflicting attribute already present.
+ Attr *Existing;
+ if (IsAudited) {
+ Existing = D->getAttr<CFUnknownTransferAttr>();
+ } else {
+ Existing = D->getAttr<CFAuditedTransferAttr>();
+ }
+ if (Existing) {
+ S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible)
+ << A.getName()
+ << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer")
+ << A.getRange() << Existing->getRange();
+ return;
+ }
+
+ // All clear; add the attribute.
+ if (IsAudited) {
+ D->addAttr(
+ ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context));
+ } else {
+ D->addAttr(
+ ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context));
+ }
+}
+
static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
const AttributeList &Attr) {
RecordDecl *RD = dyn_cast<RecordDecl>(D);
@@ -3499,6 +3534,10 @@
case AttributeList::AT_ns_bridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
+ case AttributeList::AT_cf_audited_transfer:
+ case AttributeList::AT_cf_unknown_transfer:
+ handleCFTransferAttr(S, D, Attr); break;
+
// Checker-specific.
case AttributeList::AT_cf_consumed:
case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
Added: cfe/trunk/test/Sema/Inputs/pragma-arc-cf-code-audited.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/Inputs/pragma-arc-cf-code-audited.h?rev=140846&view=auto
==============================================================================
--- cfe/trunk/test/Sema/Inputs/pragma-arc-cf-code-audited.h (added)
+++ cfe/trunk/test/Sema/Inputs/pragma-arc-cf-code-audited.h Fri Sep 30 00:12:12 2011
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#pragma clang arc_cf_code_audited begin
Added: cfe/trunk/test/Sema/pragma-arc-cf-code-audited.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pragma-arc-cf-code-audited.c?rev=140846&view=auto
==============================================================================
--- cfe/trunk/test/Sema/pragma-arc-cf-code-audited.c (added)
+++ cfe/trunk/test/Sema/pragma-arc-cf-code-audited.c Fri Sep 30 00:12:12 2011
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma clang arc_cf_code_audited foo // expected-error {{expected 'begin' or 'end'}}
+
+#pragma clang arc_cf_code_audited begin foo // expected-warning {{extra tokens at end of #pragma directive}}
+
+#pragma clang arc_cf_code_audited end
+#pragma clang arc_cf_code_audited end // expected-error {{not currently inside '#pragma clang arc_cf_code_audited'}}
+
+#pragma clang arc_cf_code_audited begin // expected-note {{#pragma entered here}}
+#pragma clang arc_cf_code_audited begin // expected-error {{already inside '#pragma clang arc_cf_code_audited'}} expected-note {{#pragma entered here}}
+
+#include "Inputs/pragma-arc-cf-code-audited.h" // expected-error {{cannot #include files inside '#pragma clang arc_cf_code_audited'}}
+
+// This is actually on the #pragma line in the header.
+// expected-error {{'#pragma clang arc_cf_code_audited' was not ended within this file}}
+
+#pragma clang arc_cf_code_audited begin // expected-error {{'#pragma clang arc_cf_code_audited' was not ended within this file}}
More information about the cfe-commits
mailing list