[cfe-commits] r124217 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/forbid-temporaries.cpp

Jeffrey Yasskin jyasskin at google.com
Tue Jan 25 12:08:13 PST 2011


Author: jyasskin
Date: Tue Jan 25 14:08:12 2011
New Revision: 124217

URL: http://llvm.org/viewvc/llvm-project?rev=124217&view=rev
Log:
Add an attribute to forbid temporary instances of a type.  This allows class
authors to write 

  class __attribute__((forbid_temporaries)) Name { ... };

when they want to force users to name all variables of the type. This protects
people from doing things like creating a scoped_lock that only lives for a
single statement instead of an entire scope.

The warning produced by this attribute can be disabled by
-Wno-forbid-temporaries.

Added:
    cfe/trunk/test/SemaCXX/forbid-temporaries.cpp
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Tue Jan 25 14:08:12 2011
@@ -25,6 +25,7 @@
 <li><a href="#vectors">Vectors and Extended Vectors</a></li>
 <li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
 <li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
+<li><a href="#forbid-temporaries-attribute">Attribute to forbid temporaries of a type</a></li>
 <li><a href="#checking_language_features">Checks for Standard Language Features</a></li>
   <ul>
   <li><a href="#cxx_exceptions">C++ exceptions</a></li>
@@ -341,6 +342,33 @@
 <p>Query for this feature with <tt>__has_feature(enumerator_attributes)</tt>.</p>
 
 <!-- ======================================================================= -->
+<h2 id="forbid-temporaries-attribute">Attribute to forbid temporaries of a type</h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides a <tt>forbid_temporaries</tt> attribute to forbid
+temporaries of a particular type.</p>
+
+<blockquote>
+<pre>class __attribute__((forbid_temporaries)) scoped_lock {
+  ...
+};</pre>
+</blockquote>
+
+<p>This prevents mistakes like</p>
+
+<blockquote>
+<pre>void foo() {
+  scoped_lock(my_mutex);
+  // Forgot the local variable name, so destructor runs here.
+  code_that_needs_lock_held();
+  // User expects destructor to run here.
+};</pre>
+</blockquote>
+
+<p>Query for this feature with <tt>__has_attribute(forbid_temporaries)</tt>.
+Use <tt>-Wno-forbid-temporaries</tt> to disable the resulting warning.</p>
+
+<!-- ======================================================================= -->
 <h2 id="checking_language_features">Checks for Standard Language Features</h2>
 <!-- ======================================================================= -->
 

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Jan 25 14:08:12 2011
@@ -232,6 +232,11 @@
   let Spellings = [];
 }
 
+def ForbidTemporaries : Attr {
+  let Spellings = ["forbid_temporaries"];
+  let Subjects = [CXXRecord];
+}
+
 def Format : InheritableAttr {
   let Spellings = ["format"];
   let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 14:08:12 2011
@@ -856,6 +856,9 @@
   "of type %1 invokes deleted constructor">;
 def err_temp_copy_incomplete : Error<
   "copying a temporary object of incomplete type %0">;
+def warn_temporaries_forbidden : Warning<
+  "must not create temporaries of type %0">,
+  InGroup<DiagGroup<"forbid-temporaries">>;
 
 // C++0x decltype
 def err_cannot_determine_declared_type_of_overloaded_function : Error<

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Tue Jan 25 14:08:12 2011
@@ -104,6 +104,7 @@
     AT_dllimport,
     AT_ext_vector_type,
     AT_fastcall,
+    AT_forbid_temporaries,
     AT_format,
     AT_format_arg,
     AT_global,

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Tue Jan 25 14:08:12 2011
@@ -85,6 +85,7 @@
     .Case("deprecated", AT_deprecated)
     .Case("visibility", AT_visibility)
     .Case("destructor", AT_destructor)
+    .Case("forbid_temporaries", AT_forbid_temporaries)
     .Case("format_arg", AT_format_arg)
     .Case("gnu_inline", AT_gnu_inline)
     .Case("weak_import", AT_weak_import)

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Jan 25 14:08:12 2011
@@ -885,6 +885,24 @@
   d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
 }
 
+static void HandleForbidTemporariesAttr(Decl *d, const AttributeList &Attr,
+                                        Sema &S) {
+  assert(Attr.isInvalid() == false);
+
+  if (Attr.getNumArgs() != 0) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+    return;
+  }
+
+  if (!isa<TypeDecl>(d)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << 9 /*class*/;
+    return;
+  }
+
+  d->addAttr(::new (S.Context) ForbidTemporariesAttr(Attr.getLoc(), S.Context));
+}
+
 static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
@@ -2674,6 +2692,8 @@
   case AttributeList::AT_ext_vector_type:
     HandleExtVectorTypeAttr(scope, D, Attr, S);
     break;
+  case AttributeList::AT_forbid_temporaries:
+    HandleForbidTemporariesAttr(D, Attr, S); break;
   case AttributeList::AT_format:      HandleFormatAttr      (D, Attr, S); break;
   case AttributeList::AT_format_arg:  HandleFormatArgAttr   (D, Attr, S); break;
   case AttributeList::AT_global:      HandleGlobalAttr      (D, Attr, S); break;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124217&r1=124216&r2=124217&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jan 25 14:08:12 2011
@@ -3188,9 +3188,12 @@
     }
   }
 
+  CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+  if (RD->getAttr<ForbidTemporariesAttr>())
+    Diag(E->getExprLoc(), diag::warn_temporaries_forbidden) << E->getType();
+
   // That should be enough to guarantee that this type is complete.
   // If it has a trivial destructor, we can avoid the extra copy.
-  CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
   if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
     return Owned(E);
 

Added: cfe/trunk/test/SemaCXX/forbid-temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/forbid-temporaries.cpp?rev=124217&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/forbid-temporaries.cpp (added)
+++ cfe/trunk/test/SemaCXX/forbid-temporaries.cpp Tue Jan 25 14:08:12 2011
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_attribute(forbid_temporaries)
+#error "Should support forbid_temporaries attribute"
+#endif
+
+class __attribute__((forbid_temporaries)) NotATemporary {
+};
+
+class __attribute__((forbid_temporaries(1))) ShouldntHaveArguments {  // expected-error {{attribute requires 0 argument(s)}}
+};
+
+void bad_function() __attribute__((forbid_temporaries));  // expected-warning {{'forbid_temporaries' attribute only applies to classes}}
+
+int var __attribute__((forbid_temporaries));  // expected-warning {{'forbid_temporaries' attribute only applies to classes}}
+
+void bar(const NotATemporary&);
+
+void foo() {
+  NotATemporary this_is_fine;
+  bar(NotATemporary());  // expected-warning {{must not create temporaries of type 'NotATemporary'}}
+  NotATemporary();   // expected-warning {{must not create temporaries of type 'NotATemporary'}}
+}
+
+
+// Check that the above restrictions work for templates too.
+template<typename T>
+class __attribute__((forbid_temporaries)) NotATemporaryTpl {
+};
+
+template<typename T>
+void bar_tpl(const NotATemporaryTpl<T>&);
+
+void tpl_user() {
+  NotATemporaryTpl<int> this_is_fine;
+  bar_tpl(NotATemporaryTpl<int>());  // expected-warning {{must not create temporaries of type 'NotATemporaryTpl<int>'}}
+  NotATemporaryTpl<int>();   // expected-warning {{must not create temporaries of type 'NotATemporaryTpl<int>'}}
+}
+
+
+// Test that a specialization can override the template's default.
+struct TemporariesOk;
+template<> class NotATemporaryTpl<TemporariesOk> {
+};
+
+void specialization_user() {
+  NotATemporaryTpl<TemporariesOk> this_is_fine;
+  bar_tpl(NotATemporaryTpl<TemporariesOk>());
+  NotATemporaryTpl<TemporariesOk>();
+}





More information about the cfe-commits mailing list