From rjmccall at apple.com Mon Jan 24 01:00:30 2011 From: rjmccall at apple.com (John McCall) Date: Mon, 24 Jan 2011 01:00:30 -0800 Subject: [cfe-commits] r124087 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Sema/AttributeList.h lib/Parse/ParseDeclCXX.cpp lib/Sema/AttributeList.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp test/CXX/dcl.dcl/dcl.attr/dcl.attr.overrid In-Reply-To: <4D3D30AC.1070209@gmail.com> References: <4D3D30AC.1070209@gmail.com> Message-ID: On Jan 23, 2011, at 11:56 PM, Abramo Bagnara wrote: > Il 24/01/2011 02:52, Anders Carlsson ha scritto: >> >> On Jan 23, 2011, at 5:50 PM, Nico Weber wrote: >> >>> Why? Is the plan to reimplement this in some other way? >> >> >> The attributes have been replaced with keywords specified in http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3206.htm >> >> clang already supports the new keywords and allows them as an extension in C++98. > > Syntactic representation apart aren't that properties better stored > using clang attributes (i.e. Attr)? > > This seems appropriate to me both under a conceptual point of view and > both thinking about keyword location preserving issues. I agree; I'm not sure why we had to make these non-Attrs just because they're not actually spelled as attributes anymore. John. From hans at chromium.org Mon Jan 24 03:50:07 2011 From: hans at chromium.org (Hans Wennborg) Date: Mon, 24 Jan 2011 11:50:07 +0000 Subject: [cfe-commits] [Patch] disallow function template partial specialization Message-ID: Hi, The attached patch attempts to fix http://llvm.org/bugs/show_bug.cgi?id=8295 My reasoning is that: 1. For a regular function template declaration, one would never have template arguments 2. The same holds for overloading 3. For a function template explicit specialization ("full specialization"), one would never have template parameters. So, if a function template declaration has both template parameters and template arguments, it must be an attempt at partial specialization. I would be grateful if someone with deeper C++ knowledge could verify that this is correct. Also, does C++0x change any of this? Thanks, Hans -------------- next part -------------- A non-text attachment was scrubbed... Name: func_temp_partial_spec.patch Type: text/x-patch Size: 1926 bytes Desc: not available URL: From dgregor at apple.com Mon Jan 24 07:22:41 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 15:22:41 -0000 Subject: [cfe-commits] r124118 - /cfe/trunk/docs/LanguageExtensions.html Message-ID: <20110124152241.C1D122A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 09:22:41 2011 New Revision: 124118 URL: http://llvm.org/viewvc/llvm-project?rev=124118&view=rev Log: Eliminate the last reference to concepts, from Jean-Daniel Dupas Modified: cfe/trunk/docs/LanguageExtensions.html Modified: cfe/trunk/docs/LanguageExtensions.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=124118&r1=124117&r2=124118&view=diff ============================================================================== --- cfe/trunk/docs/LanguageExtensions.html (original) +++ cfe/trunk/docs/LanguageExtensions.html Mon Jan 24 09:22:41 2011 @@ -35,7 +35,6 @@
  • C++0x attributes
  • C++0x decltype()
  • C++0x deleted functions
  • -
  • C++ TR concepts
  • C++0x lambdas
  • C++0x nullptr
  • C++0x rvalue references
  • From dgregor at apple.com Mon Jan 24 07:37:22 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 07:37:22 -0800 Subject: [cfe-commits] PATCH: Fix one of the GCC feature tests in __config In-Reply-To: References: Message-ID: <565BBEAC-0B3B-4EAC-9B58-9CE644F532F0@apple.com> CC'ing Howard directly, since this is a well-disguised libc++ patch :) - Doug On Jan 22, 2011, at 4:33 PM, Chandler Carruth wrote: > Let me know if this is OK to commit. Without it, using GCC 4.5 to build in non-C++0x mode fails due to these functions being force-inlined. <0001-Test-for-varargs-function-inlining-regardless-of-whe.patch>_______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From hhinnant at apple.com Mon Jan 24 07:45:26 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Mon, 24 Jan 2011 10:45:26 -0500 Subject: [cfe-commits] PATCH: Fix one of the GCC feature tests in __config In-Reply-To: <565BBEAC-0B3B-4EAC-9B58-9CE644F532F0@apple.com> References: <565BBEAC-0B3B-4EAC-9B58-9CE644F532F0@apple.com> Message-ID: <07175D7D-EF6F-4BBC-86B2-30B9D9B9ABEA@apple.com> On Jan 24, 2011, at 10:37 AM, Douglas Gregor wrote: > CC'ing Howard directly, since this is a well-disguised libc++ patch :) Thanks Doug, I had overlooked this. > > - Doug > > On Jan 22, 2011, at 4:33 PM, Chandler Carruth wrote: > >> Let me know if this is OK to commit. Without it, using GCC 4.5 to build in non-C++0x mode fails due to these functions being force-inlined. <0001-Test-for-varargs-function-inlining-regardless-of-whe.patch>_______________________________________________ >> cfe-commits mailing list >> cfe-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > Yes, please commit, thanks. -Howard From Axel.Naumann at cern.ch Mon Jan 24 07:44:00 2011 From: Axel.Naumann at cern.ch (Axel Naumann) Date: Mon, 24 Jan 2011 15:44:00 -0000 Subject: [cfe-commits] r124119 - /cfe/trunk/lib/AST/StmtPrinter.cpp Message-ID: <20110124154400.3235D2A6C12C@llvm.org> Author: axel Date: Mon Jan 24 09:44:00 2011 New Revision: 124119 URL: http://llvm.org/viewvc/llvm-project?rev=124119&view=rev Log: Check whether DependentScopeDeclRefExpr's NestedNameSpecifier exists before accessing it, both for consistency (see StmtPrinter::VisitDeclRefExpr()) and for other use cases of dependent types. Modified: cfe/trunk/lib/AST/StmtPrinter.cpp Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=124119&r1=124118&r2=124119&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Mon Jan 24 09:44:00 2011 @@ -481,7 +481,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { - Node->getQualifier()->print(OS, Policy); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( From dgregor at apple.com Mon Jan 24 07:46:58 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 07:46:58 -0800 Subject: [cfe-commits] Patch improving parse of tuple in 98-mode In-Reply-To: References: Message-ID: <3B401E78-1D6D-41E1-AF58-7518540BEA4C@apple.com> On Jan 23, 2011, at 1:15 AM, Chandler Carruth wrote: > Hello, > > I was trying to see how Clang in -std=c++98 would handle libc++ and ran into some trouble. GCC enables a substantial amount of C++ functionality when inside of system headers in addition to suppressing warnings. Clang however only suppresses warnings and relies on 0x features to be enabled with ExtWarns in 98 mode in order for them to work in system headers. The end result is that while Clang is fine with the variadic templates, it barfs on several other constructs. One is the use of 'vector>'-style closing angle brackets. I've attached a patch, constructed with our fixit rewriter, that makes all of those contain the mandated space. Chris indicated on IRC that this should likely just be avoided in libc++. Yes, this should be avoided in libc++. The change that allows >> instead of > > actually does break some obscure code, so we can't just downgrade the error to a warning. > The other major blocker is that R-value references aren't an extension but are used heavily in libc++. Should these also become an extension, or should we add more robust survival tactics in system headers much as GCC does? Rvalue references will become an ExtWarn they are implemented well enough to be useful. With luck, that'll happen this week. > One more small blocker was the use of default template parameter arguments in function templates. Same question as to how best to proceed. This can be downgraded to an ExtWarn, although we need some better testing to be sure that it actually works, first. - Doug From hhinnant at apple.com Mon Jan 24 08:07:25 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Mon, 24 Jan 2011 16:07:25 -0000 Subject: [cfe-commits] [libcxx] r124120 - in /libcxx/trunk/include: __tuple tuple Message-ID: <20110124160725.701B42A6C12C@llvm.org> Author: hhinnant Date: Mon Jan 24 10:07:25 2011 New Revision: 124120 URL: http://llvm.org/viewvc/llvm-project?rev=124120&view=rev Log: Chandler Carruth changed >> to > > in several places. Modified: libcxx/trunk/include/__tuple libcxx/trunk/include/tuple Modified: libcxx/trunk/include/__tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tuple?rev=124120&r1=124119&r2=124120&view=diff ============================================================================== --- libcxx/trunk/include/__tuple (original) +++ libcxx/trunk/include/__tuple Mon Jan 24 10:07:25 2011 @@ -72,20 +72,20 @@ template struct __tuple_like : public __tuple_like<_Tp> {}; template struct __tuple_like : public __tuple_like<_Tp> {}; -template struct __tuple_like> : true_type {}; +template struct __tuple_like > : true_type {}; template struct __tuple_like > : true_type {}; template struct __tuple_like > : true_type {}; template -typename tuple_element<_Ip, tuple<_Tp...>>::type& +typename tuple_element<_Ip, tuple<_Tp...> >::type& get(tuple<_Tp...>&); template -const typename tuple_element<_Ip, tuple<_Tp...>>::type& +const typename tuple_element<_Ip, tuple<_Tp...> >::type& get(const tuple<_Tp...>&); template -typename tuple_element<_Ip, tuple<_Tp...>>::type&& +typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(tuple<_Tp...>&&); template @@ -143,7 +143,7 @@ template struct __tuple_types {}; template -class _LIBCPP_VISIBLE tuple_element<_Ip, __tuple_types<>> +class _LIBCPP_VISIBLE tuple_element<_Ip, __tuple_types<> > { public: static_assert(_Ip == 0, "tuple_element index out of range"); @@ -151,26 +151,26 @@ }; template -class _LIBCPP_VISIBLE tuple_element<0, __tuple_types<_Hp, _Tp...>> +class _LIBCPP_VISIBLE tuple_element<0, __tuple_types<_Hp, _Tp...> > { public: typedef _Hp type; }; template -class _LIBCPP_VISIBLE tuple_element<_Ip, __tuple_types<_Hp, _Tp...>> +class _LIBCPP_VISIBLE tuple_element<_Ip, __tuple_types<_Hp, _Tp...> > { public: - typedef typename tuple_element<_Ip-1, __tuple_types<_Tp...>>::type type; + typedef typename tuple_element<_Ip-1, __tuple_types<_Tp...> >::type type; }; template -class _LIBCPP_VISIBLE tuple_size<__tuple_types<_Tp...>> +class _LIBCPP_VISIBLE tuple_size<__tuple_types<_Tp...> > : public integral_constant { }; -template struct __tuple_like<__tuple_types<_Tp...>> : true_type {}; +template struct __tuple_like<__tuple_types<_Tp...> > : true_type {}; // __make_tuple_types @@ -212,13 +212,13 @@ struct __tuple_convertible_imp : public false_type {}; template -struct __tuple_convertible_imp, __tuple_types<_Up0, _Up...>> +struct __tuple_convertible_imp, __tuple_types<_Up0, _Up...> > : public integral_constant::value && - __tuple_convertible_imp, __tuple_types<_Up...>>::value> {}; + __tuple_convertible_imp, __tuple_types<_Up...> >::value> {}; template <> -struct __tuple_convertible_imp, __tuple_types<>> +struct __tuple_convertible_imp, __tuple_types<> > : public true_type {}; template ::type>::value, @@ -239,13 +239,13 @@ struct __tuple_assignable_imp : public false_type {}; template -struct __tuple_assignable_imp, __tuple_types<_Up0, _Up...>> +struct __tuple_assignable_imp, __tuple_types<_Up0, _Up...> > : public integral_constant::value && - __tuple_assignable_imp, __tuple_types<_Up...>>::value> {}; + __tuple_assignable_imp, __tuple_types<_Up...> >::value> {}; template <> -struct __tuple_assignable_imp, __tuple_types<>> +struct __tuple_assignable_imp, __tuple_types<> > : public true_type {}; template ::type>::value, Modified: libcxx/trunk/include/tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=124120&r1=124119&r2=124120&view=diff ============================================================================== --- libcxx/trunk/include/tuple (original) +++ libcxx/trunk/include/tuple Mon Jan 24 10:07:25 2011 @@ -120,7 +120,7 @@ // tuple_size template -class _LIBCPP_VISIBLE tuple_size> +class _LIBCPP_VISIBLE tuple_size > : public integral_constant { }; @@ -128,10 +128,10 @@ // tuple_element template -class _LIBCPP_VISIBLE tuple_element<_Ip, tuple<_Tp...>> +class _LIBCPP_VISIBLE tuple_element<_Ip, tuple<_Tp...> > { public: - typedef typename tuple_element<_Ip, __tuple_types<_Tp...>>::type type; + typedef typename tuple_element<_Ip, __tuple_types<_Tp...> >::type type; }; // __tuple_leaf @@ -373,7 +373,7 @@ template >::value + __tuple_convertible<_Tuple, tuple<_Tp...> >::value >::type > _LIBCPP_INLINE_VISIBILITY @@ -385,7 +385,7 @@ template >::value + __tuple_convertible<_Tuple, tuple<_Tp...> >::value >::type > _LIBCPP_INLINE_VISIBILITY @@ -400,7 +400,7 @@ _LIBCPP_INLINE_VISIBILITY typename enable_if < - __tuple_assignable<_Tuple, tuple<_Tp...>>::value, + __tuple_assignable<_Tuple, tuple<_Tp...> >::value, __tuple_impl& >::type operator=(_Tuple&& __t) @@ -425,11 +425,11 @@ base base_; template friend - typename tuple_element<_Jp, tuple<_Up...>>::type& get(tuple<_Up...>&); + typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&); template friend - const typename tuple_element<_Jp, tuple<_Up...>>::type& get(const tuple<_Up...>&); + const typename tuple_element<_Jp, tuple<_Up...> >::type& get(const tuple<_Up...>&); template friend - typename tuple_element<_Jp, tuple<_Up...>>::type&& get(tuple<_Up...>&&); + typename tuple_element<_Jp, tuple<_Up...> >::type&& get(tuple<_Up...>&&); public: _LIBCPP_INLINE_VISIBILITY @@ -567,28 +567,28 @@ template inline _LIBCPP_INLINE_VISIBILITY -typename tuple_element<_Ip, tuple<_Tp...>>::type& +typename tuple_element<_Ip, tuple<_Tp...> >::type& get(tuple<_Tp...>& __t) { - typedef typename tuple_element<_Ip, tuple<_Tp...>>::type type; + typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; return static_cast<__tuple_leaf<_Ip, type>&>(__t.base_).get(); } template inline _LIBCPP_INLINE_VISIBILITY -const typename tuple_element<_Ip, tuple<_Tp...>>::type& +const typename tuple_element<_Ip, tuple<_Tp...> >::type& get(const tuple<_Tp...>& __t) { - typedef typename tuple_element<_Ip, tuple<_Tp...>>::type type; + typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; return static_cast&>(__t.base_).get(); } template inline _LIBCPP_INLINE_VISIBILITY -typename tuple_element<_Ip, tuple<_Tp...>>::type&& +typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(tuple<_Tp...>&& __t) { - typedef typename tuple_element<_Ip, tuple<_Tp...>>::type type; + typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; return static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get(); } @@ -626,7 +626,7 @@ }; template -struct ___make_tuple_return> +struct ___make_tuple_return > { typedef _Tp& type; }; @@ -751,7 +751,7 @@ template struct __tuple_cat_type; template -struct __tuple_cat_type, __tuple_types<_Utypes...>> +struct __tuple_cat_type, __tuple_types<_Utypes...> > { typedef tuple<_Ttypes..., _Utypes...> type; }; @@ -841,7 +841,7 @@ struct __tuple_cat; template -struct __tuple_cat, __tuple_indices<_I0...>, __tuple_indices<_J0...>> +struct __tuple_cat, __tuple_indices<_I0...>, __tuple_indices<_J0...> > { template _LIBCPP_INLINE_VISIBILITY From hhinnant at apple.com Mon Jan 24 08:11:46 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Mon, 24 Jan 2011 11:11:46 -0500 Subject: [cfe-commits] Patch improving parse of tuple in 98-mode In-Reply-To: References: Message-ID: On Jan 23, 2011, at 4:15 AM, Chandler Carruth wrote: > Hello, > > I was trying to see how Clang in -std=c++98 would handle libc++ and ran into some trouble. GCC enables a substantial amount of C++ functionality when inside of system headers in addition to suppressing warnings. Clang however only suppresses warnings and relies on 0x features to be enabled with ExtWarns in 98 mode in order for them to work in system headers. The end result is that while Clang is fine with the variadic templates, it barfs on several other constructs. One is the use of 'vector>'-style closing angle brackets. I've attached a patch, constructed with our fixit rewriter, that makes all of those contain the mandated space. Chris indicated on IRC that this should likely just be avoided in libc++. This patch included changes to test/lit.cfg which had conflicts. I've committed the changes to __tuple and tuple, thanks. -Howard > > The other major blocker is that R-value references aren't an extension but are used heavily in libc++. Should these also become an extension, or should we add more robust survival tactics in system headers much as GCC does? > > One more small blocker was the use of default template parameter arguments in function templates. Same question as to how best to proceed. > > Thanks, > -Chandler > From dgregor at apple.com Mon Jan 24 08:14:37 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 16:14:37 -0000 Subject: [cfe-commits] r124121 - in /cfe/trunk: lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp test/SemaCXX/conditional-expr.cpp test/SemaCXX/decl-init-ref.cpp Message-ID: <20110124161437.6CB0B2A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 10:14:37 2011 New Revision: 124121 URL: http://llvm.org/viewvc/llvm-project?rev=124121&view=rev Log: Re-instate r123977/r123978, my updates of the reference-binding implementation used by overload resolution to support rvalue references. The original commits caused PR9026 and some hard-to-reproduce self-host breakage. The only (crucial!) difference between this commit and the previous commits is that we now properly check the SuppressUserConversions flag before attempting to perform a second user-defined conversion in reference binding, breaking the infinite recursion chain of user-defined conversions. Rvalue references should be working a bit better now. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp cfe/trunk/test/SemaCXX/conditional-expr.cpp cfe/trunk/test/SemaCXX/decl-init-ref.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124121&r1=124120&r2=124121&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jan 24 10:14:37 2011 @@ -2798,10 +2798,6 @@ CXXRecordDecl *T2RecordDecl = dyn_cast(T2->getAs()->getDecl()); - QualType ToType - = AllowRvalues? DeclType->getAs()->getPointeeType() - : DeclType; - OverloadCandidateSet CandidateSet(DeclLoc); const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); @@ -2852,10 +2848,10 @@ if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, ToType, CandidateSet); + Init, DeclType, CandidateSet); else S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - ToType, CandidateSet); + DeclType, CandidateSet); } OverloadCandidateSet::iterator Best; @@ -2944,9 +2940,7 @@ // of type "cv2 T2" as follows: // -- If reference is an lvalue reference and the initializer expression - // The next bullet point (T1 is a function) is pretty much equivalent to this - // one, so it's handled here. - if (!isRValRef || T1->isFunctionType()) { + if (!isRValRef) { // -- is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // @@ -3001,8 +2995,7 @@ // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference - // shall be an rvalue reference and the initializer expression shall be - // an rvalue or have a function type. + // shall be an rvalue reference. // // We actually handle one oddity of C++ [over.ics.ref] at this // point, which is that, due to p2 (which short-circuits reference @@ -3016,73 +3009,62 @@ if (!isRValRef && !T1.isConstQualified()) return ICS; - // -- If T1 is a function type, then - // -- if T2 is the same type as T1, the reference is bound to the - // initializer expression lvalue; - // -- if T2 is a class type and the initializer expression can be - // implicitly converted to an lvalue of type T1 [...], the - // reference is bound to the function lvalue that is the result - // of the conversion; - // This is the same as for the lvalue case above, so it was handled there. - // -- otherwise, the program is ill-formed. - // This is the one difference to the lvalue case. - if (T1->isFunctionType()) - return ICS; - - // -- Otherwise, if T2 is a class type and - // -- the initializer expression is an rvalue and "cv1 T1" - // is reference-compatible with "cv2 T2," or - // - // -- T1 is not reference-related to T2 and the initializer - // expression can be implicitly converted to an rvalue - // of type "cv3 T3" (this conversion is selected by - // enumerating the applicable conversion functions - // (13.3.1.6) and choosing the best one through overload - // resolution (13.3)), - // - // then the reference is bound to the initializer - // expression rvalue in the first case and to the object - // that is the result of the conversion in the second case - // (or, in either case, to the appropriate base class - // subobject of the object). - if (T2->isRecordType()) { - // First case: "cv1 T1" is reference-compatible with "cv2 T2". This is a - // direct binding in C++0x but not in C++03. - if (InitCategory.isRValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base - : ObjCConversion? ICK_Compatible_Conversion - : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; - ICS.Standard.RRefBinding = isRValRef; - ICS.Standard.CopyConstructor = 0; - return ICS; - } - - // Second case: not reference-related. - if (RefRelationship == Sema::Ref_Incompatible && - !S.RequireCompleteType(DeclLoc, T2, 0) && - FindConversionForRefInit(S, ICS, DeclType, DeclLoc, - Init, T2, /*AllowRvalues=*/true, - AllowExplicit)) { - // In the second case, if the reference is an rvalue reference - // and the second standard conversion sequence of the - // user-defined conversion sequence includes an lvalue-to-rvalue - // conversion, the program is ill-formed. - if (ICS.isUserDefined() && isRValRef && - ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue) - ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); + // -- If the initializer expression + // + // -- is an xvalue, class prvalue, array prvalue or function + // lvalue and "cv1T1" is reference-compatible with "cv2 T2", or + if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && + (InitCategory.isXValue() || + (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || + (InitCategory.isLValue() && T2->isFunctionType()))) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base + : ObjCConversion? ICK_Compatible_Conversion + : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + // In C++0x, this is always a direct binding. In C++98/03, it's a direct + // binding unless we're binding to a class prvalue. + // Note: Although xvalues wouldn't normally show up in C++98/03 code, we + // allow the use of rvalue references in C++98/03 for the benefit of + // standard library implementors; therefore, we need the xvalue check here. + ICS.Standard.DirectBinding = + S.getLangOptions().CPlusPlus0x || + (InitCategory.isPRValue() && !T2->isRecordType()); + ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.CopyConstructor = 0; + return ICS; + } + + // -- has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to + // an xvalue, class prvalue, or function lvalue of type + // "cv3 T3", where "cv1 T1" is reference-compatible with + // "cv3 T3", + // + // then the reference is bound to the value of the initializer + // expression in the first case and to the result of the conversion + // in the second case (or, in either case, to an appropriate base + // class subobject). + if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible && + T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && + FindConversionForRefInit(S, ICS, DeclType, DeclLoc, + Init, T2, /*AllowRvalues=*/true, + AllowExplicit)) { + // In the second case, if the reference is an rvalue reference + // and the second standard conversion sequence of the + // user-defined conversion sequence includes an lvalue-to-rvalue + // conversion, the program is ill-formed. + if (ICS.isUserDefined() && isRValRef && + ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue) + ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); - return ICS; - } + return ICS; } // -- Otherwise, a temporary of type "cv1 T1" is created and Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124121&r1=124120&r2=124121&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan 24 10:14:37 2011 @@ -2470,6 +2470,7 @@ TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); unsigned ArgIdx = 0; + LocalInstantiationScope InstScope(*this, true); while (Param != ParamEnd) { if (ArgIdx > NumArgs && PartialTemplateArgs) break; Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp?rev=124121&r1=124120&r2=124121&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp (original) +++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp Mon Jan 24 10:14:37 2011 @@ -17,7 +17,7 @@ template struct ConvertsTo { - operator T(); // expected-note 2{{candidate function}} + operator T(); // expected-note 4{{candidate function}} }; void test_rvalue_refs() { @@ -130,3 +130,35 @@ double&& rrd3 = i; } +namespace argument_passing { + void base_rvalue_ref(Base&&); + void int_rvalue_ref(int&&); // expected-note 2{{passing argument to parameter here}} + void array_rvalue_ref(int (&&)[5]); + void function_rvalue_ref(int (&&)(int)); + + void test() { + base_rvalue_ref(xvalue()); + base_rvalue_ref(xvalue()); + int_rvalue_ref(xvalue()); + + base_rvalue_ref(prvalue()); + base_rvalue_ref(prvalue()); + + array_rvalue_ref(HasArray().array); + + function_rvalue_ref(f); + + base_rvalue_ref(ConvertsTo()); + base_rvalue_ref(ConvertsTo()); + int_rvalue_ref(ConvertsTo()); + + base_rvalue_ref(ConvertsTo()); + base_rvalue_ref(ConvertsTo()); + + function_rvalue_ref(ConvertsTo()); + + int_rvalue_ref(ConvertsTo()); // expected-error{{no viable conversion from 'ConvertsTo' to 'int'}} + int_rvalue_ref(ConvertsTo()); // expected-error{{no viable conversion from 'ConvertsTo' to 'int'}} + } + +} Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=124121&r1=124120&r2=124121&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original) +++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Mon Jan 24 10:14:37 2011 @@ -7,7 +7,10 @@ struct ToBool { explicit operator bool(); }; struct B; -struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} +struct A { + A(); + A(const B&); // expected-note 2 {{candidate constructor}} +}; struct B { operator A() const; }; // expected-note 2 {{candidate function}} struct I { operator int(); }; struct J { operator I(); }; Modified: cfe/trunk/test/SemaCXX/decl-init-ref.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-init-ref.cpp?rev=124121&r1=124120&r2=124121&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/decl-init-ref.cpp (original) +++ cfe/trunk/test/SemaCXX/decl-init-ref.cpp Mon Jan 24 10:14:37 2011 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s -struct A {}; // expected-note {{candidate is the implicit copy constructor}} +struct A {}; struct BASE { operator A(); // expected-note {{candidate function}} From andersca at mac.com Mon Jan 24 08:26:15 2011 From: andersca at mac.com (Anders Carlsson) Date: Mon, 24 Jan 2011 16:26:15 -0000 Subject: [cfe-commits] r124122 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclCXX.h include/clang/Basic/Attr.td lib/AST/DeclCXX.cpp lib/CodeGen/CGExprCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp lib/Serialization/ASTWriterDecl.cpp Message-ID: <20110124162616.04AAD2A6C12C@llvm.org> Author: andersca Date: Mon Jan 24 10:26:15 2011 New Revision: 124122 URL: http://llvm.org/viewvc/llvm-project?rev=124122&view=rev Log: Use attributes for all the override control specifiers. Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/Basic/Attr.td cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Jan 24 10:26:15 2011 @@ -1195,8 +1195,6 @@ bool IsDeleted : 1; bool IsTrivial : 1; // sunk from CXXMethodDecl bool HasImplicitReturnZero : 1; - bool IsMarkedOverride : 1; // sunk from CXXMethodDecl - bool IsMarkedFinal : 1; // sunk from CXXMethodDecl /// \brief End part of this FunctionDecl's source range. /// @@ -1276,8 +1274,7 @@ IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), - HasImplicitReturnZero(false), IsMarkedOverride(false), - IsMarkedFinal(false), EndRangeLoc(NameInfo.getEndLoc()), + HasImplicitReturnZero(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1390,16 +1387,6 @@ bool hasImplicitReturnZero() const { return HasImplicitReturnZero; } void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } - /// \brief Whether this member function is marked with the 'override' keyword, - /// C++0x [class.mem]p8. - bool isMarkedOverride() const { return IsMarkedOverride; } - void setIsMarkedOverride(bool IMO) { IsMarkedOverride = IMO; } - - /// \brief Whether this member function is marked with the 'final' keyword, - /// C++0x [class.mem]p8. - bool isMarkedFinal() const { return IsMarkedFinal; } - void setIsMarkedFinal(bool IMF) { IsMarkedFinal = IMF; } - /// \brief Whether this function has a prototype, either because one /// was explicitly written or because it was "inherited" by merging /// a declaration without a prototype with a declaration that has a Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Jan 24 10:26:15 2011 @@ -356,12 +356,6 @@ /// \brief Whether we have already declared a destructor within the class. bool DeclaredDestructor : 1; - /// \brief Whether this class is marked 'final'. - bool IsMarkedFinal : 1; - - /// \brief Whether this class is marked 'explicit'. - bool IsMarkedExplicit : 1; - /// NumBases - The number of base class specifiers in Bases. unsigned NumBases; @@ -665,18 +659,6 @@ /// This value is used for lazy creation of destructors. bool hasDeclaredDestructor() const { return data().DeclaredDestructor; } - /// \brief Whether this class is marked 'final'. - bool isMarkedFinal() const { return data().IsMarkedFinal; } - - /// \brief Mark this class as 'final'. - void setIsMarkedFinal(bool IMF) { data().IsMarkedFinal = IMF; } - - /// \brief Whether this class is marked 'explicit'. - bool isMarkedExplicit() const { return data().IsMarkedExplicit; } - - /// \brief Mark this class as 'explicit'. - void setIsMarkedExplicit(bool IME) { data().IsMarkedExplicit = IME; } - /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. UnresolvedSetImpl *getConversionFunctions() { Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Mon Jan 24 10:26:15 2011 @@ -213,10 +213,18 @@ let Spellings = ["dllimport"]; } +def Explicit : InheritableAttr { + let Spellings = []; +} + def FastCall : InheritableAttr { let Spellings = ["fastcall", "__fastcall"]; } +def Final : InheritableAttr { + let Spellings = []; +} + def Format : InheritableAttr { let Spellings = ["format"]; let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">, @@ -336,6 +344,10 @@ let Spellings = ["overloadable"]; } +def Override : InheritableAttr { + let Spellings = []; +} + def Ownership : InheritableAttr { let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"]; let Args = [EnumArgument<"OwnKind", "OwnershipKind", Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Jan 24 10:26:15 2011 @@ -36,9 +36,8 @@ HasTrivialDestructor(true), ComputedVisibleConversions(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), DeclaredDestructor(false), - IsMarkedFinal(false), IsMarkedExplicit(false), - NumBases(0), NumVBases(0), Bases(), VBases(), - Definition(D), FirstFriend(0) { + NumBases(0), NumVBases(0), Bases(), VBases(), + Definition(D), FirstFriend(0) { } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Mon Jan 24 10:26:15 2011 @@ -65,12 +65,12 @@ // If the member function is marked 'final', we know that it can't be // overridden and can therefore devirtualize it. - if (MD->isMarkedFinal()) + if (MD->hasAttr()) return true; // Similarly, if the class itself is marked 'final' it can't be overridden // and we can therefore devirtualize the member function call. - if (MD->getParent()->isMarkedFinal()) + if (MD->getParent()->hasAttr()) return true; if (const DeclRefExpr *DRE = dyn_cast(Base)) { Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 24 10:26:15 2011 @@ -6386,8 +6386,10 @@ if (!Record->getIdentifier()) return; - Record->setIsMarkedFinal(CVS.isFinalSpecified()); - Record->setIsMarkedExplicit(CVS.isExplicitSpecified()); + if (CVS.isFinalSpecified()) + Record->addAttr(new (Context) FinalAttr(CVS.getFinalLoc(), Context)); + if (CVS.isExplicitSpecified()) + Record->addAttr(new (Context) ExplicitAttr(CVS.getExplicitLoc(), Context)); // C++ [class]p2: // [...] The class-name is also inserted into the scope of the Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan 24 10:26:15 2011 @@ -525,7 +525,7 @@ // If a class is marked with the class-virt-specifier final and it appears // as a base-type-specifier in a base-clause (10 class.derived), the program // is ill-formed. - if (CXXBaseDecl->isMarkedFinal()) { + if (CXXBaseDecl->hasAttr()) { Diag(BaseLoc, diag::err_class_marked_final_used_as_base) << CXXBaseDecl->getDeclName(); Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) @@ -871,7 +871,7 @@ // the program is ill-formed. bool HasOverriddenMethods = MD->begin_overridden_methods() != MD->end_overridden_methods(); - if (MD->isMarkedOverride() && !HasOverriddenMethods) { + if (MD->hasAttr() && !HasOverriddenMethods) { Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding) << MD->getDeclName(); @@ -883,8 +883,8 @@ // if a virtual member function that is neither implicitly-declared nor a // destructor overrides a member function of a base class and it is not // marked with the virt-specifier override, the program is ill-formed. - if (MD->getParent()->isMarkedExplicit() && !isa(MD) && - HasOverriddenMethods && !MD->isMarkedOverride()) { + if (MD->getParent()->hasAttr() && !isa(MD) && + HasOverriddenMethods && !MD->hasAttr()) { llvm::SmallVector OverriddenMethods(MD->begin_overridden_methods(), MD->end_overridden_methods()); @@ -904,7 +904,7 @@ /// C++0x [class.virtual]p3. bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - if (!Old->isMarkedFinal()) + if (!Old->hasAttr()) return false; Diag(New->getLocation(), diag::err_final_function_overridden) @@ -1057,7 +1057,7 @@ diag::override_keyword_only_allowed_on_virtual_member_functions) << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc()); } else - MD->setIsMarkedOverride(true); + MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); } if (VS.isFinalSpecified()) { CXXMethodDecl *MD = dyn_cast(Member); @@ -1066,7 +1066,7 @@ diag::override_keyword_only_allowed_on_virtual_member_functions) << "final" << FixItHint::CreateRemoval(VS.getFinalLoc()); } else - MD->setIsMarkedFinal(true); + MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); } CheckOverrideControl(Member); Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Jan 24 10:26:15 2011 @@ -1640,9 +1640,6 @@ Instantiation->setTagKind(Pattern->getTagKind()); - Instantiation->setIsMarkedFinal(Pattern->isMarkedFinal()); - Instantiation->setIsMarkedExplicit(Pattern->isMarkedExplicit()); - // Do substitution on the base class specifiers. if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) Invalid = true; Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jan 24 10:26:15 2011 @@ -1389,8 +1389,6 @@ if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); - Method->setIsMarkedOverride(D->isMarkedOverride()); - Method->setIsMarkedFinal(D->isMarkedFinal()); Method->setAccess(D->getAccess()); SemaRef.CheckOverrideControl(Method); Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Jan 24 10:26:15 2011 @@ -395,9 +395,6 @@ FD->IsDeleted = Record[Idx++]; FD->IsTrivial = Record[Idx++]; FD->HasImplicitReturnZero = Record[Idx++]; - FD->IsMarkedOverride = Record[Idx++]; - FD->IsMarkedFinal = Record[Idx++]; - FD->EndRangeLoc = ReadSourceLocation(Record, Idx); // Read in the parameters. @@ -800,8 +797,6 @@ Data.DeclaredCopyConstructor = Record[Idx++]; Data.DeclaredCopyAssignment = Record[Idx++]; Data.DeclaredDestructor = Record[Idx++]; - Data.IsMarkedFinal = Record[Idx++]; - Data.IsMarkedExplicit = Record[Idx++]; Data.NumBases = Record[Idx++]; if (Data.NumBases) Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Jan 24 10:26:15 2011 @@ -3394,8 +3394,6 @@ Record.push_back(Data.DeclaredCopyConstructor); Record.push_back(Data.DeclaredCopyAssignment); Record.push_back(Data.DeclaredDestructor); - Record.push_back(Data.IsMarkedFinal); - Record.push_back(Data.IsMarkedExplicit); Record.push_back(Data.NumBases); if (Data.NumBases > 0) Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=124122&r1=124121&r2=124122&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Jan 24 10:26:15 2011 @@ -312,8 +312,6 @@ Record.push_back(D->isDeleted()); Record.push_back(D->isTrivial()); Record.push_back(D->hasImplicitReturnZero()); - Record.push_back(D->isMarkedOverride()); - Record.push_back(D->isMarkedFinal()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->param_size()); From andersca at mac.com Mon Jan 24 08:30:19 2011 From: andersca at mac.com (Anders Carlsson) Date: Mon, 24 Jan 2011 08:30:19 -0800 Subject: [cfe-commits] r124087 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Sema/AttributeList.h lib/Parse/ParseDeclCXX.cpp lib/Sema/AttributeList.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp test/CXX/dcl.dcl/dcl.attr/dcl.attr.overrid In-Reply-To: References: <4D3D30AC.1070209@gmail.com> Message-ID: <4359BB01-9797-4E3C-A3F3-5786FC7AE6DF@mac.com> On Jan 24, 2011, at 1:00 AM, John McCall wrote: > On Jan 23, 2011, at 11:56 PM, Abramo Bagnara wrote: >> Il 24/01/2011 02:52, Anders Carlsson ha scritto: >>> >>> On Jan 23, 2011, at 5:50 PM, Nico Weber wrote: >>> >>>> Why? Is the plan to reimplement this in some other way? >>> >>> >>> The attributes have been replaced with keywords specified in http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3206.htm >>> >>> clang already supports the new keywords and allows them as an extension in C++98. >> >> Syntactic representation apart aren't that properties better stored >> using clang attributes (i.e. Attr)? >> >> This seems appropriate to me both under a conceptual point of view and >> both thinking about keyword location preserving issues. > > I agree; I'm not sure why we had to make these non-Attrs just because they're not actually spelled as attributes anymore. > You're absolutely right. Fixed in 124122. - Anders From rafael.espindola at gmail.com Mon Jan 24 08:40:01 2011 From: rafael.espindola at gmail.com (=?ISO-8859-1?Q?Rafael_=C1vila_de_Esp=EDndola?=) Date: Mon, 24 Jan 2011 11:40:01 -0500 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/CodeGenCXX/virt-template-vtable.cpp test/CodeGenCXX/visibility.cpp test/CodeGenCXX/vtable-key-function.cpp test/CodeGenCXX/vtable-linkage.cpp test/CodeGenCXX/vtt-layout.cpp test/CodeGenObjCXX/rtti.mm test/SemaCXX/typeid-ref.cpp In-Reply-To: <20110124004619.DA8DF2A6C12C@llvm.org> References: <20110124004619.DA8DF2A6C12C@llvm.org> Message-ID: <4D3DAB61.8040508@gmail.com> On 11-01-23 7:46 PM, Anders Carlsson wrote: > Author: andersca > Date: Sun Jan 23 18:46:19 2011 > New Revision: 124089 > > URL: http://llvm.org/viewvc/llvm-project?rev=124089&view=rev > Log: > Mark VTables and RTTI data linkonce_odr instead of weak_odr, with the exception of explicit template instantiations, which have to be weak_odr. I remember asking this before, but I cannot remember the answer. Is it valid for a program to have multiple explicit template instantiations with the same arguments? If not, we could use strong definitions for those vtables, no? Cheers, Rafael From Renato.Golin at arm.com Mon Jan 24 09:08:23 2011 From: Renato.Golin at arm.com (Renato Golin) Date: Mon, 24 Jan 2011 17:08:23 +0000 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DAB61.8040508@gmail.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> Message-ID: <4D3DB207.1050606@arm.com> On 01/24/11 16:40, Rafael Ávila de Espíndola wrote: > I remember asking this before, but I cannot remember the answer. Is it > valid for a program to have multiple explicit template instantiations > with the same arguments? Nope: paragraph 14.7.5 > If not, we could use strong definitions for > those vtables, no? I think you can't use strong symbol definitions for any template code, as the linker may find exactly the same symbol in another object, and two identical non-weak symbols generates an error. So it has to be either weak or ODR. But I could be wrong... cheers, --renato -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. From rdivacky at freebsd.org Mon Jan 24 09:10:59 2011 From: rdivacky at freebsd.org (Roman Divacky) Date: Mon, 24 Jan 2011 18:10:59 +0100 Subject: [cfe-commits] [PATCH]: GPROF implementation Message-ID: <20110124171059.GA12377@freebsd.org> Hi, The attached patch implemented GPROF (ie. -pg) support in clang. It introduces GPROFInstrument CodeGenOption and sets it when -pg is specified. The FreeBSD ::Link() method was adjusted to link the correct libraries when -pg is specified. Finally, CodeGen was modified to emit calls to "mcount" (the actual name differs between arch/OS tuples) at the start of the function body. This patch is quite FreeBSD specific (the driver modification and the mcount name selection) but adding other OSes should be trivial once this is commited. Please review! roman -------------- next part -------------- A non-text attachment was scrubbed... Name: clang-gprof.patch Type: text/x-diff Size: 8245 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 196 bytes Desc: not available URL: From dgregor at apple.com Mon Jan 24 09:17:32 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 09:17:32 -0800 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DB207.1050606@arm.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> Message-ID: <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> On Jan 24, 2011, at 9:08 AM, Renato Golin wrote: > On 01/24/11 16:40, Rafael Ávila de Espíndola wrote: >> I remember asking this before, but I cannot remember the answer. Is it >> valid for a program to have multiple explicit template instantiations >> with the same arguments? > > Nope: paragraph 14.7.5 You are technically correct, but the prohibition of multiple explicit template instantiations is almost useless in practice, because there still may be any number of implicit template instantiations with the same arguments. - Doug From Renato.Golin at arm.com Mon Jan 24 09:24:10 2011 From: Renato.Golin at arm.com (Renato Golin) Date: Mon, 24 Jan 2011 17:24:10 +0000 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> Message-ID: <4D3DB5BA.8070708@arm.com> On 01/24/11 17:17, Douglas Gregor wrote: > You are technically correct, but the prohibition of multiple explicit > template instantiations is almost useless in practice, because there > still may be any number of implicit template instantiations with the > same arguments. But by priority rules, explicit instantiation takes precedence over implicit ones. If you have multiple implicit and one explicit, you'll always take the explicit one. However, if you have multiple implicit (and not any explicit) or multiple explicit ones, that's an ill-formed program. cheers, --renato -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. From rafael.espindola at gmail.com Mon Jan 24 09:24:24 2011 From: rafael.espindola at gmail.com (=?ISO-8859-1?Q?Rafael_=C1vila_de_Esp=EDndola?=) Date: Mon, 24 Jan 2011 12:24:24 -0500 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> Message-ID: <4D3DB5C8.9070603@gmail.com> On 11-01-24 12:17 PM, Douglas Gregor wrote: > > On Jan 24, 2011, at 9:08 AM, Renato Golin wrote: > >> On 01/24/11 16:40, Rafael Ávila de Espíndola wrote: >>> I remember asking this before, but I cannot remember the answer. Is it >>> valid for a program to have multiple explicit template instantiations >>> with the same arguments? >> >> Nope: paragraph 14.7.5 > > You are technically correct, but the prohibition of multiple explicit template instantiations is almost useless in practice, because there still may be any number of implicit template instantiations with the same arguments. Ah, so it is not legal to have multiple explicit instantiations, but it is not required to always have an explicit instantiation declaration in context? > - Doug Thanks, Rafael From dgregor at apple.com Mon Jan 24 09:25:03 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 17:25:03 -0000 Subject: [cfe-commits] r124123 - /cfe/trunk/lib/AST/StmtPrinter.cpp Message-ID: <20110124172503.BC1D42A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 11:25:03 2011 New Revision: 124123 URL: http://llvm.org/viewvc/llvm-project?rev=124123&view=rev Log: Improve the printing of C++ construction expressions, from Yuri Gribov! Modified: cfe/trunk/lib/AST/StmtPrinter.cpp Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=124123&r1=124122&r2=124123&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Mon Jan 24 11:25:03 2011 @@ -1128,14 +1128,15 @@ } void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { - // FIXME. For now we just print a trivial constructor call expression, - // constructing its first argument object. - if (E->getNumArgs() == 1) { - CXXConstructorDecl *CD = E->getConstructor(); - if (CD->isTrivial()) - PrintExpr(E->getArg(0)); + for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { + if (isa(E->getArg(i))) { + // Don't print any defaulted arguments + break; + } + + if (i) OS << ", "; + PrintExpr(E->getArg(i)); } - // Nothing to print. } void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) { From dgregor at apple.com Mon Jan 24 09:28:19 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 09:28:19 -0800 Subject: [cfe-commits] Small fixes In-Reply-To: References: Message-ID: <0A216463-12B4-4A38-9FE5-3924B4DB229D@apple.com> On Jan 20, 2011, at 9:51 AM, Yuri Gribov wrote: > Hi all, > > 1) I have noticed that constructors are not pretty-printed correctly > (current implementation is basically a stub) e.g. > void f() { > A x(1); > } > will result in > void f() { > A x(); > } > which is of course incorrect. I have attached the patch (which is > basically a copy of VisitCallExpr) which seems to fix it. Could > someone review/submit it? I tried running the tests but they fail > mercilessly both with and without my change (yes, I am on Windows) and > I do not feel like fixing testscripts today. Looks great, thanks! Committed as r124123. > 2) it seems that "Hacking on Clang" is somewhat out-of-date - I have > attached patch for that as well. IIRC, the --param=build_config= setting is only needed for CMake builds. I suggest mentioning this explicitly, so that people using the autoconf builds don't get confused. > 3) A general question - I am not an official developer; should I send > patch suggestions to cfe-dev or to cfe-commits? You've found the right place: cfe-commits. - Doug From dgregor at apple.com Mon Jan 24 09:30:37 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 09:30:37 -0800 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DB5C8.9070603@gmail.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> <4D3DB5C8.9070603@gmail.com> Message-ID: On Jan 24, 2011, at 9:24 AM, Rafael Ávila de Espíndola wrote: > On 11-01-24 12:17 PM, Douglas Gregor wrote: >> >> On Jan 24, 2011, at 9:08 AM, Renato Golin wrote: >> >>> On 01/24/11 16:40, Rafael Ávila de Espíndola wrote: >>>> I remember asking this before, but I cannot remember the answer. Is it >>>> valid for a program to have multiple explicit template instantiations >>>> with the same arguments? >>> >>> Nope: paragraph 14.7.5 >> >> You are technically correct, but the prohibition of multiple explicit template instantiations is almost useless in practice, because there still may be any number of implicit template instantiations with the same arguments. > > Ah, so it is not legal to have multiple explicit instantiations, but it > is not required to always have an explicit instantiation declaration in > context? Correct. Remember that explicit instantiation declarations were not available in C++98/03, so until C++0x (or if one makes use of extern template in GNU C++) there was no way to suppress implicit instantiations. FWIW, I've had a feature request on my plate for a long time to add an attribute "unique_instantiation". The attribute would be applied to the explicit instantiation declaration, and would guarantee that the template would never be instantiated if it isn't under the control of that explicit instantiation declaration. The intent was, of course, to allow us to emit the explicit instantiation definition as a strong external (including vtable, RTTI, virtual member functions, etc.). - Doug From dgregor at apple.com Mon Jan 24 09:33:59 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 09:33:59 -0800 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DB5BA.8070708@arm.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> <4D3DB5BA.8070708@arm.com> Message-ID: On Jan 24, 2011, at 9:24 AM, Renato Golin wrote: > On 01/24/11 17:17, Douglas Gregor wrote: >> You are technically correct, but the prohibition of multiple explicit >> template instantiations is almost useless in practice, because there >> still may be any number of implicit template instantiations with the >> same arguments. > > But by priority rules, explicit instantiation takes precedence over > implicit ones. If you have multiple implicit and one explicit, you'll > always take the explicit one. That depends on the linker. With the Mac OS 10.6 dynamic linker, for example, a strong external symbol in one shared library will not get merged with same-named weak symbols in another shared library. - Doug From tetra2005 at googlemail.com Mon Jan 24 10:00:24 2011 From: tetra2005 at googlemail.com (Yuri Gribov) Date: Mon, 24 Jan 2011 21:00:24 +0300 Subject: [cfe-commits] Small fixes In-Reply-To: <0A216463-12B4-4A38-9FE5-3924B4DB229D@apple.com> References: <0A216463-12B4-4A38-9FE5-3924B4DB229D@apple.com> Message-ID: Great, thanks. > IIRC, the --param=build_config= setting is only needed for CMake builds. > I suggest mentioning this explicitly, so that people using the autoconf builds don't get confused. Here is the updated diff for hacking.html. Best regards, Yuri -------------- next part -------------- A non-text attachment was scrubbed... Name: hacking.html.diff Type: application/octet-stream Size: 475 bytes Desc: not available URL: From dgregor at apple.com Mon Jan 24 10:01:02 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 10:01:02 -0800 Subject: [cfe-commits] [PATCH] Constructor and Destructor mangling, along with improved Calling Convention handling for Windows. In-Reply-To: References: <4D392218.9040405@mymail.mines.edu> Message-ID: The Microsoft mangling changes look good, but please supply a test case that tests the new manglings. The calling-convention changes are going to need a bit more discussion. The main change is this: Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h (revision 123972) +++ include/clang/AST/Type.h (working copy) @@ -2205,11 +2205,12 @@ // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|regparm - // |0 .. 2| 3 |4 .. 6 + // | CC |noreturn|regparm|CC-default + // |0 .. 2| 3 |4 .. 6| 7 enum { CallConvMask = 0x7 }; enum { NoReturnMask = 0x8 }; - enum { RegParmMask = ~(CallConvMask | NoReturnMask), + enum { DefaultCallConvMask = 0x80 }; + enum { RegParmMask = ~(CallConvMask | NoReturnMask | DefaultCallConvMask), RegParmOffset = 4 }; unsigned char Bits; @@ -2232,8 +2233,9 @@ ExtInfo() : Bits(0) {} bool getNoReturn() const { return Bits & NoReturnMask; } - unsigned getRegParm() const { return Bits >> RegParmOffset; } + unsigned getRegParm() const { return (Bits & RegParmMask) >> RegParmOffset; } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } + bool isCCDefault() const { return (getCC() == CC_Default) || (Bits & DefaultCallConvMask); } bool operator==(ExtInfo Other) const { return Bits == Other.Bits; @@ -2257,9 +2259,13 @@ } ExtInfo withCallingConv(CallingConv cc) const { - return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); + return ExtInfo((Bits & ~(CallConvMask|DefaultCallConvMask)) | (unsigned) cc); } - + + ExtInfo withDefaultCallingConv(CallingConv cc) const { + return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc | DefaultCallConvMask); + } + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } which partially separates the notion of "is this the default calling convention"? from the description of the calling convention. However, it's not a complete separation, which I find a bit awkward. I could imagine removing CC_Default entirely, then adding the "the function type was written without an explicit calling convention" bit. When the function type itself is created, we pick the calling convention based on context (?) if it's default. Also, a change like this really needs testing. Here's a fun case: typedef void func_type(int); struct X { func_type f; }; presumably, "f" gets the thiscall calling convention because of its context, but then decltype(X::f) is different from func_type. - Doug On Jan 21, 2011, at 7:06 AM, Ricky Taylor wrote: > Not sure how, but that last message had an old version of the patch. > I've attached the correct version to this message. > > -- Ricky Taylor > > On Fri, Jan 21, 2011 at 11:16 AM, Ricky Taylor wrote: >> On Fri, Jan 21, 2011 at 6:05 AM, Charles Davis wrote: >>> >>> On 1/20/11 10:12 PM, Ricky Taylor wrote: >>>> Hello, >>>> >>>> I've created a patch for clang, that addresses some issues with the >>>> Microsoft ABI: >>>> >>>> - Constructors and Destructors are now mangled correctly >>>> - 'Repeated Namespaces' are mangled correctly >>>> - The correct default calling convention is used for class/struct methods >>>> - __declspec syntax is now used, (and presumably the GCC equivalent). >>>> - Attributes are passed down the chain correctly, (they were not being >>>> copied into the Declarator). >>>> >>>> The patch is attached below, >>> Hi, >>> >>> I wrote the Microsoft C++ Mangler initially. Comments below: >>> >>> Index: include/clang/Sema/DeclSpec.h >>> =================================================================== >>> --- include/clang/Sema/DeclSpec.h (revision 123612) >>> +++ include/clang/Sema/DeclSpec.h (working copy) >>> @@ -1206,7 +1206,7 @@ >>> Declarator(const DeclSpec &ds, TheContext C) >>> : DS(ds), Range(ds.getSourceRange()), Context(C), >>> InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), >>> - GroupingParens(false), AttrList(0), AsmLabel(0), >>> + GroupingParens(false), AttrList(ds.getAttributes().getList()), >>> AsmLabel(0), >>> InlineParamsUsed(false), Extension(false) { >>> } >>> >>> I think there's a reason they weren't being passed down. I'm not sure >>> about Microsoft attributes, but IIRC GNU attributes on the decl-spec >>> belong to the type, not the declarator. Maybe we should pass down only >>> Microsoft (i.e. __declspec) attributes. >>> >>> Also, you used tab characters instead of spaces. Please don't do that. >>> Lots of people use a tab width of 8, so the indentation looks off. >>> >>> Index: lib/AST/ASTContext.cpp >>> =================================================================== >>> --- lib/AST/ASTContext.cpp (revision 123612) >>> +++ lib/AST/ASTContext.cpp (working copy) >>> @@ -885,6 +885,14 @@ >>> return toCharUnitsFromBits(getTypeAlign(T)); >>> } >>> >>> +/// getDefaultCallingConvForDeclarator - Determines the default calling >>> convention >>> +/// for a Declarator before attributes are applied. >>> +CallingConv ASTContext::getDefaultCallingConvForDeclarator(Declarator >>> &D, Scope *S) const >>> +{ >>> + // Pass through to ABI. >>> + return ABI->getDefaultCallingConvForDeclarator(D, S); >>> +} >>> + >>> >>> You could avoid having to add another method to the C++ ABI object by >>> calling the getDefaultMethodCallingConv() method on the ABI object. Then >>> this becomes: >>> >>> CallingConv getDefaultCallingConvForDeclarator(Declarator &D, Scope >>> *S) const { >>> if() >>> return ABI->getDefaultMethodCallingConv(); >>> >>> return CC_C; >>> } >>> >>> >>> Index: lib/AST/CXXABI.h >>> =================================================================== >>> --- lib/AST/CXXABI.h (revision 123612) >>> +++ lib/AST/CXXABI.h (working copy) >>> @@ -21,6 +21,8 @@ >>> >>> class ASTContext; >>> class MemberPointerType; >>> +class Declarator; >>> +class Scope; >>> >>> /// Implements C++ ABI-specific semantic analysis functions. >>> class CXXABI { >>> @@ -30,10 +32,13 @@ >>> /// Returns the size of a member pointer in multiples of the target >>> /// pointer size. >>> virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) >>> const = 0; >>> - >>> + >>> /// Returns the default calling convention for C++ methods. >>> virtual CallingConv getDefaultMethodCallConv() const = 0; >>> >>> + /// Returns the default calling convention for a particular Declarator. >>> + virtual CallingConv getDefaultCallingConvForDeclarator(Declarator &D, >>> Scope *S) const = 0; >>> + >>> >>> You shouldn't have to do this (see above). >>> >>> Index: lib/AST/MicrosoftCXXABI.cpp >>> =================================================================== >>> --- lib/AST/MicrosoftCXXABI.cpp (revision 123612) >>> +++ lib/AST/MicrosoftCXXABI.cpp (working copy) >>> @@ -17,6 +17,8 @@ >>> #include "clang/AST/DeclCXX.h" >>> #include "clang/AST/RecordLayout.h" >>> #include "clang/AST/Type.h" >>> +#include "clang/Sema/DeclSpec.h" >>> +#include "clang/Sema/Scope.h" >>> #include "clang/Basic/TargetInfo.h" >>> >>> using namespace clang; >>> @@ -36,6 +38,13 @@ >>> return CC_C; >>> } >>> >>> + CallingConv getDefaultCallingConvForDeclarator(Declarator &D, Scope >>> *S) const { >>> + if(S && (S->getFlags() & Scope::ClassScope)) >>> + return CC_X86ThisCall; >>> + >>> + return CC_C; >>> + } >>> + >>> >>> You should probably make sure that the declarator doesn't have the >>> static storage class. For static methods, the default calling convention >>> is still __cdecl. (Of course, this is after moving the implementation >>> over to ASTContext.) >>> >>> Index: lib/AST/MicrosoftMangle.cpp >>> =================================================================== >>> --- lib/AST/MicrosoftMangle.cpp (revision 123612) >>> +++ lib/AST/MicrosoftMangle.cpp (working copy) >>> @@ -30,6 +30,7 @@ >>> class MicrosoftCXXNameMangler { >>> MangleContext &Context; >>> llvm::raw_svector_ostream Out; >>> + std::vector Shortcuts; >>> >>> You might consider using a SmallVector here (there can only be 10 >>> replacements anyway). >>> >>> ASTContext &getASTContext() const { return Context.getASTContext(); } >>> >>> @@ -336,11 +337,13 @@ >>> break; >>> >>> case DeclarationName::CXXConstructorName: >>> - assert(false && "Can't mangle constructors yet!"); >>> + // ::= ?0 class-name >>> + Out << "?0"; >>> break; >>> >>> Tabs. >>> >>> case DeclarationName::CXXDestructorName: >>> - assert(false && "Can't mangle destructors yet!"); >>> + // ::= ?1 >>> + Out << "?1"; >>> break; >>> >>> Tabs again. (The second line is okay, though.) >>> >>> case DeclarationName::CXXConversionFunctionName: >>> @@ -382,7 +385,8 @@ >>> if (const BlockDecl *BD = dyn_cast(DC)) { >>> llvm::SmallString<64> Name; >>> Context.mangleBlock(BD, Name); >>> - Out << Name << '@'; >>> + >>> + Out << Name << '@'; >>> return manglePostfix(DC->getParent(), NoFunction); >>> } >>> >>> Please avoid gratuitous whitespace changes. >>> >>> @@ -525,8 +529,34 @@ >>> } >>> >>> void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { >>> - // ::= @ >>> - Out << II->getName() << '@'; >>> + // ::= @ >>> + >>> + llvm::StringRef Name = II->getName(); >>> + >>> + // Microsoft assign the first 10 names to ascii shortcuts >>> + // '0'-'9'. They are then used instead of the name@ syntax. >>> + bool newName = true; >>> + for(size_t i = 0; i < Shortcuts.size(); i++) >>> + { >>> + if(Shortcuts[i].compare(Name) == 0) >>> + { >>> + Out << std::string(1, '0' + i); >>> + newName = false; >>> + break; >>> + } >>> + } >>> + >>> + // If we weren't in the shortcut list, then we will have to >>> + // write the whole name out. >>> + if(newName) >>> + { >>> + Out << Name << '@'; >>> + >>> + if(Shortcuts.size() < 10) >>> + { >>> + Shortcuts.push_back(Name); >>> + } >>> + } >>> } >>> >>> You should probably add a test for this to >>> /test/CodeGenCXX/mangle-ms.cpp. >>> >>> Oh, and tabs again. >>> >>> The whole patch file had mixed line endings (CR-LF and LF). Try to avoid >>> that. >>> >>> Did you make sure to run Clang's tests with your patch, in case you >>> introduced a regression? >>> >>> Other than those, LGTM! Doug, John, your thoughts? >>> >>> Chip >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >> >> Hello again, >> >> Thanks for your help. I had totally mistaken how the AttributeLists >> were handled, and have corrected that. >> >> I've checked this new patch against clang's tests, and there appear to >> be no regressions. >> >> One thing to note is that I've added a bit definition to ExtInfo, this >> is so that the compiler doesn't print the calling convention of every >> function, only ones you've explicitly declared in your code. This >> could be changed, but it would require that a few of the tests are >> re-written too. (As they depend on the 'plain' function signature >> being printed out.) >> >> I've also gone through and sorted out all the white-space, sorry about that. >> >> Please find attached the improved patch. >> >> -- Ricky Taylor >> > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From dgregor at apple.com Mon Jan 24 10:04:58 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 18:04:58 -0000 Subject: [cfe-commits] r124130 - /cfe/trunk/www/hacking.html Message-ID: <20110124180458.D55D82A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 12:04:58 2011 New Revision: 124130 URL: http://llvm.org/viewvc/llvm-project?rev=124130&view=rev Log: Note the need for --param=build_config=whatever in the Hacking Clang document, from Yuri Gribov Modified: cfe/trunk/www/hacking.html Modified: cfe/trunk/www/hacking.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/hacking.html?rev=124130&r1=124129&r2=124130&view=diff ============================================================================== --- cfe/trunk/www/hacking.html (original) +++ cfe/trunk/www/hacking.html Mon Jan 24 12:04:58 2011 @@ -185,6 +185,10 @@ (path to llvm)/llvm/tools/clang/test +

    For CMake builds e.g. on Windows with Visual Studio, you will need + to specify your build configuration (Debug, Release, etc.) via + --param=build_config=(build config).

    +

    To run a single test:

    From dgregor at apple.com Mon Jan 24 10:08:25 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 10:08:25 -0800 Subject: [cfe-commits] Small fixes In-Reply-To: References: <0A216463-12B4-4A38-9FE5-3924B4DB229D@apple.com> Message-ID: On Jan 24, 2011, at 10:00 AM, Yuri Gribov wrote: > Great, thanks. > >> IIRC, the --param=build_config= setting is only needed for CMake builds. >> I suggest mentioning this explicitly, so that people using the autoconf builds don't get confused. > > Here is the updated diff for hacking.html. Thanks! Committed as r124130. - Doug From dgregor at apple.com Mon Jan 24 10:25:03 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 10:25:03 -0800 Subject: [cfe-commits] [PATCH] Check access and ambiguity of delete operator In-Reply-To: References: Message-ID: On Jan 21, 2011, at 4:39 PM, Alex Miller wrote: > The attached patch should fix the TODO at lib/Sema/SemaExprCXX.cpp:1610 > > When compiling the following code > > class Foo { > private: > ~Foo(); > }; > > void do_foo() { > Foo *f = new Foo; > delete f; > } > > clang now emits the error > > testcase.cpp:8:10: error: calling a private destructor of class 'Foo *' > delete f; > ^ > testcase.cpp:3:5: note: declared private here > ~Foo(); > ^ > 1 error generated. > > instead of compiling the code successfully. Patch looks good. Could you provide a test case that we can integrate into Clang's test suite, e.g., that extends test/SemaCXX/new-delete.cpp? > If someone could point out how to turn the QualType instance representing 'Foo *' into just 'Foo', I'd appreciate it. Isn't PointeeElem the type you want to print? In any case, if you want to dig out the type that a QualType T points to, use something like if (const PointerType *PointerT = T->getAs()) { // PointerT->getPointeeType() is the type that T points to } Could you re-submit the patch with those tweaks? Thanks for working on this! - Doug From cdavis at mymail.mines.edu Mon Jan 24 10:28:02 2011 From: cdavis at mymail.mines.edu (Charles Davis) Date: Mon, 24 Jan 2011 11:28:02 -0700 Subject: [cfe-commits] [PATCH] Constructor and Destructor mangling, along with improved Calling Convention handling for Windows. In-Reply-To: References: <4D392218.9040405@mymail.mines.edu> Message-ID: <4D3DC4B2.9020604@mymail.mines.edu> On 1/24/11 11:01 AM, Douglas Gregor wrote: > Also, a change like this really needs testing. Here's a fun case: > > typedef void func_type(int); > > struct X { > func_type f; > }; > > presumably, "f" gets the thiscall calling convention because of its context, but then decltype(X::f) is different from func_type. Let me save you the trouble: Z:\Users\chip>cl /c test.cpp Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. test.cpp Z:\Users\chip>dumpbin /symbols test.obj Microsoft (R) COFF/PE Dumper Version 8.00.50727.42 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file test.obj File Type: COFF OBJECT COFF SYMBOL TABLE 000 006EC627 ABS notype Static | @comp.id 001 00000001 ABS notype Static | @feat.00 002 00000000 SECT1 notype Static | .drectve Section length 2F, #relocs 0, #linenums 0, checksum 0 004 00000000 SECT2 notype Static | .debug$S Section length 7D, #relocs 0, #linenums 0, checksum 0 006 00000000 SECT3 notype Static | .text Section length D, #relocs 0, #linenums 0, checksum 564BACA5 008 00000000 SECT3 notype () External | ?f at X@@QAEXH at Z (public: void __thiscall X::f(int)) String Table Size = 0x11 bytes Summary 7D .debug$S 2F .drectve D .text In VC8, X::f() does indeed have the __thiscall convention. I'm willing to bet that that's true of VC9 and VC10 as well. Chip From dgregor at apple.com Mon Jan 24 10:44:28 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 18:44:28 -0000 Subject: [cfe-commits] r124133 - in /cfe/trunk: test/Index/print-typekind.c tools/libclang/CXType.cpp Message-ID: <20110124184428.6C8532A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 12:44:28 2011 New Revision: 124133 URL: http://llvm.org/viewvc/llvm-project?rev=124133&view=rev Log: Eliminate the use of getTypeForDecl from clang_getCursorType() and clang_getDeclObjCTypeEncoding(); use ASTContext's methods instead, which will (lazily) create the type as needed. Otherwise, we can end up with null QualTypes. Modified: cfe/trunk/test/Index/print-typekind.c cfe/trunk/tools/libclang/CXType.cpp Modified: cfe/trunk/test/Index/print-typekind.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/print-typekind.c?rev=124133&r1=124132&r2=124133&view=diff ============================================================================== --- cfe/trunk/test/Index/print-typekind.c (original) +++ cfe/trunk/test/Index/print-typekind.c Mon Jan 24 12:44:28 2011 @@ -4,6 +4,7 @@ FooType w = z; return p + z; } +typedef double OtherType; // RUN: c-index-test -test-print-typekind %s | FileCheck %s // CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] [isPOD=1] @@ -22,4 +23,5 @@ // CHECK: UnexposedExpr= typekind=Pointer [isPOD=1] // CHECK: DeclRefExpr=p:3:13 typekind=Pointer [isPOD=1] // CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1] +// CHECK: TypedefDecl=OtherType:7:16 (Definition) typekind=Typedef [canonical=Double] [isPOD=1] Modified: cfe/trunk/tools/libclang/CXType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=124133&r1=124132&r2=124133&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CXType.cpp (original) +++ cfe/trunk/tools/libclang/CXType.cpp Mon Jan 24 12:44:28 2011 @@ -113,6 +113,7 @@ using namespace cxcursor; CXTranslationUnit TU = cxcursor::getCursorTU(C); + ASTContext &Context = static_cast(TU->TUData)->getASTContext(); if (clang_isExpression(C.kind)) { QualType T = cxcursor::getCursorExpr(C)->getType(); return MakeCXType(T, TU); @@ -122,9 +123,9 @@ Decl *D = cxcursor::getCursorDecl(C); if (TypeDecl *TD = dyn_cast(D)) - return MakeCXType(QualType(TD->getTypeForDecl(), 0), TU); + return MakeCXType(Context.getTypeDeclType(TD), TU); if (ObjCInterfaceDecl *ID = dyn_cast(D)) - return MakeCXType(QualType(ID->getTypeForDecl(), 0), TU); + return MakeCXType(Context.getObjCInterfaceType(ID), TU); if (ValueDecl *VD = dyn_cast(D)) return MakeCXType(VD->getType(), TU); if (ObjCPropertyDecl *PD = dyn_cast(D)) @@ -136,22 +137,22 @@ if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: - return MakeCXType( - QualType(getCursorObjCSuperClassRef(C).first->getTypeForDecl(), - 0), - TU); - - case CXCursor_ObjCClassRef: - return MakeCXType( - QualType(getCursorObjCClassRef(C).first->getTypeForDecl(), - 0), - TU); - - case CXCursor_TypeRef: - return MakeCXType(QualType(getCursorTypeRef(C).first->getTypeForDecl(), - 0), - TU); + case CXCursor_ObjCSuperClassRef: { + QualType T + = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_ObjCClassRef: { + QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_TypeRef: { + QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first); + return MakeCXType(T, TU); + + } case CXCursor_CXXBaseSpecifier: return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU); @@ -372,7 +373,7 @@ else { QualType Ty; if (TypeDecl *TD = dyn_cast(D)) - Ty = QualType(TD->getTypeForDecl(), 0); + Ty = Ctx.getTypeDeclType(TD); if (ValueDecl *VD = dyn_cast(D)) Ty = VD->getType(); else return cxstring::createCXString("?"); From dgregor at apple.com Mon Jan 24 10:51:00 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 10:51:00 -0800 Subject: [cfe-commits] patch: improve diagnostic on "class T::iterator" where T::iterator is a typedef In-Reply-To: References: Message-ID: <889F3B71-EC04-47B0-A8DB-03F4B068659E@apple.com> LGTM! On Jan 23, 2011, at 2:34 PM, Nick Lewycky wrote: > This patch fixes PR8755, a bug where we give a worse diagnostic when templates are involved than when they aren't. In the case of "class T::iterator" we look up tag types only then error out when one isn't found. The patch works by extended the error path to do a second lookup and report a more informative error when a non-tag type is found. > > Please review! > > Nick > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From dgregor at apple.com Mon Jan 24 10:54:39 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 18:54:39 -0000 Subject: [cfe-commits] r124135 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/SemaTemplate/function-template-specialization.cpp Message-ID: <20110124185439.9CF3F2A6C12C@llvm.org> Author: dgregor Date: Mon Jan 24 12:54:39 2011 New Revision: 124135 URL: http://llvm.org/viewvc/llvm-project?rev=124135&view=rev Log: Disallow function template partial specializations, from Hans Wennborg! Fixes PR8295. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/SemaTemplate/function-template-specialization.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124135&r1=124134&r2=124135&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 24 12:54:39 2011 @@ -1683,6 +1683,8 @@ "arguments to identify a particular function template">; def note_function_template_spec_matched : Note< "function template matches specialization %0">; +def err_function_template_partial_spec : Error< + "function template partial specialization is not allowed">; // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124135&r1=124134&r2=124135&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 24 12:54:39 2011 @@ -3836,8 +3836,10 @@ HasExplicitTemplateArgs = true; if (FunctionTemplate) { - // FIXME: Diagnose function template with explicit template - // arguments. + // Function template with explicit template arguments. + Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); + HasExplicitTemplateArgs = false; } else if (!isFunctionTemplateSpecialization && !D.getDeclSpec().isFriendSpecified()) { Modified: cfe/trunk/test/SemaTemplate/function-template-specialization.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/function-template-specialization.cpp?rev=124135&r1=124134&r2=124135&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/function-template-specialization.cpp (original) +++ cfe/trunk/test/SemaTemplate/function-template-specialization.cpp Mon Jan 24 12:54:39 2011 @@ -41,3 +41,8 @@ } template <> bool PR5833::f0(float &t1) {} +// PR8295 +namespace PR8295 { + template void f(T t) {} + template void f(T* t) {} // expected-error{{function template partial specialization is not allowed}} +} From dgregor at apple.com Mon Jan 24 10:58:06 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 10:58:06 -0800 Subject: [cfe-commits] [Patch] disallow function template partial specialization In-Reply-To: References: Message-ID: <9E381B42-8067-4961-9C72-FBC17F3C6120@apple.com> On Jan 24, 2011, at 3:50 AM, Hans Wennborg wrote: > Hi, > > The attached patch attempts to fix http://llvm.org/bugs/show_bug.cgi?id=8295 > > My reasoning is that: > > 1. For a regular function template declaration, one would never have > template arguments > 2. The same holds for overloading > 3. For a function template explicit specialization ("full > specialization"), one would never have template parameters. > > So, if a function template declaration has both template parameters > and template arguments, it must be an attempt at partial > specialization. > > I would be grateful if someone with deeper C++ knowledge could verify > that this is correct. Yes, this is all correct. > > Also, does C++0x change any of this? No, C++0x did not change this at all. Your patch looks great. I've committed it as r124135, thanks! - Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicholas at mxc.ca Mon Jan 24 11:01:04 2011 From: nicholas at mxc.ca (Nick Lewycky) Date: Mon, 24 Jan 2011 19:01:04 -0000 Subject: [cfe-commits] r124136 - in /cfe/trunk: lib/Sema/TreeTransform.h test/SemaCXX/PR8755.cpp Message-ID: <20110124190104.E23E22A6C12C@llvm.org> Author: nicholas Date: Mon Jan 24 13:01:04 2011 New Revision: 124136 URL: http://llvm.org/viewvc/llvm-project?rev=124136&view=rev Log: Enhance the diagnostic for referring to a typedef with an elaborated name to be as useful in a templated context as it is without templates. Fixes PR8755! Added: cfe/trunk/test/SemaCXX/PR8755.cpp Modified: cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=124136&r1=124135&r2=124136&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Mon Jan 24 13:01:04 2011 @@ -796,9 +796,28 @@ } if (!Tag) { - // FIXME: Would be nice to highlight just the source range. - SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) - << Kind << Id << DC; + // Check where the name exists but isn't a tag type and use that to emit + // better diagnostics. + LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); + SemaRef.LookupQualifiedName(Result, DC); + switch (Result.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: { + NamedDecl *SomeDecl = Result.getRepresentativeDecl(); + unsigned Kind = 0; + if (isa(SomeDecl)) Kind = 1; + else if (isa(SomeDecl)) Kind = 2; + SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; + SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); + break; + } + default: + // FIXME: Would be nice to highlight just the source range. + SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) + << Kind << Id << DC; + break; + } return QualType(); } Added: cfe/trunk/test/SemaCXX/PR8755.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR8755.cpp?rev=124136&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/PR8755.cpp (added) +++ cfe/trunk/test/SemaCXX/PR8755.cpp Mon Jan 24 13:01:04 2011 @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template +struct A { + typedef int iterator; // expected-note{{declared here}} +}; + +template +void f() { + class A ::iterator foo; // expected-error{{elaborated type refers to a typedef}} +} + +void g() { + f(); // expected-note{{in instantiation of function template}} +} + From dgregor at apple.com Mon Jan 24 11:22:01 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 11:22:01 -0800 Subject: [cfe-commits] [PATCH][Review request] ++/-- for AltiVec vectors In-Reply-To: <4D3ACE66.7060504@Gmail.com> References: <4CF32459.2000700@Gmail.com> <4D3ACE66.7060504@Gmail.com> Message-ID: <27003943-1EA5-4D4E-B685-856D6E7E0286@apple.com> On Jan 22, 2011, at 4:32 AM, Anton Yartsev wrote: > On 14.12.2010 19:08, Douglas Gregor wrote: >> On Nov 28, 2010, at 7:56 PM, Anton Yartsev wrote: >> >>> Support of ++/-- for AltiVec vectors according to "C/C++ Language Extensions for CBEA(Version 2.6)" section 10.3 >> A few comments. >> >> Index: lib/CodeGen/CGExprScalar.cpp >> =================================================================== >> --- lib/CodeGen/CGExprScalar.cpp (revision 120239) >> +++ lib/CodeGen/CGExprScalar.cpp (working copy) >> @@ -1257,10 +1257,11 @@ >> // An interesting aspect of this is that increment is always true. >> // Decrement does not have this property. >> NextVal = llvm::ConstantInt::getTrue(VMContext); >> - } else if (isa(InVal->getType())) { >> + } else if (isa(InVal->getType()) || >> + ValTy->isVectorType()&& ValTy->hasIntegerRepresentation()) { >> NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); >> - >> - if (!ValTy->isSignedIntegerType()) >> + >> + if (!ValTy->hasSignedIntegerRepresentation()) >> // Unsigned integer inc is always two's complement. >> NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); >> else { >> @@ -1292,6 +1293,8 @@ >> NextVal = >> llvm::ConstantFP::get(VMContext, >> llvm::APFloat(static_cast(AmountVal))); >> + else if (ValTy->isVectorType()&& ValTy->hasFloatingRepresentation()) >> + NextVal = llvm::ConstantFP::get(InVal->getType(), AmountVal); >> else { >> llvm::APFloat F(static_cast(AmountVal)); >> bool ignored; >> >> This looks a bit tangled... please completely separate out the vector case, rather than lumping it in with the integer case. >> >> Index: lib/Sema/SemaExpr.cpp >> =================================================================== >> --- lib/Sema/SemaExpr.cpp (revision 120239) >> +++ lib/Sema/SemaExpr.cpp (working copy) >> @@ -6931,6 +6931,8 @@ >> if (PR.isInvalid()) return QualType(); >> return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, >> isInc, isPrefix); >> + } else if (ResType->isVectorType()&& S.getLangOptions().AltiVec) { >> + // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) >> } else { >> S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) >> << ResType<< int(isInc)<< Op->getSourceRange(); >> >> Please check S.getLangOptions().AltiVec first, since the isVectorType() check is more expensive. >> >> Could you add some test cases that ensure that ++ and -- on vectors work properly in C++? Things to consider: >> - Test that the result is an lvalue, such that you can assign to it, assign to its components, etc. >> - Test that ++/-- work in templates, both with an arbitrary type 'T' that gets instantiated to an AltiVec vector, and when we have an AltiVec vector of dependent size (e.g., the size is N, a non-type template parameter of type unsigned). >> >> - Doug > Here is the new patch. Looks good, thanks! I've forgotten: do you have commit access? > Took into account the comments, but have not got how to create AltiVec vector of dependent size. Did you mean creating gcc vector with the vector_size attribute? I was thinking of: template struct X { typedef float type __attribute__((ext_vector_type(N))); }; X<4>::type v = { 1, 2, 3, 4}; But I've completely forgotten how or if ext_vector_type relates to AltiVec vectors! ;) - Doug From rjmccall at apple.com Mon Jan 24 11:43:20 2011 From: rjmccall at apple.com (John McCall) Date: Mon, 24 Jan 2011 11:43:20 -0800 Subject: [cfe-commits] [PATCH] Constructor and Destructor mangling, along with improved Calling Convention handling for Windows. In-Reply-To: References: <4D392218.9040405@mymail.mines.edu> Message-ID: On Jan 24, 2011, at 10:01 AM, Douglas Gregor wrote: > The calling-convention changes are going to need a bit more discussion. The main change is this: [snip] > which partially separates the notion of "is this the default calling convention"? from the description of the calling convention. However, it's not a complete separation, which I find a bit awkward. I could imagine removing CC_Default entirely, then adding the "the function type was written without an explicit calling convention" bit. When the function type itself is created, we pick the calling convention based on context (?) if it's default. It's not clear to me how this is supposed to work for typedefs or any other way we might get a function type independent from a single declaration. Plus, as you say, this leads to weirdness with typeof/decltype. I think CC_Default is actually the "least surprise" solution, but that we should change canonicalization so that CC_Default doesn't have any special relationship with CC_C or anything else. We then make the "isSameCallConv" predicate be context-dependent, where the contexts I can see are: (1) normal file-scope and static member functions, (2) blocks, (3) non-static member functions, and (4) Objective-C methods (although obviously the last doesn't come into play in the general type system). So these types would no longer have the same canonical type, which I think is good: cdecl void(int) void(int) What I think is a more interesting question is whether these types have the same canonical type: cdecl void(*)(int) void(*)(int) Clearly these are logically the same type, but the problem is that (1) it's possible to detect the difference with template argument deduction and (2) throwing a pointer on something and then removing it would no longer be a semantic no-op. So maybe the best solution is to leave them canonically distinct and introduce more 'noreturn'-like conversions, which I'm sure is what you wanted to hear. :) John. From anton.yartsev at gmail.com Mon Jan 24 12:55:22 2011 From: anton.yartsev at gmail.com (Anton Yartsev) Date: Mon, 24 Jan 2011 20:55:22 -0000 Subject: [cfe-commits] r124146 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/CodeGen/builtins-ppc-altivec.c test/SemaCXX/altivec.cpp Message-ID: <20110124205522.7D6422A6C12C@llvm.org> Author: ayartsev Date: Mon Jan 24 14:55:22 2011 New Revision: 124146 URL: http://llvm.org/viewvc/llvm-project?rev=124146&view=rev Log: pre/post increase/decrease for AltiVec vectors Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/CodeGen/builtins-ppc-altivec.c cfe/trunk/test/SemaCXX/altivec.cpp Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=124146&r1=124145&r2=124146&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Mon Jan 24 14:55:22 2011 @@ -302,6 +302,11 @@ return EmitScalarPrePostIncDec(E, LV, true, true); } + llvm::Value *EmitAddConsiderOverflowBehavior(const UnaryOperator *E, + llvm::Value *InVal, + llvm::Value *NextVal, + bool IsInc); + llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); @@ -1222,6 +1227,31 @@ //===----------------------------------------------------------------------===// llvm::Value *ScalarExprEmitter:: +EmitAddConsiderOverflowBehavior(const UnaryOperator *E, + llvm::Value *InVal, + llvm::Value *NextVal, bool IsInc) { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Undefined: + return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + break; + case LangOptions::SOB_Defined: + return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + break; + case LangOptions::SOB_Trapping: + BinOpInfo BinOp; + BinOp.LHS = InVal; + BinOp.RHS = NextVal; + BinOp.Ty = E->getType(); + BinOp.Opcode = BO_Add; + BinOp.E = E; + return EmitOverflowCheckedBinOp(BinOp); + break; + } + assert(false && "Unknown SignedOverflowBehaviorTy"); + return 0; +} + +llvm::Value *ScalarExprEmitter:: EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { @@ -1270,31 +1300,26 @@ // An interesting aspect of this is that increment is always true. // Decrement does not have this property. NextVal = llvm::ConstantInt::getTrue(VMContext); + } else if (ValTy->isVectorType()) { + if (ValTy->hasIntegerRepresentation()) { + NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); + + NextVal = ValTy->hasSignedIntegerRepresentation() ? + EmitAddConsiderOverflowBehavior(E, InVal, NextVal, isInc) : + Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + } else { + NextVal = Builder.CreateFAdd( + InVal, + llvm::ConstantFP::get(InVal->getType(), AmountVal), + isInc ? "inc" : "dec"); + } } else if (isa(InVal->getType())) { NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - - if (!ValTy->isSignedIntegerType()) - // Unsigned integer inc is always two's complement. - NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); - else { - switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec"); - break; - case LangOptions::SOB_Defined: - NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); - break; - case LangOptions::SOB_Trapping: - BinOpInfo BinOp; - BinOp.LHS = InVal; - BinOp.RHS = NextVal; - BinOp.Ty = E->getType(); - BinOp.Opcode = BO_Add; - BinOp.E = E; - NextVal = EmitOverflowCheckedBinOp(BinOp); - break; - } - } + + NextVal = ValTy->isSignedIntegerType() ? + EmitAddConsiderOverflowBehavior(E, InVal, NextVal, isInc) : + // Unsigned integer inc is always two's complement. + Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); } else { // Add the inc/dec to the real part. if (InVal->getType()->isFloatTy()) Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124146&r1=124145&r2=124146&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 24 14:55:22 2011 @@ -7081,6 +7081,8 @@ if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, isInc, isPrefix); + } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) { + // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) << ResType << int(isInc) << Op->getSourceRange(); Modified: cfe/trunk/test/CodeGen/builtins-ppc-altivec.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins-ppc-altivec.c?rev=124146&r1=124145&r2=124146&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/builtins-ppc-altivec.c (original) +++ cfe/trunk/test/CodeGen/builtins-ppc-altivec.c Mon Jan 24 14:55:22 2011 @@ -3113,3 +3113,14 @@ res_i = (vf1 <= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 res_i = (vf1 >= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 } + +/* ------------------------------- increment/decrement: ----------------------------- */ +// CHECK: define void @test8 +void test8() { + vector int vi; + vi++; // CHECK: add nsw <4 x i32> {{.*}} + vector unsigned int vui; + --vui; // CHECK: add <4 x i32> {{.*}} + vector float vf; + vf++; // CHECK: fadd <4 x float> {{.*}} +} Modified: cfe/trunk/test/SemaCXX/altivec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/altivec.cpp?rev=124146&r1=124145&r2=124146&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/altivec.cpp (original) +++ cfe/trunk/test/SemaCXX/altivec.cpp Mon Jan 24 14:55:22 2011 @@ -6,7 +6,7 @@ { } -void test() +void test1() { V4i vGCC; vector int vAltiVec; @@ -16,3 +16,24 @@ bool res = vGCC > vAltiVec; vAltiVec = 0 ? vGCC : vGCC; } + +template +void template_f(T param) { + param++; +} + +void test2() +{ + vector int vi; + ++vi; + vi++; + --vi; + vi--; + vector float vf; + vf++; + + ++vi=vi; + vi++=vi; // expected-error {{expression is not assignable}} + (++vi)[1]=1; + template_f(vi); +} From anton.yartsev at gmail.com Mon Jan 24 13:01:01 2011 From: anton.yartsev at gmail.com (Anton Yartsev) Date: Tue, 25 Jan 2011 00:01:01 +0300 Subject: [cfe-commits] [PATCH][Review request] ++/-- for AltiVec vectors In-Reply-To: <27003943-1EA5-4D4E-B685-856D6E7E0286@apple.com> References: <4CF32459.2000700@Gmail.com> <4D3ACE66.7060504@Gmail.com> <27003943-1EA5-4D4E-B685-856D6E7E0286@apple.com> Message-ID: <4D3DE88D.4010606@Gmail.com> On 24.01.2011 22:22, Douglas Gregor wrote: > On Jan 22, 2011, at 4:32 AM, Anton Yartsev wrote: > >> On 14.12.2010 19:08, Douglas Gregor wrote: >>> On Nov 28, 2010, at 7:56 PM, Anton Yartsev wrote: >>> >>>> Support of ++/-- for AltiVec vectors according to "C/C++ Language Extensions for CBEA(Version 2.6)" section 10.3 >>> A few comments. >>> >>> Index: lib/CodeGen/CGExprScalar.cpp >>> =================================================================== >>> --- lib/CodeGen/CGExprScalar.cpp (revision 120239) >>> +++ lib/CodeGen/CGExprScalar.cpp (working copy) >>> @@ -1257,10 +1257,11 @@ >>> // An interesting aspect of this is that increment is always true. >>> // Decrement does not have this property. >>> NextVal = llvm::ConstantInt::getTrue(VMContext); >>> - } else if (isa(InVal->getType())) { >>> + } else if (isa(InVal->getType()) || >>> + ValTy->isVectorType()&& ValTy->hasIntegerRepresentation()) { >>> NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); >>> - >>> - if (!ValTy->isSignedIntegerType()) >>> + >>> + if (!ValTy->hasSignedIntegerRepresentation()) >>> // Unsigned integer inc is always two's complement. >>> NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); >>> else { >>> @@ -1292,6 +1293,8 @@ >>> NextVal = >>> llvm::ConstantFP::get(VMContext, >>> llvm::APFloat(static_cast(AmountVal))); >>> + else if (ValTy->isVectorType()&& ValTy->hasFloatingRepresentation()) >>> + NextVal = llvm::ConstantFP::get(InVal->getType(), AmountVal); >>> else { >>> llvm::APFloat F(static_cast(AmountVal)); >>> bool ignored; >>> >>> This looks a bit tangled... please completely separate out the vector case, rather than lumping it in with the integer case. >>> >>> Index: lib/Sema/SemaExpr.cpp >>> =================================================================== >>> --- lib/Sema/SemaExpr.cpp (revision 120239) >>> +++ lib/Sema/SemaExpr.cpp (working copy) >>> @@ -6931,6 +6931,8 @@ >>> if (PR.isInvalid()) return QualType(); >>> return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, >>> isInc, isPrefix); >>> + } else if (ResType->isVectorType()&& S.getLangOptions().AltiVec) { >>> + // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) >>> } else { >>> S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) >>> << ResType<< int(isInc)<< Op->getSourceRange(); >>> >>> Please check S.getLangOptions().AltiVec first, since the isVectorType() check is more expensive. >>> >>> Could you add some test cases that ensure that ++ and -- on vectors work properly in C++? Things to consider: >>> - Test that the result is an lvalue, such that you can assign to it, assign to its components, etc. >>> - Test that ++/-- work in templates, both with an arbitrary type 'T' that gets instantiated to an AltiVec vector, and when we have an AltiVec vector of dependent size (e.g., the size is N, a non-type template parameter of type unsigned). >>> >>> - Doug >> Here is the new patch. > Looks good, thanks! I've forgotten: do you have commit access? > >> Took into account the comments, but have not got how to create AltiVec vector of dependent size. Did you mean creating gcc vector with the vector_size attribute? > > I was thinking of: > > template > struct X { > typedef float type __attribute__((ext_vector_type(N))); > }; > > X<4>::type v = { 1, 2, 3, 4}; > > But I've completely forgotten how or if ext_vector_type relates to AltiVec vectors! ;) > > - Doug Commited at 124146! -- Anton From Renato.Golin at arm.com Mon Jan 24 13:30:10 2011 From: Renato.Golin at arm.com (Renato Golin) Date: Mon, 24 Jan 2011 21:30:10 +0000 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> <4D3DB5BA.8070708@arm.com> Message-ID: <4D3DEF62.7060709@arm.com> On 24/01/11 17:33, Douglas Gregor wrote: > That depends on the linker. With the Mac OS 10.6 dynamic linker, for > example, a strong external symbol in one shared library will not get > merged with same-named weak symbols in another shared library. Oh! I see... So what do you do? Mangle them differently? Or just make sure that nothing in one object access the symbols in the other objects? cheers, --renato -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. From dgregor at apple.com Mon Jan 24 14:40:09 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 14:40:09 -0800 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DEF62.7060709@arm.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> <4D3DB5BA.8070708@arm.com> <4D3DEF62.7060709@arm.com> Message-ID: <6B1653D1-515C-4148-A1B7-1883735CCAFE@apple.com> On Jan 24, 2011, at 1:30 PM, Renato Golin wrote: > On 24/01/11 17:33, Douglas Gregor wrote: >> That depends on the linker. With the Mac OS 10.6 dynamic linker, for >> example, a strong external symbol in one shared library will not get >> merged with same-named weak symbols in another shared library. > > Oh! I see... > > So what do you do? Mangle them differently? Or just make sure that > nothing in one object access the symbols in the other objects? I honestly don't know the details of the optimization. I just know the limits it places on explicit instantiations :) - Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: From echristo at apple.com Mon Jan 24 15:07:03 2011 From: echristo at apple.com (Eric Christopher) Date: Mon, 24 Jan 2011 23:07:03 -0000 Subject: [cfe-commits] r124153 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/CodeGen/builtins-ppc-altivec.c test/SemaCXX/altivec.cpp Message-ID: <20110124230703.A99432A6C12C@llvm.org> Author: echristo Date: Mon Jan 24 17:07:03 2011 New Revision: 124153 URL: http://llvm.org/viewvc/llvm-project?rev=124153&view=rev Log: Revert r124146 for now. It appears to be failing on a few platforms. Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/CodeGen/builtins-ppc-altivec.c cfe/trunk/test/SemaCXX/altivec.cpp Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=124153&r1=124152&r2=124153&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Mon Jan 24 17:07:03 2011 @@ -302,11 +302,6 @@ return EmitScalarPrePostIncDec(E, LV, true, true); } - llvm::Value *EmitAddConsiderOverflowBehavior(const UnaryOperator *E, - llvm::Value *InVal, - llvm::Value *NextVal, - bool IsInc); - llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); @@ -1227,31 +1222,6 @@ //===----------------------------------------------------------------------===// llvm::Value *ScalarExprEmitter:: -EmitAddConsiderOverflowBehavior(const UnaryOperator *E, - llvm::Value *InVal, - llvm::Value *NextVal, bool IsInc) { - switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); - break; - case LangOptions::SOB_Defined: - return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec"); - break; - case LangOptions::SOB_Trapping: - BinOpInfo BinOp; - BinOp.LHS = InVal; - BinOp.RHS = NextVal; - BinOp.Ty = E->getType(); - BinOp.Opcode = BO_Add; - BinOp.E = E; - return EmitOverflowCheckedBinOp(BinOp); - break; - } - assert(false && "Unknown SignedOverflowBehaviorTy"); - return 0; -} - -llvm::Value *ScalarExprEmitter:: EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { @@ -1300,26 +1270,31 @@ // An interesting aspect of this is that increment is always true. // Decrement does not have this property. NextVal = llvm::ConstantInt::getTrue(VMContext); - } else if (ValTy->isVectorType()) { - if (ValTy->hasIntegerRepresentation()) { - NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - - NextVal = ValTy->hasSignedIntegerRepresentation() ? - EmitAddConsiderOverflowBehavior(E, InVal, NextVal, isInc) : - Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); - } else { - NextVal = Builder.CreateFAdd( - InVal, - llvm::ConstantFP::get(InVal->getType(), AmountVal), - isInc ? "inc" : "dec"); - } } else if (isa(InVal->getType())) { NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - - NextVal = ValTy->isSignedIntegerType() ? - EmitAddConsiderOverflowBehavior(E, InVal, NextVal, isInc) : - // Unsigned integer inc is always two's complement. - Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + + if (!ValTy->isSignedIntegerType()) + // Unsigned integer inc is always two's complement. + NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + else { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Undefined: + NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec"); + break; + case LangOptions::SOB_Defined: + NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + break; + case LangOptions::SOB_Trapping: + BinOpInfo BinOp; + BinOp.LHS = InVal; + BinOp.RHS = NextVal; + BinOp.Ty = E->getType(); + BinOp.Opcode = BO_Add; + BinOp.E = E; + NextVal = EmitOverflowCheckedBinOp(BinOp); + break; + } + } } else { // Add the inc/dec to the real part. if (InVal->getType()->isFloatTy()) Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124153&r1=124152&r2=124153&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 24 17:07:03 2011 @@ -7081,8 +7081,6 @@ if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, isInc, isPrefix); - } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) { - // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) << ResType << int(isInc) << Op->getSourceRange(); Modified: cfe/trunk/test/CodeGen/builtins-ppc-altivec.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins-ppc-altivec.c?rev=124153&r1=124152&r2=124153&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/builtins-ppc-altivec.c (original) +++ cfe/trunk/test/CodeGen/builtins-ppc-altivec.c Mon Jan 24 17:07:03 2011 @@ -3113,14 +3113,3 @@ res_i = (vf1 <= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 res_i = (vf1 >= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 } - -/* ------------------------------- increment/decrement: ----------------------------- */ -// CHECK: define void @test8 -void test8() { - vector int vi; - vi++; // CHECK: add nsw <4 x i32> {{.*}} - vector unsigned int vui; - --vui; // CHECK: add <4 x i32> {{.*}} - vector float vf; - vf++; // CHECK: fadd <4 x float> {{.*}} -} Modified: cfe/trunk/test/SemaCXX/altivec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/altivec.cpp?rev=124153&r1=124152&r2=124153&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/altivec.cpp (original) +++ cfe/trunk/test/SemaCXX/altivec.cpp Mon Jan 24 17:07:03 2011 @@ -6,7 +6,7 @@ { } -void test1() +void test() { V4i vGCC; vector int vAltiVec; @@ -16,24 +16,3 @@ bool res = vGCC > vAltiVec; vAltiVec = 0 ? vGCC : vGCC; } - -template -void template_f(T param) { - param++; -} - -void test2() -{ - vector int vi; - ++vi; - vi++; - --vi; - vi--; - vector float vf; - vf++; - - ++vi=vi; - vi++=vi; // expected-error {{expression is not assignable}} - (++vi)[1]=1; - template_f(vi); -} From rjmccall at apple.com Mon Jan 24 15:24:39 2011 From: rjmccall at apple.com (John McCall) Date: Mon, 24 Jan 2011 15:24:39 -0800 Subject: [cfe-commits] r124089 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/exceptions-no-rtti.cpp test/CodeGenCXX/key-function-vtable.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/rtti-linkage.cpp test/Co... In-Reply-To: <4D3DEF62.7060709@arm.com> References: <20110124004619.DA8DF2A6C12C@llvm.org> <4D3DAB61.8040508@gmail.com> <4D3DB207.1050606@arm.com> <25556E38-807F-4F0F-96EE-5213154D50F1@apple.com> <4D3DB5BA.8070708@arm.com> <4D3DEF62.7060709@arm.com> Message-ID: On Jan 24, 2011, at 1:30 PM, Renato Golin wrote: > On 24/01/11 17:33, Douglas Gregor wrote: >> That depends on the linker. With the Mac OS 10.6 dynamic linker, for >> example, a strong external symbol in one shared library will not get >> merged with same-named weak symbols in another shared library. > > Oh! I see... > > So what do you do? Mangle them differently? Or just make sure that > nothing in one object access the symbols in the other objects? I believe the dynamic linker just assumes it never happens, and you get undefined behavior if it does. There really isn't much point in having a strong external symbol if everyone involved gives it weak semantics anyway. John. From akyrtzi at gmail.com Mon Jan 24 16:03:45 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 00:03:45 -0000 Subject: [cfe-commits] r124157 - /cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Message-ID: <20110125000345.C11E72A6C12E@llvm.org> Author: akirtzidis Date: Mon Jan 24 18:03:45 2011 New Revision: 124157 URL: http://llvm.org/viewvc/llvm-project?rev=124157&view=rev Log: [analyzer] Simplify GetReceiverType function in BasicObjCFoundationChecks.cpp; no functionality change. Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp?rev=124157&r1=124156&r2=124157&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Mon Jan 24 18:03:45 2011 @@ -43,24 +43,8 @@ //===----------------------------------------------------------------------===// static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { - QualType T; - switch (ME->getReceiverKind()) { - case ObjCMessageExpr::Instance: - T = ME->getInstanceReceiver()->getType(); - break; - - case ObjCMessageExpr::SuperInstance: - T = ME->getSuperType(); - break; - - case ObjCMessageExpr::Class: - case ObjCMessageExpr::SuperClass: - return 0; - } - - if (const ObjCObjectPointerType *PT = T->getAs()) - return PT->getInterfaceType(); - + if (ObjCInterfaceDecl *ID = ME->getReceiverInterface()) + return ID->getTypeForDecl()->getAs(); return NULL; } From akyrtzi at gmail.com Mon Jan 24 16:03:48 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 00:03:48 -0000 Subject: [cfe-commits] r124158 - /cfe/trunk/lib/AST/Expr.cpp Message-ID: <20110125000348.4874E2A6C12F@llvm.org> Author: akirtzidis Date: Mon Jan 24 18:03:48 2011 New Revision: 124158 URL: http://llvm.org/viewvc/llvm-project?rev=124158&view=rev Log: In a ObjCMessageExpr with the super class as receiver, 'super' is actually a ObjCInterfaceType. Modified: cfe/trunk/lib/AST/Expr.cpp Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=124158&r1=124157&r2=124158&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Mon Jan 24 18:03:48 2011 @@ -2471,9 +2471,9 @@ break; case SuperClass: - if (const ObjCObjectPointerType *Iface - = getSuperType()->getAs()) - return Iface->getInterfaceDecl(); + if (const ObjCObjectType *Iface + = getSuperType()->getAs()) + return Iface->getInterface(); break; } From akyrtzi at gmail.com Mon Jan 24 16:03:53 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 00:03:53 -0000 Subject: [cfe-commits] r124159 - in /cfe/trunk: include/clang/StaticAnalyzer/PathSensitive/ lib/StaticAnalyzer/ lib/StaticAnalyzer/Checkers/ Message-ID: <20110125000354.195D62A6C12E@llvm.org> Author: akirtzidis Date: Mon Jan 24 18:03:53 2011 New Revision: 124159 URL: http://llvm.org/viewvc/llvm-project?rev=124159&view=rev Log: [analyzer] Introduce ObjCMessage which represents both explicit ObjC message expressions and implicit messages that are sent for handling properties in dot syntax. Replace all direct uses of ObjCMessageExpr in the checkers and checker interface with ObjCMessage. Added: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h cfe/trunk/lib/StaticAnalyzer/ObjCMessage.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/Checker.h cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp cfe/trunk/lib/StaticAnalyzer/CMakeLists.txt cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/Checker.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/Checker.h?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/Checker.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/Checker.h Mon Jan 24 18:03:53 2011 @@ -203,12 +203,26 @@ _PostVisit(C, S); } + void GR_visitObjCMessage(ExplodedNodeSet &Dst, + StmtNodeBuilder &Builder, + ExprEngine &Eng, + const ObjCMessage &msg, + ExplodedNode *Pred, void *tag, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + isPrevisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind, 0, msg.getOriginExpr()); + if (isPrevisit) + preVisitObjCMessage(C, msg); + else + postVisitObjCMessage(C, msg); + } + bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, - ExprEngine &Eng, const ObjCMessageExpr *ME, + ExprEngine &Eng, const ObjCMessage &msg, ExplodedNode *Pred, const GRState *state, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - 0, ME, state); - return evalNilReceiver(C, ME); + 0, msg.getOriginExpr(), state); + return evalNilReceiver(C, msg); } bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, @@ -258,6 +272,8 @@ virtual ~Checker(); virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} + virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} + virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location, bool isLoad) {} virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, @@ -272,7 +288,7 @@ ExprEngine &Eng, const Stmt *Condition, void *tag) {} - virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) { + virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) { return false; } Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def Mon Jan 24 18:03:53 2011 @@ -34,7 +34,6 @@ PREVISIT(DeclStmt, Stmt) PREVISIT(ImplicitCastExpr, CastExpr) PREVISIT(ObjCAtSynchronizedStmt, Stmt) -PREVISIT(ObjCMessageExpr, Stmt) PREVISIT(ReturnStmt, Stmt) POSTVISIT(BlockExpr, Stmt) @@ -43,7 +42,6 @@ POSTVISIT(CompoundAssignOperator, BinaryOperator) POSTVISIT(CXXOperatorCallExpr, GenericCall) POSTVISIT(CXXMemberCallExpr, GenericCall) -POSTVISIT(ObjCMessageExpr, Stmt) POSTVISIT(ObjCIvarRefExpr, Stmt) #undef PREVISIT Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h Mon Jan 24 18:03:53 2011 @@ -282,11 +282,14 @@ void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, CallbackKind Kind); + void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, bool isPrevisit); + bool CheckerEvalCall(const CallExpr *CE, ExplodedNodeSet &Dst, ExplodedNode *Pred); - void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + void CheckerEvalNilReceiver(const ObjCMessage &msg, ExplodedNodeSet &Dst, const GRState *state, ExplodedNode *Pred); @@ -490,10 +493,10 @@ } protected: - void evalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME, - ExplodedNode* Pred, const GRState *state) { + void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg, + ExplodedNode* Pred, const GRState *state) { assert (Builder && "StmtNodeBuilder must be defined."); - getTF().evalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state); + getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state); } const GRState* MarkBranch(const GRState* St, const Stmt* Terminator, Added: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h?rev=124159&view=auto ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h (added) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h Mon Jan 24 18:03:53 2011 @@ -0,0 +1,207 @@ +//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ObjCMessage which serves as a common wrapper for ObjC +// message expressions or implicit messages for loading/storing ObjC properties. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE +#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE + +#include "clang/StaticAnalyzer/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/PathSensitive/GRState.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { +namespace ento { + +/// \brief Represents both explicit ObjC message expressions and implicit +/// messages that are sent for handling properties in dot syntax. +class ObjCMessage { + const Expr *MsgOrPropE; + const Expr *OriginE; + bool IsPropSetter; + SVal SetterArgV; + +protected: + ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV) + : MsgOrPropE(E), OriginE(origE), + IsPropSetter(isSetter), SetterArgV(setArgV) { } + +public: + ObjCMessage() : MsgOrPropE(0), OriginE(0) { } + + ObjCMessage(const ObjCMessageExpr *E) + : MsgOrPropE(E), OriginE(E) { + assert(E && "should not be initialized with null expression"); + } + + bool isValid() const { return MsgOrPropE != 0; } + bool isInvalid() const { return !isValid(); } + + bool isMessageExpr() const { + return isValid() && isa(MsgOrPropE); + } + + bool isPropertyGetter() const { + return isValid() && + isa(MsgOrPropE) && !IsPropSetter; + } + + bool isPropertySetter() const { + return isValid() && + isa(MsgOrPropE) && IsPropSetter; + } + + const Expr *getOriginExpr() const { return OriginE; } + + QualType getType(ASTContext &ctx) const; + + QualType getResultType(ASTContext &ctx) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + if (const ObjCMethodDecl *MD = msgE->getMethodDecl()) + return MD->getResultType(); + return getType(ctx); + } + + Selector getSelector() const; + + const Expr *getInstanceReceiver() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getInstanceReceiver(); + return cast(MsgOrPropE)->getBase(); + } + + bool isInstanceMessage() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->isInstanceMessage(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + // FIXME: 'super' may be super class. + return propE->isObjectReceiver() || propE->isSuperReceiver(); + } + + const ObjCMethodDecl *getMethodDecl() const; + + const ObjCInterfaceDecl *getReceiverInterface() const; + + SourceLocation getSuperLoc() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getSuperLoc(); + return cast(MsgOrPropE)->getReceiverLocation(); + } + + SourceRange getSourceRange() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + return MsgOrPropE->getSourceRange(); + } + + unsigned getNumArgs() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getNumArgs(); + return isPropertySetter() ? 1 : 0; + } + + SVal getArgSVal(unsigned i, const GRState *state) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return state->getSVal(msgE->getArg(i)); + assert(isPropertySetter()); + return SetterArgV; + } + + QualType getArgType(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getArg(i)->getType(); + assert(isPropertySetter()); + return cast(MsgOrPropE)->getType(); + } + + const Expr *getArgExpr(unsigned i) const; + + SourceRange getArgSourceRange(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const Expr *argE = getArgExpr(i)) + return argE->getSourceRange(); + return OriginE->getSourceRange(); + } +}; + +class ObjCPropertyGetter : public ObjCMessage { +public: + ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE) + : ObjCMessage(propE, originE, false, SVal()) { + assert(propE && originE && + "should not be initialized with null expressions"); + } +}; + +class ObjCPropertySetter : public ObjCMessage { +public: + ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE, + SVal argV) + : ObjCMessage(propE, storeE, true, argV) { + assert(propE && storeE &&"should not be initialized with null expressions"); + } +}; + +/// \brief Common wrapper for a call expression or an ObjC message, mainly to +/// provide a common interface for handling their arguments. +class CallOrObjCMessage { + const CallExpr *CallE; + ObjCMessage Msg; + const GRState *State; + +public: + CallOrObjCMessage(const CallExpr *callE, const GRState *state) + : CallE(callE), State(state) { } + CallOrObjCMessage(const ObjCMessage &msg, const GRState *state) + : CallE(0), Msg(msg), State(state) { } + + QualType getResultType(ASTContext &ctx) const; + + unsigned getNumArgs() const { + if (CallE) return CallE->getNumArgs(); + return Msg.getNumArgs(); + } + + SVal getArgSVal(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return State->getSVal(CallE->getArg(i)); + return Msg.getArgSVal(i, State); + } + + SVal getArgSValAsScalarOrLoc(unsigned i) const; + + const Expr *getArg(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return CallE->getArg(i); + return Msg.getArgExpr(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return CallE->getArg(i)->getSourceRange(); + return Msg.getArgSourceRange(i); + } +}; + +} +} + +#endif Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h Mon Jan 24 18:03:53 2011 @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/PathSensitive/GRState.h" #include "clang/StaticAnalyzer/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h" #include namespace clang { @@ -47,12 +48,12 @@ const CallExpr* CE, SVal L, ExplodedNode* Pred) {} - virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - const ObjCMessageExpr* ME, - ExplodedNode* Pred, - const GRState *state) {} + virtual void evalObjCMessage(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + ObjCMessage msg, + ExplodedNode* Pred, + const GRState *state) {} // Stores. Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Mon Jan 24 18:03:53 2011 @@ -40,14 +40,15 @@ namespace { class InstanceReceiver { - const ObjCMessageExpr *ME; + ObjCMessage Msg; const LocationContext *LC; public: - InstanceReceiver(const ObjCMessageExpr *me = 0, - const LocationContext *lc = 0) : ME(me), LC(lc) {} + InstanceReceiver() : LC(0) { } + InstanceReceiver(const ObjCMessage &msg, + const LocationContext *lc = 0) : Msg(msg), LC(lc) {} bool isValid() const { - return ME && ME->isInstanceMessage(); + return Msg.isValid() && Msg.isInstanceMessage(); } operator bool() const { return isValid(); @@ -57,7 +58,7 @@ assert(isValid()); // We have an expression for the receiver? Fetch the value // of that expression. - if (const Expr *Ex = ME->getInstanceReceiver()) + if (const Expr *Ex = Msg.getInstanceReceiver()) return state->getSValAsScalarOrLoc(Ex); // Otherwise we are sending a message to super. In this case the @@ -70,11 +71,11 @@ SourceRange getSourceRange() const { assert(isValid()); - if (const Expr *Ex = ME->getInstanceReceiver()) + if (const Expr *Ex = Msg.getInstanceReceiver()) return Ex->getSourceRange(); // Otherwise we are sending a message to super. - SourceLocation L = ME->getSuperLoc(); + SourceLocation L = Msg.getSuperLoc(); assert(L.isValid()); return SourceRange(L, L); } @@ -798,14 +799,14 @@ RetainSummary* getSummary(const FunctionDecl* FD); - RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME, + RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg, const GRState *state, const LocationContext *LC); - RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, + RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg, const ObjCInterfaceDecl* ID) { - return getInstanceMethodSummary(ME->getSelector(), 0, - ID, ME->getMethodDecl(), ME->getType()); + return getInstanceMethodSummary(msg.getSelector(), 0, + ID, msg.getMethodDecl(), msg.getType(Ctx)); } RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, @@ -818,23 +819,15 @@ const ObjCMethodDecl *MD, QualType RetTy); - RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { - ObjCInterfaceDecl *Class = 0; - switch (ME->getReceiverKind()) { - case ObjCMessageExpr::Class: - case ObjCMessageExpr::SuperClass: - Class = ME->getReceiverInterface(); - break; - - case ObjCMessageExpr::Instance: - case ObjCMessageExpr::SuperInstance: - break; - } + RetainSummary *getClassMethodSummary(const ObjCMessage &msg) { + const ObjCInterfaceDecl *Class = 0; + if (!msg.isInstanceMessage()) + Class = msg.getReceiverInterface(); - return getClassMethodSummary(ME->getSelector(), + return getClassMethodSummary(msg.getSelector(), Class? Class->getIdentifier() : 0, Class, - ME->getMethodDecl(), ME->getType()); + msg.getMethodDecl(), msg.getType(Ctx)); } /// getMethodSummary - This version of getMethodSummary is used to query @@ -1310,13 +1303,13 @@ } RetainSummary* -RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, +RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg, const GRState *state, const LocationContext *LC) { // We need the type-information of the tracked receiver object // Retrieve it from the state. - const Expr *Receiver = ME->getInstanceReceiver(); + const Expr *Receiver = msg.getInstanceReceiver(); const ObjCInterfaceDecl* ID = 0; // FIXME: Is this really working as expected? There are cases where @@ -1344,12 +1337,12 @@ } } else { // FIXME: Hack for 'super'. - ID = ME->getReceiverInterface(); + ID = msg.getReceiverInterface(); } // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. - RetainSummary *Summ = getInstanceMethodSummary(ME, ID); + RetainSummary *Summ = getInstanceMethodSummary(msg, ID); // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. @@ -1693,10 +1686,10 @@ ExprEngine& Eng, StmtNodeBuilder& Builder, const Expr* Ex, + const CallOrObjCMessage &callOrMsg, InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, - ConstExprIterator arg_beg, ConstExprIterator arg_end, ExplodedNode* Pred, const GRState *state); virtual void evalCall(ExplodedNodeSet& Dst, @@ -1706,12 +1699,12 @@ ExplodedNode* Pred); - virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - const ObjCMessageExpr* ME, - ExplodedNode* Pred, - const GRState *state); + virtual void evalObjCMessage(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + ObjCMessage msg, + ExplodedNode* Pred, + const GRState *state); // Stores. virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val); @@ -2477,16 +2470,14 @@ ExprEngine& Eng, StmtNodeBuilder& Builder, const Expr* Ex, + const CallOrObjCMessage &callOrMsg, InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, - ConstExprIterator arg_beg, - ConstExprIterator arg_end, ExplodedNode* Pred, const GRState *state) { // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; - unsigned idx = 0; SourceRange ErrorRange; SymbolRef ErrorSym = 0; @@ -2498,8 +2489,8 @@ // done an invalidation pass. llvm::DenseSet WhitelistedSymbols; - for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { - SVal V = state->getSValAsScalarOrLoc(*I); + for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) { + SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx); SymbolRef Sym = V.getAsLocSymbol(); if (Sym) @@ -2507,7 +2498,7 @@ WhitelistedSymbols.insert(Sym); state = Update(state, Sym, *T, Summ.getArg(idx), hasErr); if (hasErr) { - ErrorRange = (*I)->getSourceRange(); + ErrorRange = callOrMsg.getArgSourceRange(idx); ErrorSym = Sym; break; } @@ -2650,19 +2641,7 @@ // FIXME: We eventually should handle structs and other compound types // that are returned by value. - QualType T = Ex->getType(); - - // For CallExpr, use the result type to know if it returns a reference. - if (const CallExpr *CE = dyn_cast(Ex)) { - const Expr *Callee = CE->getCallee(); - if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl()) - T = FD->getResultType(); - } - else if (const ObjCMessageExpr *ME = dyn_cast(Ex)) { - if (const ObjCMethodDecl *MD = ME->getMethodDecl()) - T = MD->getResultType(); - } - + QualType T = callOrMsg.getResultType(Eng.getContext()); if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); SValBuilder &svalBuilder = Eng.getSValBuilder(); @@ -2675,9 +2654,8 @@ case RetEffect::Alias: { unsigned idx = RE.getIndex(); - assert (arg_end >= arg_beg); - assert (idx < (unsigned) (arg_end - arg_beg)); - SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx)); + assert (idx < callOrMsg.getNumArgs()); + SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx); state = state->BindExpr(Ex, V, false); break; } @@ -2756,25 +2734,28 @@ } assert(Summ); - evalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(), - CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred)); + evalSummary(Dst, Eng, Builder, CE, + CallOrObjCMessage(CE, Builder.GetState(Pred)), + InstanceReceiver(), *Summ,L.getAsRegion(), + Pred, Builder.GetState(Pred)); } -void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const ObjCMessageExpr* ME, - ExplodedNode* Pred, - const GRState *state) { +void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst, + ExprEngine& Eng, + StmtNodeBuilder& Builder, + ObjCMessage msg, + ExplodedNode* Pred, + const GRState *state) { RetainSummary *Summ = - ME->isInstanceMessage() - ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) - : Summaries.getClassMethodSummary(ME); + msg.isInstanceMessage() + ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext()) + : Summaries.getClassMethodSummary(msg); assert(Summ && "RetainSummary is null"); - evalSummary(Dst, Eng, Builder, ME, - InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL, - ME->arg_begin(), ME->arg_end(), Pred, state); + evalSummary(Dst, Eng, Builder, msg.getOriginExpr(), + CallOrObjCMessage(msg, Builder.GetState(Pred)), + InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL, + Pred, state); } namespace { Modified: cfe/trunk/lib/StaticAnalyzer/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CMakeLists.txt?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/CMakeLists.txt (original) +++ cfe/trunk/lib/StaticAnalyzer/CMakeLists.txt Mon Jan 24 18:03:53 2011 @@ -24,6 +24,7 @@ HTMLDiagnostics.cpp ManagerRegistry.cpp MemRegion.cpp + ObjCMessage.cpp PathDiagnostic.cpp PlistDiagnostics.cpp RangeConstraintManager.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Mon Jan 24 18:03:53 2011 @@ -42,14 +42,14 @@ // Utility functions. //===----------------------------------------------------------------------===// -static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { - if (ObjCInterfaceDecl *ID = ME->getReceiverInterface()) +static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) { + if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface()) return ID->getTypeForDecl()->getAs(); return NULL; } -static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { - if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) +static const char* GetReceiverNameType(const ObjCMessage &msg) { + if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg)) return ReceiverType->getDecl()->getIdentifier()->getNameStart(); return NULL; } @@ -69,16 +69,16 @@ namespace { class NilArgChecker : public CheckerVisitor { APIMisuse *BT; - void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg); + void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg); public: NilArgChecker() : BT(0) {} static void *getTag() { static int x = 0; return &x; } - void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); }; } void NilArgChecker::WarnNilArg(CheckerContext &C, - const clang::ObjCMessageExpr *ME, + const ObjCMessage &msg, unsigned int Arg) { if (!BT) @@ -87,24 +87,24 @@ if (ExplodedNode *N = C.generateSink()) { llvm::SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Argument to '" << GetReceiverNameType(ME) << "' method '" - << ME->getSelector().getAsString() << "' cannot be nil"; + os << "Argument to '" << GetReceiverNameType(msg) << "' method '" + << msg.getSelector().getAsString() << "' cannot be nil"; RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); - R->addRange(ME->getArg(Arg)->getSourceRange()); + R->addRange(msg.getArgSourceRange(Arg)); C.EmitReport(R); } } -void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) +void NilArgChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { - const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); + const ObjCInterfaceType *ReceiverType = GetReceiverType(msg); if (!ReceiverType) return; if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) { - Selector S = ME->getSelector(); + Selector S = msg.getSelector(); if (S.isUnarySelector()) return; @@ -127,8 +127,8 @@ Name == "compare:options:range:locale:" || Name == "componentsSeparatedByCharactersInSet:" || Name == "initWithFormat:") { - if (isNil(C.getState()->getSVal(ME->getArg(0)))) - WarnNilArg(C, ME, 0); + if (isNil(msg.getArgSVal(0, C.getState()))) + WarnNilArg(C, msg, 0); } } } @@ -441,12 +441,12 @@ static void *getTag() { static int x = 0; return &x; } - void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); }; } -void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) { +void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { if (!BT) { BT = new APIMisuse("message incorrectly sent to class instead of class " @@ -459,21 +459,12 @@ drainS = GetNullarySelector("drain", Ctx); } - ObjCInterfaceDecl *Class = 0; - - switch (ME->getReceiverKind()) { - case ObjCMessageExpr::Class: - Class = ME->getClassReceiver()->getAs()->getInterface(); - break; - case ObjCMessageExpr::SuperClass: - Class = ME->getSuperType()->getAs()->getInterface(); - break; - case ObjCMessageExpr::Instance: - case ObjCMessageExpr::SuperInstance: + if (msg.isInstanceMessage()) return; - } + const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); + assert(Class); - Selector S = ME->getSelector(); + Selector S = msg.getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; @@ -486,7 +477,7 @@ << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); - report->addRange(ME->getSourceRange()); + report->addRange(msg.getSourceRange()); C.EmitReport(report); } } Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp Mon Jan 24 18:03:53 2011 @@ -41,19 +41,21 @@ } void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); - void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); - bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); + void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); + bool evalNilReceiver(CheckerContext &C, ObjCMessage msg); private: - bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex, - const char *BT_desc, BugType *&BT); + void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, + const char *BT_desc, BugType *&BT); + bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, + const Expr *argEx, const char *BT_desc, BugType *&BT); void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); - void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, + void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, ExplodedNode *N); void HandleNilReceiver(CheckerContext &C, const GRState *state, - const ObjCMessageExpr *ME); + ObjCMessage msg); void LazyInit_BT(const char *desc, BugType *&BT) { if (!BT) @@ -78,21 +80,32 @@ C.EmitReport(R); } +void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, + CallOrObjCMessage callOrMsg, + const char *BT_desc, + BugType *&BT) { + for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) + if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), + callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), + BT_desc, BT)) + return; +} + bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, - const Expr *Ex, + SVal V, SourceRange argRange, + const Expr *argEx, const char *BT_desc, BugType *&BT) { - const SVal &V = C.getState()->getSVal(Ex); - if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { LazyInit_BT(BT_desc, BT); // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); - R->addRange(Ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + R->addRange(argRange); + if (argEx) + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx); C.EmitReport(R); } return true; @@ -172,7 +185,7 @@ // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); - R->addRange(Ex->getSourceRange()); + R->addRange(argRange); // FIXME: enhance track back for uninitialized value for arbitrary // memregions @@ -206,21 +219,18 @@ EmitBadCall(BT_call_null, C, CE); } - for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) - if (PreVisitProcessArg(C, *I, - "Function call argument is an uninitialized value", - BT_call_arg)) - return; + PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()), + "Function call argument is an uninitialized value", + BT_call_arg); } -void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) { +void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { const GRState *state = C.getState(); // FIXME: Handle 'super'? - if (const Expr *receiver = ME->getInstanceReceiver()) + if (const Expr *receiver = msg.getInstanceReceiver()) if (state->getSVal(receiver).isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_msg_undef) @@ -237,22 +247,19 @@ } // Check for any arguments that are uninitialized/undefined. - for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), - E = ME->arg_end(); I != E; ++I) - if (PreVisitProcessArg(C, *I, - "Argument in message expression " - "is an uninitialized value", BT_msg_arg)) - return; + PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), + "Argument in message expression " + "is an uninitialized value", BT_msg_arg); } bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C, - const ObjCMessageExpr *ME) { - HandleNilReceiver(C, C.getState(), ME); + ObjCMessage msg) { + HandleNilReceiver(C, C.getState(), msg); return true; // Nil receiver is not handled elsewhere. } void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, - const ObjCMessageExpr *ME, + const ObjCMessage &msg, ExplodedNode *N) { if (!BT_msg_ret) @@ -262,12 +269,12 @@ llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "The receiver of message '" << ME->getSelector().getAsString() + os << "The receiver of message '" << msg.getSelector().getAsString() << "' is nil and returns a value of type '" - << ME->getType().getAsString() << "' that will be garbage"; + << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); - if (const Expr *receiver = ME->getInstanceReceiver()) { + if (const Expr *receiver = msg.getInstanceReceiver()) { report->addRange(receiver->getSourceRange()); report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, receiver); @@ -284,22 +291,22 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const GRState *state, - const ObjCMessageExpr *ME) { + ObjCMessage msg) { + ASTContext &Ctx = C.getASTContext(); // Check the return type of the message expression. A message to nil will // return different values depending on the return type and the architecture. - QualType RetTy = ME->getType(); + QualType RetTy = msg.getType(Ctx); - ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); if (CanRetTy->isStructureOrClassType()) { // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead // have the "use of undefined value" be smarter about where the // undefined value came from. - if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){ if (ExplodedNode* N = C.generateSink(state)) - emitNilReceiverBug(C, ME, N); + emitNilReceiverBug(C, msg, N); return; } @@ -311,7 +318,7 @@ // Other cases: check if the return type is smaller than void*. if (CanRetTy != Ctx.VoidTy && - C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) { // Compute: sizeof(void *) and sizeof(return type) const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); @@ -324,7 +331,7 @@ Ctx.LongLongTy == CanRetTy || Ctx.UnsignedLongLongTy == CanRetTy))) { if (ExplodedNode* N = C.generateSink(state)) - emitNilReceiverBug(C, ME, N); + emitNilReceiverBug(C, msg, N); return; } @@ -341,8 +348,8 @@ // it most likely isn't nil. We should assume the semantics // of this case unless we have *a lot* more knowledge. // - SVal V = C.getSValBuilder().makeZeroVal(ME->getType()); - C.generateNode(state->BindExpr(ME, V)); + SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); + C.generateNode(state->BindExpr(msg.getOriginExpr(), V)); return; } Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Mon Jan 24 18:03:53 2011 @@ -145,10 +145,49 @@ // automatically. } -void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred) { +void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg, + ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, + bool isPrevisit) { + + if (Checkers.empty()) { + Dst.insert(Src); + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } + + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg, + *NI, tag, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} + +void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { bool evaluated = false; ExplodedNodeSet DstTmp; @@ -156,7 +195,7 @@ void *tag = I->first; Checker *checker = I->second; - if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, + if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state, tag)) { evaluated = true; break; @@ -2263,7 +2302,7 @@ // Now that the arguments are processed, handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback); + CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; @@ -2305,7 +2344,7 @@ Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, notNilState); + evalObjCMessage(dstEval, ME, Pred, notNilState); } else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { IdentifierInfo* ClsName = Iface->getIdentifier(); @@ -2353,7 +2392,7 @@ Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred)); + evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred)); } // Handle the case where no nodes where generated. Auto-generate that @@ -2365,7 +2404,7 @@ // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback); + CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false); } //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp Mon Jan 24 18:03:53 2011 @@ -39,7 +39,7 @@ return &x; } - void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); }; } // end anonymous namespace @@ -54,10 +54,10 @@ } void -NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) { +NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { - const Expr *receiver = ME->getInstanceReceiver(); + const Expr *receiver = msg.getInstanceReceiver(); if (!receiver) return; @@ -75,13 +75,13 @@ return; // Sending 'release' message? - if (ME->getSelector() != releaseS) + if (msg.getSelector() != releaseS) return; - SourceRange R = ME->getSourceRange(); + SourceRange R = msg.getSourceRange(); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " - "and garbage collection", ME->getLocStart(), &R, 1); + "and garbage collection", R.getBegin(), &R, 1); } Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp?rev=124159&r1=124158&r2=124159&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Mon Jan 24 18:03:53 2011 @@ -58,7 +58,7 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); static bool isInitializationMethod(const ObjCMethodDecl *MD); -static bool isInitMessage(const ObjCMessageExpr *E); +static bool isInitMessage(const ObjCMessage &msg); static bool isSelfVar(SVal location, CheckerContext &C); namespace { @@ -82,7 +82,7 @@ public: static void *getTag() { static int tag = 0; return &tag; } - void PostVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *E); + void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg); void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE); @@ -176,8 +176,8 @@ C.EmitReport(report); } -void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *E) { +void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { // When encountering a message that does initialization (init rule), // tag the return value so that we know later on that if self has this value // then it is properly initialized. @@ -187,10 +187,10 @@ C.getCurrentAnalysisContext()->getDecl()))) return; - if (isInitMessage(E)) { + if (isInitMessage(msg)) { // Tag the return value as the result of an initializer. const GRState *state = C.getState(); - SVal V = state->getSVal(E); + SVal V = state->getSVal(msg.getOriginExpr()); addSelfFlag(V, SelfFlag_InitRes, C); return; } @@ -301,6 +301,6 @@ /*ignorePrefix=*/false) == cocoa::InitRule; } -static bool isInitMessage(const ObjCMessageExpr *E) { - return cocoa::deriveNamingConvention(E->getSelector()) == cocoa::InitRule; +static bool isInitMessage(const ObjCMessage &msg) { + return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule; } Added: cfe/trunk/lib/StaticAnalyzer/ObjCMessage.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/ObjCMessage.cpp?rev=124159&view=auto ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/ObjCMessage.cpp (added) +++ cfe/trunk/lib/StaticAnalyzer/ObjCMessage.cpp Mon Jan 24 18:03:53 2011 @@ -0,0 +1,99 @@ +//===- ObjCMessage.cpp - Wrapper for ObjC messages and dot syntax -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ObjCMessage which serves as a common wrapper for ObjC +// message expressions or implicit messages for loading/storing ObjC properties. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h" + +using namespace clang; +using namespace ento; + +QualType ObjCMessage::getType(ASTContext &ctx) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getType(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (isPropertySetter()) + return ctx.VoidTy; + return propE->getType(); +} + +Selector ObjCMessage::getSelector() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getSelector(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (isPropertySetter()) + return propE->getSetterSelector(); + return propE->getGetterSelector(); +} + +const ObjCMethodDecl *ObjCMessage::getMethodDecl() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getMethodDecl(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (propE->isImplicitProperty()) + return isPropertySetter() ? propE->getImplicitPropertySetter() + : propE->getImplicitPropertyGetter(); + return 0; +} + +const ObjCInterfaceDecl *ObjCMessage::getReceiverInterface() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getReceiverInterface(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (propE->isClassReceiver()) + return propE->getClassReceiver(); + QualType recT; + if (const Expr *recE = getInstanceReceiver()) + recT = recE->getType(); + else { + assert(propE->isSuperReceiver()); + recT = propE->getSuperReceiverType(); + } + if (const ObjCObjectPointerType *Ptr = recT->getAs()) + return Ptr->getInterfaceDecl(); + return 0; +} + +const Expr *ObjCMessage::getArgExpr(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getArg(i); + assert(isPropertySetter()); + if (const BinaryOperator *bop = dyn_cast(OriginE)) + if (bop->isAssignmentOp()) + return bop->getRHS(); + return 0; +} + +QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { + if (CallE) { + const Expr *Callee = CallE->getCallee(); + if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) + return FD->getResultType(); + return CallE->getType(); + } + return Msg.getResultType(ctx); +} + +SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i)); + QualType argT = Msg.getArgType(i); + if (Loc::IsLocType(argT) || argT->isIntegerType()) + return Msg.getArgSVal(i, State); + return UnknownVal(); +} From akyrtzi at gmail.com Mon Jan 24 16:03:57 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 00:03:57 -0000 Subject: [cfe-commits] r124160 - in /cfe/trunk: include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Checkers/ExprEngine.cpp Message-ID: <20110125000357.E9B942A6C12F@llvm.org> Author: akirtzidis Date: Mon Jan 24 18:03:57 2011 New Revision: 124160 URL: http://llvm.org/viewvc/llvm-project?rev=124160&view=rev Log: [analyzer] Introduce ExprEngine::VisitObjCMessage for handling general ObjCMessages (both message expressions and property access) and use it in ExprEngine::VisitObjCMessageExpr. Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h?rev=124160&r1=124159&r2=124160&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h Mon Jan 24 18:03:57 2011 @@ -391,6 +391,8 @@ /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Src, + ExplodedNodeSet& Dst); /// VisitReturnStmt - Transfer function logic for return statements. void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred, Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124160&r1=124159&r2=124160&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Mon Jan 24 18:03:57 2011 @@ -2300,9 +2300,16 @@ WL.push_back(ObjCMsgWLItem(Item.I, *NI)); } - // Now that the arguments are processed, handle the previsits checks. + // Now that the arguments are processed, handle the ObjC message. + VisitObjCMessage(ME, ArgsEvaluated, Dst); +} + +void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, + ExplodedNodeSet &Src, ExplodedNodeSet& Dst) { + + // Handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true); + CheckerVisitObjCMessage(msg, DstPrevisit, Src, /*isPreVisit=*/true); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; @@ -2310,13 +2317,13 @@ for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(), DE = DstPrevisit.end(); DI != DE; ++DI) { - Pred = *DI; + ExplodedNode *Pred = *DI; bool RaisesException = false; unsigned oldSize = dstEval.size(); SaveAndRestore OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->hasGeneratedNode); - if (const Expr *Receiver = ME->getInstanceReceiver()) { + if (const Expr *Receiver = msg.getInstanceReceiver()) { const GRState *state = GetState(Pred); // Bifurcate the state into nil and non-nil ones. @@ -2329,13 +2336,13 @@ // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We handle must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - CheckerEvalNilReceiver(ME, dstEval, nilState, Pred); + CheckerEvalNilReceiver(msg, dstEval, nilState, Pred); continue; } // Check if the "raise" message was sent. assert(notNilState); - if (ME->getSelector() == RaiseSel) + if (msg.getSelector() == RaiseSel) RaisesException = true; // Check if we raise an exception. For now treat these as sinks. @@ -2344,11 +2351,11 @@ Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, ME, Pred, notNilState); + evalObjCMessage(dstEval, msg, Pred, notNilState); } - else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { + else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { IdentifierInfo* ClsName = Iface->getIdentifier(); - Selector S = ME->getSelector(); + Selector S = msg.getSelector(); // Check for special instance methods. if (!NSExceptionII) { @@ -2392,19 +2399,19 @@ Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred)); + evalObjCMessage(dstEval, msg, Pred, Builder->GetState(Pred)); } // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && dstEval.size() == oldSize && !Builder->hasGeneratedNode) - MakeNode(dstEval, ME, Pred, GetState(Pred)); + MakeNode(dstEval, msg.getOriginExpr(), Pred, GetState(Pred)); } // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false); + CheckerVisitObjCMessage(msg, Dst, dstEval, /*isPreVisit=*/false); } //===----------------------------------------------------------------------===// From akyrtzi at gmail.com Mon Jan 24 16:04:03 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 00:04:03 -0000 Subject: [cfe-commits] r124161 - in /cfe/trunk: include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h include/clang/StaticAnalyzer/PathSensitive/SVals.h lib/StaticAnalyzer/BasicStore.cpp lib/StaticAnalyzer/CFRefCount.cpp lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp lib/StaticAnalyzer/Checkers/ExprEngine.cpp lib/StaticAnalyzer/RegionStore.cpp lib/StaticAnalyzer/SVals.cpp test/Analysis/properties.m Message-ID: <20110125000403.697B12A6C12E@llvm.org> Author: akirtzidis Date: Mon Jan 24 18:04:03 2011 New Revision: 124161 URL: http://llvm.org/viewvc/llvm-project?rev=124161&view=rev Log: [analyzer] Handle the dot syntax for properties in the ExprEngine. We translate property accesses to obj-c messages by simulating "loads" or "stores" to properties using a pseudo-location SVal kind (ObjCPropRef). Checkers can now reason about obj-c messages for both explicit message expressions and implicit messages due to property accesses. Added: cfe/trunk/test/Analysis/properties.m Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/SVals.h cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/RegionStore.cpp cfe/trunk/lib/StaticAnalyzer/SVals.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h Mon Jan 24 18:04:03 2011 @@ -375,6 +375,9 @@ void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); + void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + /// Transfer function logic for computing the lvalue of an Objective-C ivar. void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst); Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/SVals.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/SVals.h?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/SVals.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/SVals.h Mon Jan 24 18:04:03 2011 @@ -427,7 +427,7 @@ namespace loc { -enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind, ObjCPropRefKind }; class GotoLabel : public Loc { public: @@ -505,6 +505,28 @@ } }; +/// \brief Pseudo-location SVal used by the ExprEngine to simulate a "load" or +/// "store" of an ObjC property for the dot syntax. +class ObjCPropRef : public Loc { +public: + explicit ObjCPropRef(const ObjCPropertyRefExpr *E) + : Loc(ObjCPropRefKind, E) {} + + const ObjCPropertyRefExpr *getPropRefExpr() const { + return static_cast(Data); + } + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ObjCPropRefKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ObjCPropRefKind; + } +}; + } // end ento::loc namespace } // end GR namespace Modified: cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp Mon Jan 24 18:04:03 2011 @@ -196,6 +196,7 @@ return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T); } + case loc::ObjCPropRefKind: case loc::ConcreteIntKind: // Support direct accesses to memory. It's up to individual checkers // to flag an error. Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Mon Jan 24 18:04:03 2011 @@ -2033,9 +2033,10 @@ else os << "function call"; } - else { - assert (isa(S)); + else if (isa(S)) { os << "Method"; + } else { + os << "Property"; } if (CurrV.getObjKind() == RetEffect::CF) { Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp Mon Jan 24 18:04:03 2011 @@ -246,10 +246,11 @@ return; } + const char *bugDesc = msg.isPropertySetter() ? + "Argument for property setter is an uninitialized value" + : "Argument in message expression is an uninitialized value"; // Check for any arguments that are uninitialized/undefined. - PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), - "Argument in message expression " - "is an uninitialized value", BT_msg_arg); + PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg); } bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C, Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Mon Jan 24 18:04:03 2011 @@ -865,6 +865,10 @@ VisitObjCAtSynchronizedStmt(cast(S), Pred, Dst); break; + case Stmt::ObjCPropertyRefExprClass: + VisitObjCPropertyRefExpr(cast(S), Pred, Dst); + break; + // Cases not handled yet; but will handle some day. case Stmt::DesignatedInitExprClass: case Stmt::ExtVectorElementExprClass: @@ -875,7 +879,6 @@ case Stmt::ObjCAtTryStmtClass: case Stmt::ObjCEncodeExprClass: case Stmt::ObjCIsaExprClass: - case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCProtocolExprClass: case Stmt::ObjCSelectorExprClass: case Stmt::ObjCStringLiteralClass: @@ -1799,6 +1802,17 @@ assert(Builder && "StmtNodeBuilder must be defined."); + // Proceed with the store. We use AssignE as the anchor for the PostStore + // ProgramPoint if it is non-NULL, and LocationE otherwise. + const Expr *StoreE = AssignE ? AssignE : LocationE; + + if (isa(location)) { + loc::ObjCPropRef prop = cast(location); + ExplodedNodeSet src = Pred; + return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(), + StoreE, Val), src, Dst); + } + // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; evalLocation(Tmp, LocationE, Pred, state, location, tag, false); @@ -1811,10 +1825,6 @@ SaveAndRestore OldSPointKind(Builder->PointKind, ProgramPoint::PostStoreKind); - // Proceed with the store. We use AssignE as the anchor for the PostStore - // ProgramPoint if it is non-NULL, and LocationE otherwise. - const Expr *StoreE = AssignE ? AssignE : LocationE; - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); } @@ -1825,6 +1835,13 @@ const void *tag, QualType LoadTy) { assert(!isa(location) && "location cannot be a NonLoc."); + if (isa(location)) { + loc::ObjCPropRef prop = cast(location); + ExplodedNodeSet src = Pred; + return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex), + src, Dst); + } + // Are we loading from a region? This actually results in two loads; one // to fetch the address of the referenced value and one to fetch the // referenced value. @@ -2048,6 +2065,34 @@ } //===----------------------------------------------------------------------===// +// Transfer function: Objective-C dot-syntax to access a property. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + // Visit the base expression, which is needed for computing the lvalue + // of the ivar. + ExplodedNodeSet dstBase; + const Expr *baseExpr = Ex->getBase(); + Visit(baseExpr, Pred, dstBase); + + ExplodedNodeSet dstPropRef; + + // Using the base, compute the lvalue of the instance variable. + for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); + I!=E; ++I) { + ExplodedNode *nodeBase = *I; + const GRState *state = GetState(nodeBase); + SVal baseVal = state->getSVal(baseExpr); + MakeNode(dstPropRef, Ex, *I, state->BindExpr(Ex, loc::ObjCPropRef(Ex))); + } + + Dst.insert(dstPropRef); +} + +//===----------------------------------------------------------------------===// // Transfer function: Objective-C ivar references. //===----------------------------------------------------------------------===// @@ -2426,7 +2471,8 @@ ExplodedNodeSet S2; CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); - if (CastE->getCastKind() == CK_LValueToRValue) { + if (CastE->getCastKind() == CK_LValueToRValue || + CastE->getCastKind() == CK_GetObjCProperty) { for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; const GRState *state = GetState(subExprNode); Modified: cfe/trunk/lib/StaticAnalyzer/RegionStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/RegionStore.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/RegionStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/RegionStore.cpp Mon Jan 24 18:04:03 2011 @@ -985,6 +985,9 @@ if (isa(L)) { return UnknownVal(); } + if (!isa(L)) { + return UnknownVal(); + } const MemRegion *MR = cast(L).getRegion(); Modified: cfe/trunk/lib/StaticAnalyzer/SVals.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/SVals.cpp?rev=124161&r1=124160&r2=124161&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/SVals.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/SVals.cpp Mon Jan 24 18:04:03 2011 @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/PathSensitive/GRState.h" +#include "clang/AST/ExprObjC.h" #include "clang/Basic/IdentifierTable.h" using namespace clang; @@ -354,6 +355,22 @@ case loc::MemRegionKind: os << '&' << cast(this)->getRegion()->getString(); break; + case loc::ObjCPropRefKind: { + const ObjCPropertyRefExpr *E = cast(this)->getPropRefExpr(); + os << "objc-prop{"; + if (E->isSuperReceiver()) + os << "super."; + else if (E->getBase()) + os << "."; + + if (E->isImplicitProperty()) + os << E->getImplicitPropertyGetter()->getSelector().getAsString(); + else + os << E->getExplicitProperty()->getName(); + + os << "}"; + break; + } default: assert(false && "Pretty-printing not implemented for this Loc."); break; Added: cfe/trunk/test/Analysis/properties.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/properties.m?rev=124161&view=auto ============================================================================== --- cfe/trunk/test/Analysis/properties.m (added) +++ cfe/trunk/test/Analysis/properties.m Mon Jan 24 18:04:03 2011 @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; + at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; + at protocol NSObject - (BOOL)isEqual:(id)object; @end + at protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end + at protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end + at protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end + at interface NSObject {} ++(id)alloc; +-(id)init; +-(id)autorelease; +-(id)copy; +-(id)retain; + at end + at interface NSString : NSObject +- (NSUInteger)length; +-(id)initWithFormat:(NSString *)f,...; +-(BOOL)isEqualToString:(NSString *)s; ++ (id)string; + at end + at interface NSNumber : NSObject {} ++(id)alloc; +-(id)initWithInteger:(int)i; + at end + +// rdar://6946338 + + at interface Test1 : NSObject { + NSString *text; +} +-(id)myMethod; + at property (nonatomic, assign) NSString *text; + at end + + + at implementation Test1 + + at synthesize text; + +-(id)myMethod { + Test1 *cell = [[[Test1 alloc] init] autorelease]; + + NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}} + cell.text = string1; + + return cell; +} + + at end + + +// rdar://8824416 + + at interface MyNumber : NSObject +{ + NSNumber* _myNumber; +} + +- (id)initWithNumber:(NSNumber *)number; + + at property (nonatomic, readonly) NSNumber* myNumber; + at property (nonatomic, readonly) NSNumber* newMyNumber; + + at end + + at implementation MyNumber + at synthesize myNumber=_myNumber; + +- (id)initWithNumber:(NSNumber *)number +{ + self = [super init]; + + if ( self ) + { + _myNumber = [number copy]; + } + + return self; +} + +- (NSNumber*)newMyNumber +{ + if ( _myNumber ) + return [_myNumber retain]; + + return [[NSNumber alloc] initWithInteger:1]; +} + +- (id)valueForUndefinedKey:(NSString*)key +{ + id value = 0; + + if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"]) + value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained. + else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"]) + value = [self.myNumber retain]; // this line fixes the over release + else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"]) + value = self.newMyNumber; // this one is ok, since value is returned retained + else + value = [[NSNumber alloc] initWithInteger:0]; + + return [value autorelease]; // expected-warning {{Object sent -autorelease too many times}} +} + + at end + +NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber) +{ + NSNumber* result = aMyNumber.myNumber; + + return [result autorelease]; // expected-warning {{Object sent -autorelease too many times}} +} + + +// rdar://6611873 + + at interface Person : NSObject { + NSString *_name; +} + at property (retain) NSString * name; + at end + + at implementation Person + at synthesize name = _name; + at end + +void rdar6611873() { + Person *p = [[[Person alloc] init] autorelease]; + + p.name = [[NSString string] retain]; // expected-warning {{leak}} + p.name = [[NSString alloc] init]; // expected-warning {{leak}} +} From dgregor at apple.com Mon Jan 24 17:15:41 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 01:15:41 -0000 Subject: [cfe-commits] [libcxx] r124166 - in /libcxx/trunk: include/type_traits test/utilities/meta/meta.rel/is_convertible.pass.cpp Message-ID: <20110125011541.DF4662A6C130@llvm.org> Author: dgregor Date: Mon Jan 24 19:15:41 2011 New Revision: 124166 URL: http://llvm.org/viewvc/llvm-project?rev=124166&view=rev Log: Eliminate the C++0x-only is_convertible testing function that accepts a cv-qualifier rvalue reference to the type, e.g., template char __test(const volatile typename remove_reference<_Tp>::type&&); The use of this function signature rather than the more straightforward one used in C++98/03 mode, e.g., template char __test(_Tp); is broken in two ways: 1) An rvalue reference cannot bind to lvalues, so is_convertible::value would be false. This breaks two of the unique_ptr tests on Clang and GCC >= 4.5. Prior GCC's seem to have allowed rvalue references to bind to lvalues, allowing this bug to slip in. 2) By adding cv-qualifiers to the type we're converting to, we get some incorrect "true" results for, e.g., is_convertible::value. Modified: libcxx/trunk/include/type_traits libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124166&r1=124165&r2=124166&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Mon Jan 24 19:15:41 2011 @@ -600,11 +600,7 @@ namespace __is_convertible_imp { -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES -template char __test(const volatile typename remove_reference<_Tp>::type&&); -#else template char __test(_Tp); -#endif template __two __test(...); #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES template _Tp&& __source(); Modified: libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp?rev=124166&r1=124165&r2=124166&view=diff ============================================================================== --- libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp (original) +++ libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Mon Jan 24 19:15:41 2011 @@ -16,6 +16,10 @@ typedef void Function(); typedef char Array[1]; +class NonCopyable { + NonCopyable(NonCopyable&); +}; + int main() { { @@ -366,4 +370,15 @@ static_assert((!std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); } + { + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((std::is_convertible::value), ""); + static_assert((!std::is_convertible::value), ""); + } } From hhinnant at apple.com Mon Jan 24 18:07:35 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Mon, 24 Jan 2011 21:07:35 -0500 Subject: [cfe-commits] [libcxx] r124166 - in /libcxx/trunk: include/type_traits test/utilities/meta/meta.rel/is_convertible.pass.cpp In-Reply-To: <20110125011541.DF4662A6C130@llvm.org> References: <20110125011541.DF4662A6C130@llvm.org> Message-ID: <47BE01B1-9CD4-425F-AC50-80A183FA168E@apple.com> Thanks Doug. Ultimately I'd like to see is_convertible mapped into a compiler intrinsic. -Howard On Jan 24, 2011, at 8:15 PM, Douglas Gregor wrote: > Author: dgregor > Date: Mon Jan 24 19:15:41 2011 > New Revision: 124166 > > URL: http://llvm.org/viewvc/llvm-project?rev=124166&view=rev > Log: > Eliminate the C++0x-only is_convertible testing function that accepts > a cv-qualifier rvalue reference to the type, e.g., > > template char __test(const volatile typename remove_reference<_Tp>::type&&); > > The use of this function signature rather than the more > straightforward one used in C++98/03 mode, e.g., > > template char __test(_Tp); > > is broken in two ways: > > 1) An rvalue reference cannot bind to lvalues, so is_convertible X&>::value would be false. This breaks two of the unique_ptr tests > on Clang and GCC >= 4.5. Prior GCC's seem to have allowed rvalue > references to bind to lvalues, allowing this bug to slip in. > > 2) By adding cv-qualifiers to the type we're converting to, we get > some incorrect "true" results for, e.g., is_convertible::value. > > > > > Modified: > libcxx/trunk/include/type_traits > libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp > > Modified: libcxx/trunk/include/type_traits > URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124166&r1=124165&r2=124166&view=diff > ============================================================================== > --- libcxx/trunk/include/type_traits (original) > +++ libcxx/trunk/include/type_traits Mon Jan 24 19:15:41 2011 > @@ -600,11 +600,7 @@ > > namespace __is_convertible_imp > { > -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES > -template char __test(const volatile typename remove_reference<_Tp>::type&&); > -#else > template char __test(_Tp); > -#endif > template __two __test(...); > #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES > template _Tp&& __source(); > > Modified: libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp > URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp?rev=124166&r1=124165&r2=124166&view=diff > ============================================================================== > --- libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp (original) > +++ libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Mon Jan 24 19:15:41 2011 > @@ -16,6 +16,10 @@ > typedef void Function(); > typedef char Array[1]; > > +class NonCopyable { > + NonCopyable(NonCopyable&); > +}; > + > int main() > { > { > @@ -366,4 +370,15 @@ > static_assert((!std::is_convertible::value), ""); > static_assert(( std::is_convertible::value), ""); > } > + { > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((std::is_convertible::value), ""); > + static_assert((!std::is_convertible::value), ""); > + } > } > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From dgregor at apple.com Mon Jan 24 18:17:32 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 02:17:32 -0000 Subject: [cfe-commits] r124169 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td lib/Lex/PPMacroExpansion.cpp lib/Parse/ParseDecl.cpp test/Lexer/has_feature_cxx0x.cpp test/Parser/cxx-reference.cpp Message-ID: <20110125021732.553CD2A6C130@llvm.org> Author: dgregor Date: Mon Jan 24 20:17:32 2011 New Revision: 124169 URL: http://llvm.org/viewvc/llvm-project?rev=124169&view=rev Log: Downgrade the error about rvalue references to an extension warning and turn on __has_feature(cxx_rvalue_references). The core rvalue references proposal seems to be fully implemented now, pending lots more testing. Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/test/Lexer/has_feature_cxx0x.cpp cfe/trunk/test/Parser/cxx-reference.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=124169&r1=124168&r2=124169&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jan 24 20:17:32 2011 @@ -158,10 +158,10 @@ "'%0' qualifier may not be applied to a reference">; def err_illegal_decl_reference_to_reference : Error< "%0 declared as a reference to a reference">; -def err_rvalue_reference : Error< - "rvalue references are only allowed in C++0x">; -def ext_inline_namespace : Extension< - "inline namespaces are a C++0x feature">; +def ext_rvalue_reference : ExtWarn< + "rvalue references are a C++0x extension">, InGroup; +def ext_inline_namespace : ExtWarn< + "inline namespaces are a C++0x feature">, InGroup; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124169&r1=124168&r2=124169&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Mon Jan 24 20:17:32 2011 @@ -555,10 +555,10 @@ .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) - .Case("cxx_inline_namespaces", true) + .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) //.Case("cxx_lambdas", false) //.Case("cxx_nullptr", false) - //.Case("cxx_rvalue_references", false) + .Case("cxx_rvalue_references", LangOpts.CPlusPlus) .Case("cxx_variadic_templates", LangOpts.CPlusPlus) .Case("tls", PP.getTargetInfo().isTLSSupported()) .Default(false); Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124169&r1=124168&r2=124169&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jan 24 20:17:32 2011 @@ -2722,7 +2722,7 @@ // Complain about rvalue references in C++03, but then go on and build // the declarator. if (Kind == tok::ampamp && !getLang().CPlusPlus0x) - Diag(Loc, diag::err_rvalue_reference); + Diag(Loc, diag::ext_rvalue_reference); // C++ 8.3.2p1: cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef or of a Modified: cfe/trunk/test/Lexer/has_feature_cxx0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/has_feature_cxx0x.cpp?rev=124169&r1=124168&r2=124169&view=diff ============================================================================== --- cfe/trunk/test/Lexer/has_feature_cxx0x.cpp (original) +++ cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Mon Jan 24 20:17:32 2011 @@ -77,8 +77,8 @@ int no_rvalue_references(); #endif -// CHECK-0X: no_rvalue_references -// CHECK-NO-0X: no_rvalue_references +// CHECK-0X: rvalue_references +// CHECK-NO-0X: rvalue_references #if __has_feature(cxx_variadic_templates) Modified: cfe/trunk/test/Parser/cxx-reference.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-reference.cpp?rev=124169&r1=124168&r2=124169&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx-reference.cpp (original) +++ cfe/trunk/test/Parser/cxx-reference.cpp Mon Jan 24 20:17:32 2011 @@ -18,4 +18,4 @@ int & const volatile Z = val; /* expected-error {{'const' qualifier may not be applied}} \ expected-error {{'volatile' qualifier may not be applied}} */ -typedef int && RV; // expected-error {{rvalue references are only allowed in C++0x}} +typedef int && RV; // expected-warning {{rvalue references are a C++0x extension}} From dgregor at apple.com Mon Jan 24 18:30:52 2011 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 24 Jan 2011 18:30:52 -0800 Subject: [cfe-commits] [libcxx] r124166 - in /libcxx/trunk: include/type_traits test/utilities/meta/meta.rel/is_convertible.pass.cpp In-Reply-To: <47BE01B1-9CD4-425F-AC50-80A183FA168E@apple.com> References: <20110125011541.DF4662A6C130@llvm.org> <47BE01B1-9CD4-425F-AC50-80A183FA168E@apple.com> Message-ID: <5EE6FFEC-A298-46EB-B27E-2A532690597F@apple.com> On Jan 24, 2011, at 6:07 PM, Howard Hinnant wrote: > Thanks Doug. > > Ultimately I'd like to see is_convertible mapped into a compiler intrinsic. Yeah, I agree that that would make sense. But, not until we've knocked off a few more C++0x features that libc++ needs! - Doug > -Howard > > On Jan 24, 2011, at 8:15 PM, Douglas Gregor wrote: > >> Author: dgregor >> Date: Mon Jan 24 19:15:41 2011 >> New Revision: 124166 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=124166&view=rev >> Log: >> Eliminate the C++0x-only is_convertible testing function that accepts >> a cv-qualifier rvalue reference to the type, e.g., >> >> template char __test(const volatile typename remove_reference<_Tp>::type&&); >> >> The use of this function signature rather than the more >> straightforward one used in C++98/03 mode, e.g., >> >> template char __test(_Tp); >> >> is broken in two ways: >> >> 1) An rvalue reference cannot bind to lvalues, so is_convertible> X&>::value would be false. This breaks two of the unique_ptr tests >> on Clang and GCC >= 4.5. Prior GCC's seem to have allowed rvalue >> references to bind to lvalues, allowing this bug to slip in. >> >> 2) By adding cv-qualifiers to the type we're converting to, we get >> some incorrect "true" results for, e.g., is_convertible::value. >> >> >> >> >> Modified: >> libcxx/trunk/include/type_traits >> libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp >> >> Modified: libcxx/trunk/include/type_traits >> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124166&r1=124165&r2=124166&view=diff >> ============================================================================== >> --- libcxx/trunk/include/type_traits (original) >> +++ libcxx/trunk/include/type_traits Mon Jan 24 19:15:41 2011 >> @@ -600,11 +600,7 @@ >> >> namespace __is_convertible_imp >> { >> -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES >> -template char __test(const volatile typename remove_reference<_Tp>::type&&); >> -#else >> template char __test(_Tp); >> -#endif >> template __two __test(...); >> #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES >> template _Tp&& __source(); >> >> Modified: libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp >> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp?rev=124166&r1=124165&r2=124166&view=diff >> ============================================================================== >> --- libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp (original) >> +++ libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Mon Jan 24 19:15:41 2011 >> @@ -16,6 +16,10 @@ >> typedef void Function(); >> typedef char Array[1]; >> >> +class NonCopyable { >> + NonCopyable(NonCopyable&); >> +}; >> + >> int main() >> { >> { >> @@ -366,4 +370,15 @@ >> static_assert((!std::is_convertible::value), ""); >> static_assert(( std::is_convertible::value), ""); >> } >> + { >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((std::is_convertible::value), ""); >> + static_assert((!std::is_convertible::value), ""); >> + } >> } >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Mon Jan 24 19:31:58 2011 From: rjmccall at apple.com (John McCall) Date: Tue, 25 Jan 2011 03:31:58 -0000 Subject: [cfe-commits] r124174 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/Analysis/retain-release.m Message-ID: <20110125033158.7884A2A6C130@llvm.org> Author: rjmccall Date: Mon Jan 24 21:31:58 2011 New Revision: 124174 URL: http://llvm.org/viewvc/llvm-project?rev=124174&view=rev Log: Add the ns_consumes_self, ns_consumed, cf_consumed, and ns_returns_autoreleased attributes for the benefit of the static analyzer. Modified: 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/test/Analysis/retain-release.m Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Mon Jan 24 21:31:58 2011 @@ -146,10 +146,17 @@ def CFReturnsRetained : InheritableAttr { let Spellings = ["cf_returns_retained"]; + let Subjects = [ObjCMethod, Function]; } def CFReturnsNotRetained : InheritableAttr { let Spellings = ["cf_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def CFConsumed : InheritableAttr { + let Spellings = ["cf_consumed"]; + let Subjects = [ParmVar]; } def Cleanup : InheritableAttr { @@ -326,10 +333,27 @@ def NSReturnsRetained : InheritableAttr { let Spellings = ["ns_returns_retained"]; + let Subjects = [ObjCMethod, Function]; } def NSReturnsNotRetained : InheritableAttr { let Spellings = ["ns_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def NSReturnsAutoreleased : InheritableAttr { + let Spellings = ["ns_returns_autoreleased"]; + let Subjects = [ObjCMethod, Function]; +} + +def NSConsumesSelf : InheritableAttr { + let Spellings = ["ns_consumes_self"]; + let Subjects = [ObjCMethod]; +} + +def NSConsumed : InheritableAttr { + let Spellings = ["ns_consumed"]; + let Subjects = [ParmVar]; } def ObjCException : InheritableAttr { @@ -337,7 +361,7 @@ } def ObjCNSObject : InheritableAttr { - let Spellings = ["NSOjbect"]; + let Spellings = ["NSObject"]; } def Overloadable : Attr { Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 24 21:31:58 2011 @@ -1040,15 +1040,15 @@ def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" "variable and function|function or method|parameter|" - "parameter or Objective-C method |function, method or block|" + "parameter or Objective-C method|function, method or block|" "virtual method or class|function, method, or parameter|class|virtual method" - "|member|variable}1 types">; + "|member|variable|method}1 types">; def err_attribute_wrong_decl_type : Error< "%0 attribute only applies to %select{function|union|" "variable and function|function or method|parameter|" - "parameter or Objective-C method |function, method or block|" + "parameter or Objective-C method|function, method or block|" "virtual method or class|function, method, or parameter|class|virtual method" - "|member|variable}1 types">; + "|member|variable|method}1 types">; def warn_function_attribute_wrong_type : Warning< "%0 only applies to function types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< @@ -1179,8 +1179,11 @@ def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; def warn_ns_attribute_wrong_return_type : Warning< - "%0 attribute only applies to functions or methods that " - "return a pointer or Objective-C object">; + "%0 attribute only applies to %select{functions|methods}1 that " + "return %select{an Objective-C object|a pointer}2">; +def warn_ns_attribute_wrong_parameter_type : Warning< + "%0 attribute only applies to %select{Objective-C object|pointer}1 " + "parameters">; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; Modified: cfe/trunk/include/clang/Sema/AttributeList.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/AttributeList.h (original) +++ cfe/trunk/include/clang/Sema/AttributeList.h Mon Jan 24 21:31:58 2011 @@ -129,6 +129,10 @@ AT_cf_returns_retained, // Clang-specific. AT_ns_returns_not_retained, // Clang-specific. AT_ns_returns_retained, // Clang-specific. + AT_ns_returns_autoreleased, // Clang-specific. + AT_cf_consumed, // Clang-specific. + AT_ns_consumed, // Clang-specific. + AT_ns_consumes_self, // Clang-specific. AT_objc_gc, AT_overloadable, // Clang-specific. AT_ownership_holds, // Clang-specific. Modified: cfe/trunk/lib/Sema/AttributeList.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AttributeList.cpp (original) +++ cfe/trunk/lib/Sema/AttributeList.cpp Mon Jan 24 21:31:58 2011 @@ -105,8 +105,12 @@ .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) .Case("carries_dependency", AT_carries_dependency) + .Case("ns_consumed", AT_ns_consumed) + .Case("ns_consumes_self", AT_ns_consumes_self) + .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_consumed", AT_cf_consumed) .Case("cf_returns_not_retained", AT_cf_returns_not_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("ownership_returns", AT_ownership_returns) Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Jan 24 21:31:58 2011 @@ -2441,48 +2441,116 @@ // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// -static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, +static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { + return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); +} +static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { + return type->isPointerType() || isValidSubjectOfNSAttribute(S, type); +} + +static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) { + ParmVarDecl *param = dyn_cast(d); + if (!param) { + S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/; + return; + } + + bool typeOK, cf; + if (attr.getKind() == AttributeList::AT_ns_consumed) { + typeOK = isValidSubjectOfNSAttribute(S, param->getType()); + cf = false; + } else { + typeOK = isValidSubjectOfCFAttribute(S, param->getType()); + cf = true; + } + + if (!typeOK) { + S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << SourceRange(attr.getLoc()) << attr.getName() << cf; + return; + } + + if (cf) + param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context)); + else + param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context)); +} + +static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr, + Sema &S) { + if (!isa(d)) { + S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/; + return; + } + + d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context)); +} + +static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr, Sema &S) { - QualType RetTy; + QualType returnType; if (ObjCMethodDecl *MD = dyn_cast(d)) - RetTy = MD->getResultType(); + returnType = MD->getResultType(); else if (FunctionDecl *FD = dyn_cast(d)) - RetTy = FD->getResultType(); + returnType = FD->getResultType(); else { - SourceLocation L = Attr.getLoc(); S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 3 /* function or method */; + << SourceRange(attr.getLoc()) << attr.getName() + << 3 /* function or method */; return; } - if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs() - || RetTy->getAs())) { - SourceLocation L = Attr.getLoc(); + bool typeOK; + bool cf; + switch (attr.getKind()) { + default: llvm_unreachable("invalid ownership attribute"); return; + case AttributeList::AT_ns_returns_autoreleased: + case AttributeList::AT_ns_returns_retained: + case AttributeList::AT_ns_returns_not_retained: + typeOK = isValidSubjectOfNSAttribute(S, returnType); + cf = false; + break; + + case AttributeList::AT_cf_returns_retained: + case AttributeList::AT_cf_returns_not_retained: + typeOK = isValidSubjectOfCFAttribute(S, returnType); + cf = true; + break; + } + + if (!typeOK) { S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(L, L) << Attr.getName(); + << SourceRange(attr.getLoc()) + << attr.getName() << isa(d) << cf; return; } - switch (Attr.getKind()) { + switch (attr.getKind()) { default: assert(0 && "invalid ownership attribute"); return; + case AttributeList::AT_ns_returns_autoreleased: + d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(), + S.Context)); + return; case AttributeList::AT_cf_returns_not_retained: - d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), + d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), + d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_cf_returns_retained: - d->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), + d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_retained: - d->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), + d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(), S.Context)); return; }; @@ -2629,6 +2697,12 @@ case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break; // Checker-specific. + case AttributeList::AT_cf_consumed: + case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break; + case AttributeList::AT_ns_consumes_self: + HandleNSConsumesSelfAttr(D, Attr, S); break; + + case AttributeList::AT_ns_returns_autoreleased: case AttributeList::AT_ns_returns_not_retained: case AttributeList::AT_cf_returns_not_retained: case AttributeList::AT_ns_returns_retained: Modified: cfe/trunk/test/Analysis/retain-release.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=124174&r1=124173&r2=124174&view=diff ============================================================================== --- cfe/trunk/test/Analysis/retain-release.m (original) +++ cfe/trunk/test/Analysis/retain-release.m Mon Jan 24 21:31:58 2011 @@ -1210,7 +1210,7 @@ - (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning - (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning - (NSString*) newStringNoAttr; -- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}} +- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} @end static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}} From clattner at apple.com Mon Jan 24 19:39:46 2011 From: clattner at apple.com (Chris Lattner) Date: Mon, 24 Jan 2011 19:39:46 -0800 Subject: [cfe-commits] r124174 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/Analysis/retain-release.m In-Reply-To: <20110125033158.7884A2A6C130@llvm.org> References: <20110125033158.7884A2A6C130@llvm.org> Message-ID: On Jan 24, 2011, at 7:31 PM, John McCall wrote: > Author: rjmccall > Date: Mon Jan 24 21:31:58 2011 > New Revision: 124174 > > URL: http://llvm.org/viewvc/llvm-project?rev=124174&view=rev > Log: > Add the ns_consumes_self, ns_consumed, cf_consumed, and ns_returns_autoreleased > attributes for the benefit of the static analyzer. Ok. Please document these in the LanguageExtensions.html file though, thanks! -Chris From rjmccall at apple.com Mon Jan 24 19:51:08 2011 From: rjmccall at apple.com (John McCall) Date: Tue, 25 Jan 2011 03:51:08 -0000 Subject: [cfe-commits] r124175 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td test/Analysis/retain-release.m test/Rewriter/dllimport-typedef.c test/Sema/attr-naked.c test/Sema/attr-nodebug.c test/Sema/attr-noinline.c test/Sema/attr-used.c test/Sema/attr-weak.c test/Sema/constructor-attribute.c test/Sema/dllimport-dllexport.c test/Sema/sentinel-attribute.c test/Sema/unused-expr.c test/Sema/x86-attr-force-align-arg-pointer.c test/SemaObjC/format-arg-attribute.m Message-ID: <20110125035108.8045A2A6C130@llvm.org> Author: rjmccall Date: Mon Jan 24 21:51:08 2011 New Revision: 124175 URL: http://llvm.org/viewvc/llvm-project?rev=124175&view=rev Log: Change the wording of the bad-decl-for-attribute warning and error to make it clear that we're talking about the declarations and not the types. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/test/Analysis/retain-release.m cfe/trunk/test/Rewriter/dllimport-typedef.c cfe/trunk/test/Sema/attr-naked.c cfe/trunk/test/Sema/attr-nodebug.c cfe/trunk/test/Sema/attr-noinline.c cfe/trunk/test/Sema/attr-used.c cfe/trunk/test/Sema/attr-weak.c cfe/trunk/test/Sema/constructor-attribute.c cfe/trunk/test/Sema/dllimport-dllexport.c cfe/trunk/test/Sema/sentinel-attribute.c cfe/trunk/test/Sema/unused-expr.c cfe/trunk/test/Sema/x86-attr-force-align-arg-pointer.c cfe/trunk/test/SemaObjC/format-arg-attribute.m Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 24 21:51:08 2011 @@ -1038,17 +1038,17 @@ def err_alias_not_supported_on_darwin : Error < "only weak aliases are supported on darwin">; def warn_attribute_wrong_decl_type : Warning< - "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|" - "parameter or Objective-C method|function, method or block|" - "virtual method or class|function, method, or parameter|class|virtual method" - "|member|variable|method}1 types">; + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "parameters and methods|functions, methods and blocks|" + "classes and virtual methods|functions, methods, and parameters|" + "classes|virtual methods|class members|variables|methods}1">; def err_attribute_wrong_decl_type : Error< - "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|" - "parameter or Objective-C method|function, method or block|" - "virtual method or class|function, method, or parameter|class|virtual method" - "|member|variable|method}1 types">; + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "parameters and methods|functions, methods and blocks|" + "classes and virtual methods|functions, methods, and parameters|" + "classes|virtual methods|class members|variables|methods}1">; def warn_function_attribute_wrong_type : Warning< "%0 only applies to function types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< Modified: cfe/trunk/test/Analysis/retain-release.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Analysis/retain-release.m (original) +++ cfe/trunk/test/Analysis/retain-release.m Mon Jan 24 21:51:08 2011 @@ -1213,7 +1213,7 @@ - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} @end -static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}} +static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} void test_attr_1(TestOwnershipAttr *X) { NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}} Modified: cfe/trunk/test/Rewriter/dllimport-typedef.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/dllimport-typedef.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/dllimport-typedef.c (original) +++ cfe/trunk/test/Rewriter/dllimport-typedef.c Mon Jan 24 21:51:08 2011 @@ -11,7 +11,7 @@ // CHECK-NEG: error: void function 'bar' should not return a value // CHECK-NEG: 1 error generated -// CHECK-POS: warning: 'dllimport' attribute only applies to variable and function type +// CHECK-POS: warning: 'dllimport' attribute only applies to variables and functions // CHECK-POS: error: void function 'bar' should not return a value // CHECK-POS: 1 warning and 1 error generated Modified: cfe/trunk/test/Sema/attr-naked.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-naked.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-naked.c (original) +++ cfe/trunk/test/Sema/attr-naked.c Mon Jan 24 21:51:08 2011 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to function types}} +int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}} void t1() __attribute__((naked)); Modified: cfe/trunk/test/Sema/attr-nodebug.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-nodebug.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-nodebug.c (original) +++ cfe/trunk/test/Sema/attr-nodebug.c Mon Jan 24 21:51:08 2011 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -int a __attribute__((nodebug)); // expected-warning {{'nodebug' attribute only applies to function types}} +int a __attribute__((nodebug)); // expected-warning {{'nodebug' attribute only applies to functions}} void t1() __attribute__((nodebug)); Modified: cfe/trunk/test/Sema/attr-noinline.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-noinline.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-noinline.c (original) +++ cfe/trunk/test/Sema/attr-noinline.c Mon Jan 24 21:51:08 2011 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only applies to function types}} +int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only applies to functions}} void t1() __attribute__((noinline)); Modified: cfe/trunk/test/Sema/attr-used.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-used.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-used.c (original) +++ cfe/trunk/test/Sema/attr-used.c Mon Jan 24 21:51:08 2011 @@ -3,7 +3,7 @@ extern int l0 __attribute__((used)); // expected-warning {{used attribute ignored}} __private_extern__ int l1 __attribute__((used)); // expected-warning {{used attribute ignored}} -struct __attribute__((used)) s { // expected-warning {{'used' attribute only applies to variable and function types}} +struct __attribute__((used)) s { // expected-warning {{'used' attribute only applies to variables and functions}} int x; }; Modified: cfe/trunk/test/Sema/attr-weak.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-weak.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-weak.c (original) +++ cfe/trunk/test/Sema/attr-weak.c Mon Jan 24 21:51:08 2011 @@ -8,8 +8,8 @@ void __attribute__((weak_import)) g5(void) { } -struct __attribute__((weak)) s0 {}; // expected-warning {{'weak' attribute only applies to variable and function types}} -struct __attribute__((weak_import)) s1 {}; // expected-warning {{'weak_import' attribute only applies to variable and function types}} +struct __attribute__((weak)) s0 {}; // expected-warning {{'weak' attribute only applies to variables and functions}} +struct __attribute__((weak_import)) s1 {}; // expected-warning {{'weak_import' attribute only applies to variables and functions}} static int x __attribute__((weak)); // expected-error {{weak declaration of 'x' must be public}} Modified: cfe/trunk/test/Sema/constructor-attribute.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/constructor-attribute.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/constructor-attribute.c (original) +++ cfe/trunk/test/Sema/constructor-attribute.c Mon Jan 24 21:51:08 2011 @@ -1,12 +1,12 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to function types}} +int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to functions}} int f() __attribute__((constructor)); int f() __attribute__((constructor(1))); int f() __attribute__((constructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}} int f() __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires parameter 1 to be an integer constant}} -int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to function types}} +int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}} int f() __attribute__((destructor)); int f() __attribute__((destructor(1))); int f() __attribute__((destructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}} Modified: cfe/trunk/test/Sema/dllimport-dllexport.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/dllimport-dllexport.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/dllimport-dllexport.c (original) +++ cfe/trunk/test/Sema/dllimport-dllexport.c Mon Jan 24 21:51:08 2011 @@ -10,9 +10,9 @@ void __attribute__((dllexport)) foo5(); void __attribute__((dllimport)) foo5(); // expected-warning{{dllimport attribute ignored}} -typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' attribute only applies to variable and function types}} +typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' attribute only applies to variables and functions}} -typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variable and function}} +typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variables and functions}} void __attribute__((dllimport)) foo6(); void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}} @@ -28,9 +28,9 @@ void __declspec(dllexport) foo11(); void __declspec(dllimport) foo11(); // expected-warning{{dllimport attribute ignored}} -typedef int __declspec(dllexport) type1; // expected-warning{{'dllexport' attribute only applies to variable and function types}} +typedef int __declspec(dllexport) type1; // expected-warning{{'dllexport' attribute only applies to variables and functions}} -typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variable and function}} +typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variables and functions}} void __declspec(dllimport) foo12(); void foo12(){} // expected-warning {{'foo12' redeclared without dllimport attribute: previous dllimport ignored}} Modified: cfe/trunk/test/Sema/sentinel-attribute.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/sentinel-attribute.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/sentinel-attribute.c (original) +++ cfe/trunk/test/Sema/sentinel-attribute.c Mon Jan 24 21:51:08 2011 @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -int x __attribute__((sentinel)); //expected-warning{{'sentinel' attribute only applies to function, method or block types}} +int x __attribute__((sentinel)); //expected-warning{{'sentinel' attribute only applies to functions, methods and blocks}} void f1(int a, ...) __attribute__ ((sentinel)); void f2(int a, ...) __attribute__ ((sentinel(1))); Modified: cfe/trunk/test/Sema/unused-expr.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/unused-expr.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/unused-expr.c (original) +++ cfe/trunk/test/Sema/unused-expr.c Mon Jan 24 21:51:08 2011 @@ -95,7 +95,7 @@ return 0; } -int t7 __attribute__ ((warn_unused_result)); // expected-warning {{'warn_unused_result' attribute only applies to function types}} +int t7 __attribute__ ((warn_unused_result)); // expected-warning {{'warn_unused_result' attribute only applies to functions}} // PR4010 int (*fn4)(void) __attribute__ ((warn_unused_result)); Modified: cfe/trunk/test/Sema/x86-attr-force-align-arg-pointer.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/x86-attr-force-align-arg-pointer.c?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/Sema/x86-attr-force-align-arg-pointer.c (original) +++ cfe/trunk/test/Sema/x86-attr-force-align-arg-pointer.c Mon Jan 24 21:51:08 2011 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple i386-apple-darwin10 -fsyntax-only -verify %s -int a __attribute__((force_align_arg_pointer)); // expected-warning{{attribute only applies to function types}} +int a __attribute__((force_align_arg_pointer)); // expected-warning{{attribute only applies to functions}} // It doesn't matter where the attribute is located. void b(void) __attribute__((force_align_arg_pointer)); Modified: cfe/trunk/test/SemaObjC/format-arg-attribute.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-arg-attribute.m?rev=124175&r1=124174&r2=124175&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/format-arg-attribute.m (original) +++ cfe/trunk/test/SemaObjC/format-arg-attribute.m Mon Jan 24 21:51:08 2011 @@ -9,9 +9,9 @@ extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{attribute requires 1 argument(s)}} extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{attribute requires 1 argument(s)}} -struct s1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}} -union u1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}} -enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}} +struct s1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}} +union u1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}} +enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}} extern NSString *ff3 (const NSString *) __attribute__((format_arg(3-2))); extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{attribute requires 1 argument(s)}} From rjmccall at apple.com Mon Jan 24 20:26:21 2011 From: rjmccall at apple.com (John McCall) Date: Tue, 25 Jan 2011 04:26:21 -0000 Subject: [cfe-commits] r124176 - /cfe/trunk/docs/LanguageExtensions.html Message-ID: <20110125042621.361362A6C130@llvm.org> Author: rjmccall Date: Mon Jan 24 22:26:21 2011 New Revision: 124176 URL: http://llvm.org/viewvc/llvm-project?rev=124176&view=rev Log: Document the ns_returns_retained, ns_consumed, etc. attributes. Modified: cfe/trunk/docs/LanguageExtensions.html Modified: cfe/trunk/docs/LanguageExtensions.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=124176&r1=124175&r2=124176&view=diff ============================================================================== --- cfe/trunk/docs/LanguageExtensions.html (original) +++ cfe/trunk/docs/LanguageExtensions.html Mon Jan 24 22:26:21 2011 @@ -739,6 +739,51 @@

    Query for this feature with __has_feature(attribute_analyzer_noreturn).

    +

    Objective-C retaining behavior attributes

    + +

    In Objective-C, functions and methods are generally assumed to take +and return objects with +0 retain counts, with some exceptions for +special methods like +alloc and init. However, +there are exceptions, and so Clang provides attributes to allow these +exceptions to be documented, which helps the analyzer find leaks (and +ignore non-leaks).

    + +

    Usage: The ns_returns_retained, ns_returns_not_retained, +ns_returns_autoreleased, cf_returns_retained, +and cf_returns_not_retained attributes can be placed on +methods and functions that return Objective-C or CoreFoundation +objects. They are commonly placed at the end of a function prototype +or method declaration:

    + +
    +  id foo() __attribute__((ns_returns_retained));
    +
    +  - (NSString*) bar: (int) x __attribute__((ns_returns_retained));
    +
    + +

    The *_returns_retained attributes specify that the +returned object has a +1 retain count. +The *_returns_not_retained attributes specify that the return +object has a +0 retain count, even if the normal convention for its +selector would be +1. ns_returns_autoreleased specifies that the +returned object is +0, but is guaranteed to live at least as long as the +next flush of an autorelease pool.

    + +

    Usage: The ns_consumed and cf_consumed +attributes can be placed on an parameter declaration; they specify +that the argument is expected to have a +1 retain count, which will be +balanced in some way by the function or method. +The ns_consumes_self attribute can only be placed on an +Objective-C method; it specifies that the method expects +its self parameter to have a +1 retain count, which it will +balance in some way.

    + +
    +  void foo(__attribute__((ns_consumed)) NSString *string);
    +
    +  - (void) bar __attribute__((ns_consumes_self));
    +  - (void) baz: (id) __attribute__((ns_consumed)) x;
    +
    From dgregor at apple.com Tue Jan 25 08:13:26 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 16:13:26 -0000 Subject: [cfe-commits] r124189 - in /cfe/trunk: lib/Sema/SemaCXXCast.cpp test/CodeGenCXX/rvalue-references.cpp Message-ID: <20110125161326.39EBF2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 10:13:26 2011 New Revision: 124189 URL: http://llvm.org/viewvc/llvm-project?rev=124189&view=rev Log: When performing a glvalue-to-xvalue static_cast that involves a derived-to-base conversion, set the cast kind and base path appropriately. Added: cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=124189&r1=124188&r2=124189&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original) +++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Tue Jan 25 10:13:26 2011 @@ -78,7 +78,9 @@ // %1: Source Type // %2: Destination Type static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, - QualType DestType, unsigned &msg); + QualType DestType, CastKind &Kind, + CXXCastPath &BasePath, + unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -581,11 +583,9 @@ // C++0x [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg); - if (tcr != TC_NotApplicable) { - Kind = CK_NoOp; + tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, Kind, BasePath, msg); + if (tcr != TC_NotApplicable) return tcr; - } // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. @@ -695,7 +695,7 @@ /// Tests whether a conversion according to N2844 is valid. TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, - unsigned &msg) { + CastKind &Kind, CXXCastPath &BasePath, unsigned &msg) { // C++0x [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". @@ -719,6 +719,17 @@ return TC_Failed; } + if (DerivedToBase) { + Kind = CK_DerivedToBase; + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(SrcExpr->getType(), R->getPointeeType(), Paths)) + return TC_NotApplicable; + + Self.BuildBasePathArray(Paths, BasePath); + } else + Kind = CK_NoOp; + return TC_Success; } Added: cfe/trunk/test/CodeGenCXX/rvalue-references.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rvalue-references.cpp?rev=124189&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/rvalue-references.cpp (added) +++ cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Tue Jan 25 10:13:26 2011 @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + + +struct Spacer { int x; }; +struct A { double array[2]; }; +struct B : Spacer, A { }; + +B &getB(); + +// CHECK: define %struct.A* @_Z4getAv() +// CHECK: call %struct.B* @_Z4getBv() +// CHECK-NEXT: bitcast %struct.B* +// CHECK-NEXT: getelementptr i8* +// CHECK-NEXT: bitcast i8* {{.*}} to %struct.A* +// CHECK-NEXT: ret %struct.A* +A &&getA() { return static_cast(getB()); } + +int &getIntLValue(); +int &&getIntXValue(); +int getIntPRValue(); + +// CHECK: define i32* @_Z2f0v() +// CHECK: call i32* @_Z12getIntLValuev() +// CHECK-NEXT: ret i32* +int &&f0() { return static_cast(getIntLValue()); } + +// CHECK: define i32* @_Z2f1v() +// CHECK: call i32* @_Z12getIntXValuev() +// CHECK-NEXT: ret i32* +int &&f1() { return static_cast(getIntXValue()); } + +// CHECK: define i32* @_Z2f2v +// CHECK: call i32 @_Z13getIntPRValuev() +// CHECK-NEXT: store i32 {{.*}}, i32* +// CHECK-NEXT: ret i32* +int &&f2() { return static_cast(getIntPRValue()); } From dgregor at apple.com Tue Jan 25 08:14:21 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 16:14:21 -0000 Subject: [cfe-commits] [libcxx] r124190 - /libcxx/trunk/include/tuple Message-ID: <20110125161421.C38D92A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 10:14:21 2011 New Revision: 124190 URL: http://llvm.org/viewvc/llvm-project?rev=124190&view=rev Log: An rvalue reference cannot bind to an lvalue, so static_cast the result of the __tuple_leaf::get() call to an rvalue reference when returning from tuple's get(). Modified: libcxx/trunk/include/tuple Modified: libcxx/trunk/include/tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=124190&r1=124189&r2=124190&view=diff ============================================================================== --- libcxx/trunk/include/tuple (original) +++ libcxx/trunk/include/tuple Tue Jan 25 10:14:21 2011 @@ -589,7 +589,8 @@ get(tuple<_Tp...>&& __t) { typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; - return static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get(); + return static_cast >::type&&>( + static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get()); } // tie From hhinnant at apple.com Tue Jan 25 08:31:30 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Tue, 25 Jan 2011 16:31:30 -0000 Subject: [cfe-commits] [libcxx] r124192 - /libcxx/trunk/include/tuple Message-ID: <20110125163130.AE2822A6C12C@llvm.org> Author: hhinnant Date: Tue Jan 25 10:31:30 2011 New Revision: 124192 URL: http://llvm.org/viewvc/llvm-project?rev=124192&view=rev Log: tweak for readability (no functionality change) Modified: libcxx/trunk/include/tuple Modified: libcxx/trunk/include/tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=124192&r1=124191&r2=124192&view=diff ============================================================================== --- libcxx/trunk/include/tuple (original) +++ libcxx/trunk/include/tuple Tue Jan 25 10:31:30 2011 @@ -589,7 +589,7 @@ get(tuple<_Tp...>&& __t) { typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; - return static_cast >::type&&>( + return static_cast( static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get()); } From hhinnant at apple.com Tue Jan 25 08:32:04 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Tue, 25 Jan 2011 16:32:04 -0000 Subject: [cfe-commits] [libcxx] r124193 - /libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp Message-ID: <20110125163204.542B22A6C12C@llvm.org> Author: hhinnant Date: Tue Jan 25 10:32:04 2011 New Revision: 124193 URL: http://llvm.org/viewvc/llvm-project?rev=124193&view=rev Log: placeholder test Added: libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp Added: libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp?rev=124193&view=auto ============================================================================== --- libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp (added) +++ libcxx/trunk/test/utilities/meta/meta.trans/meta.trans.other/aligned_union.pass.cpp Tue Jan 25 10:32:04 2011 @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// type_traits + +// aligned_union + +#include + +int main() +{ +#error aligned_union is not implemented +} From dgregor at apple.com Tue Jan 25 08:43:15 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 08:43:15 -0800 Subject: [cfe-commits] [libcxx] r124192 - /libcxx/trunk/include/tuple In-Reply-To: <20110125163130.AE2822A6C12C@llvm.org> References: <20110125163130.AE2822A6C12C@llvm.org> Message-ID: On Jan 25, 2011, at 8:31 AM, Howard Hinnant wrote: > Author: hhinnant > Date: Tue Jan 25 10:31:30 2011 > New Revision: 124192 > > URL: http://llvm.org/viewvc/llvm-project?rev=124192&view=rev > Log: > tweak for readability (no functionality change) > > Modified: > libcxx/trunk/include/tuple > > Modified: libcxx/trunk/include/tuple > URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=124192&r1=124191&r2=124192&view=diff > ============================================================================== > --- libcxx/trunk/include/tuple (original) > +++ libcxx/trunk/include/tuple Tue Jan 25 10:31:30 2011 > @@ -589,7 +589,7 @@ > get(tuple<_Tp...>&& __t) > { > typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; > - return static_cast >::type&&>( > + return static_cast( > static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get()); > } Oh, I forgot to mention… an alternative implementation approach would be to add more __tuple_leaf::get() overloads that use ref-qualifiers to distinguish between __tuple_leaf-as-lvalue and __tuple_leaf-as-rvalue. However, Clang doesn't support ref-qualifiers yet, so I went this route. - Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: From hhinnant at apple.com Tue Jan 25 08:50:21 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Tue, 25 Jan 2011 11:50:21 -0500 Subject: [cfe-commits] [libcxx] r124192 - /libcxx/trunk/include/tuple In-Reply-To: References: <20110125163130.AE2822A6C12C@llvm.org> Message-ID: <224F0F37-54B4-4EFD-AB66-9BFB5BDF71B3@apple.com> On Jan 25, 2011, at 11:43 AM, Douglas Gregor wrote: > > On Jan 25, 2011, at 8:31 AM, Howard Hinnant wrote: > >> Author: hhinnant >> Date: Tue Jan 25 10:31:30 2011 >> New Revision: 124192 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=124192&view=rev >> Log: >> tweak for readability (no functionality change) >> >> Modified: >> libcxx/trunk/include/tuple >> >> Modified: libcxx/trunk/include/tuple >> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=124192&r1=124191&r2=124192&view=diff >> ============================================================================== >> --- libcxx/trunk/include/tuple (original) >> +++ libcxx/trunk/include/tuple Tue Jan 25 10:31:30 2011 >> @@ -589,7 +589,7 @@ >> get(tuple<_Tp...>&& __t) >> { >> typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; >> - return static_cast >::type&&>( >> + return static_cast( >> static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get()); >> } > > Oh, I forgot to mention… an alternative implementation approach would be to add more __tuple_leaf::get() overloads that use ref-qualifiers to distinguish between __tuple_leaf-as-lvalue and __tuple_leaf-as-rvalue. However, Clang doesn't support ref-qualifiers yet, so I went this route. Yeah, I don't implement anything I can't test. And that's the reason you're hitting all the "rvalue reference cannot bind to an lvalue" bugs. clang is the first compiler to be used here supporting the new rules. I'm sure there's going to be more. And looking forward to the updated rvalue-ref support! :-) -Howard From dgregor at apple.com Tue Jan 25 09:19:08 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 17:19:08 -0000 Subject: [cfe-commits] r124197 - in /cfe/trunk: lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp Message-ID: <20110125171908.53EED2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 11:19:08 2011 New Revision: 124197 URL: http://llvm.org/viewvc/llvm-project?rev=124197&view=rev Log: Implement the rvalue-reference deduction transformation (from T&& -> T) when taking the address of an overloaded function or matching a specialization to a template (C++0x [temp.deduct.type]p10). Fixes PR9044. Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=124197&r1=124196&r2=124197&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Jan 25 11:19:08 2011 @@ -49,7 +49,10 @@ /// \brief Allow non-dependent types to differ, e.g., when performing /// template argument deduction from a function call where conversions /// may apply. - TDF_SkipNonDependent = 0x08 + TDF_SkipNonDependent = 0x08, + /// \brief Whether we are performing template argument deduction for + /// parameters and arguments in a top-level template argument + TDF_TopLevelParameterTypeList = 0x10 }; } @@ -763,9 +766,9 @@ // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], - Info, Deduced, PartialOrdering, - RefParamComparisons)) + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced, TDF, PartialOrdering, + RefParamComparisons)) return Result; // Capture the deduced template arguments for each parameter pack expanded @@ -898,6 +901,29 @@ Arg.getCVRQualifiers()); Param = S.Context.getQualifiedType(UnqualParam, Quals); } + + if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { + // C++0x [temp.deduct.type]p10: + // If P and A are function types that originated from deduction when + // taking the address of a function template (14.8.2.2) or when deducing + // template arguments from a function declaration (14.8.2.6) and Pi and + // Ai are parameters of the top-level parameter-type-list of P and A, + // respectively, Pi is adjusted if it is an rvalue reference to a + // cv-unqualified template parameter and Ai is an lvalue reference, in + // which case the type of Pi is changed to be the template parameter + // type (i.e., T&& is changed to simply T). [ Note: As a result, when + // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be + // deduced as X&. — end note ] + TDF &= ~TDF_TopLevelParameterTypeList; + + if (const RValueReferenceType *ParamRef + = Param->getAs()) { + if (isa(ParamRef->getPointeeType()) && + !ParamRef->getPointeeType().getQualifiers()) + if (Arg->isLValueReferenceType()) + Param = ParamRef->getPointeeType(); + } + } } // If the parameter type is not dependent, there is nothing to deduce. @@ -1119,6 +1145,7 @@ // T(*)() // T(*)(T) case Type::FunctionProto: { + unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; const FunctionProtoType *FunctionProtoArg = dyn_cast(Arg); if (!FunctionProtoArg) @@ -1147,7 +1174,7 @@ FunctionProtoParam->getNumArgs(), FunctionProtoArg->arg_type_begin(), FunctionProtoArg->getNumArgs(), - Info, Deduced, 0); + Info, Deduced, SubTDF); } case Type::InjectedClassName: { @@ -2767,7 +2794,7 @@ if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, FunctionType, ArgFunctionType, Info, - Deduced, 0)) + Deduced, TDF_TopLevelParameterTypeList)) return Result; } Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp?rev=124197&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp Tue Jan 25 11:19:08 2011 @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +template void f(T&&); +template<> void f(int&) { } +void (*fp)(int&) = &f; From dgregor at apple.com Tue Jan 25 09:51:48 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 17:51:48 -0000 Subject: [cfe-commits] r124199 - /cfe/trunk/lib/Sema/TreeTransform.h Message-ID: <20110125175148.8A6812A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 11:51:48 2011 New Revision: 124199 URL: http://llvm.org/viewvc/llvm-project?rev=124199&view=rev Log: Be a bit more defensive about setting the temporary base location during template instantiation. This code needs to eventually die, but this little tweak fixes PR8629, where bad location information slipped through to the location of a class template instantiation. Modified: cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=124199&r1=124198&r2=124199&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Jan 25 11:51:48 2011 @@ -169,7 +169,9 @@ DeclarationName Entity) : Self(Self) { OldLocation = Self.getDerived().getBaseLocation(); OldEntity = Self.getDerived().getBaseEntity(); - Self.getDerived().setBase(Location, Entity); + + if (Location.isValid()) + Self.getDerived().setBase(Location, Entity); } ~TemporaryBase() { From chandlerc at google.com Tue Jan 25 10:03:59 2011 From: chandlerc at google.com (Chandler Carruth) Date: Tue, 25 Jan 2011 10:03:59 -0800 Subject: [cfe-commits] r124199 - /cfe/trunk/lib/Sema/TreeTransform.h In-Reply-To: <20110125175148.8A6812A6C12C@llvm.org> References: <20110125175148.8A6812A6C12C@llvm.org> Message-ID: On Tue, Jan 25, 2011 at 9:51 AM, Douglas Gregor wrote: > Be a bit more defensive about setting the temporary base location > during template instantiation. This code needs to eventually die, but > this little tweak fixes PR8629 > Test case? (Especially so we don't regress when the code actually dies...) -------------- next part -------------- An HTML attachment was scrubbed... URL: From andersca at mac.com Tue Jan 25 10:08:22 2011 From: andersca at mac.com (Anders Carlsson) Date: Tue, 25 Jan 2011 18:08:22 -0000 Subject: [cfe-commits] r124201 - in /cfe/trunk/lib/Sema: Sema.cpp SemaDeclCXX.cpp Message-ID: <20110125180823.038302A6C12C@llvm.org> Author: andersca Date: Tue Jan 25 12:08:22 2011 New Revision: 124201 URL: http://llvm.org/viewvc/llvm-project?rev=124201&view=rev Log: Don't insert class templates into the DynamicClasses vector. Modified: cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=124201&r1=124200&r2=124201&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Tue Jan 25 12:08:22 2011 @@ -290,6 +290,8 @@ // this translation unit, then those vtables are considered "used" and must // be emitted. for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + assert(!DynamicClasses[I]->isDependentType() && + "Should not see dependent types here!"); if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(DynamicClasses[I])) { const FunctionDecl *Definition = 0; Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124201&r1=124200&r2=124201&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jan 25 12:08:22 2011 @@ -2746,7 +2746,7 @@ } } - if (Record->isDynamicClass()) + if (Record->isDynamicClass() && !Record->isDependentType()) DynamicClasses.push_back(Record); if (Record->getIdentifier()) { From dgregor at apple.com Tue Jan 25 10:11:52 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 18:11:52 -0000 Subject: [cfe-commits] r124204 - /cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp Message-ID: <20110125181152.BCC932A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 12:11:52 2011 New Revision: 124204 URL: http://llvm.org/viewvc/llvm-project?rev=124204&view=rev Log: Add test for PR8629 Modified: cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp Modified: cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp?rev=124204&r1=124203&r2=124204&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp (original) +++ cfe/trunk/test/SemaTemplate/instantiate-template-template-parm.cpp Tue Jan 25 12:11:52 2011 @@ -59,3 +59,39 @@ }; Comp c0; + +namespace PR8629 { + template class TT> struct X0 + { + static void apply(); + }; + template struct Type { }; + + template struct X1 + { + template struct Inner; + + template void g() + { + typedef Inner Init; + X0::apply(); + } + template void f () + { + g >(); + } + }; + template template struct X1::Inner + { + template struct VeryInner { + }; + }; + struct X1Container + { + X1Container() + { + simplex_.f<0>(); + } + X1 simplex_; + }; +} From dgregor at apple.com Tue Jan 25 10:15:20 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 10:15:20 -0800 Subject: [cfe-commits] r124199 - /cfe/trunk/lib/Sema/TreeTransform.h In-Reply-To: References: <20110125175148.8A6812A6C12C@llvm.org> Message-ID: On Jan 25, 2011, at 10:03 AM, Chandler Carruth wrote: > On Tue, Jan 25, 2011 at 9:51 AM, Douglas Gregor wrote: > Be a bit more defensive about setting the temporary base location > during template instantiation. This code needs to eventually die, but > this little tweak fixes PR8629 > > Test case? (Especially so we don't regress when the code actually dies…) Picky, picky! ;) r124204. - Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: From richard at metafoo.co.uk Tue Jan 25 10:18:16 2011 From: richard at metafoo.co.uk (Richard Smith) Date: Tue, 25 Jan 2011 18:18:16 -0000 (UTC) Subject: [cfe-commits] [PATCH] Improved error recovery in for-statement Message-ID: <40398.10.0.16.53.1295979496.squirrel@webmail.cantab.net> Hi, The attached patch improves diagnostics error recovery in for-statements. Examples: Before: for.cpp:8:11: error: expected ';' in 'for' statement specifier for (n 0; n < 10; n++); // expected-error {{expected '=' in 'for'}} ^ for.cpp:8:8: warning: expression result unused for (n 0; n < 10; n++); // expected-error {{expected '=' in 'for'}} ^ After: for.cpp:8:11: error: expected '=' in 'for' init statement for (n 0; n < 10; n++); // expected-error {{expected '=' in 'for'}} ^ = Before (note that this error currently causes clang to get confused about the following statement): for.cpp:9:14: error: expected ';' in 'for' statement specifier for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}} ^ for.cpp:9:25: error: expected ';' in 'for' statement specifier for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}} ^ for.cpp:10:3: error: expected expression for (n = 0; n < 10 n++); // expected-error {{expected ';' in 'for'}} ^ for.cpp:10:3: error: expected ')' for.cpp:9:7: note: to match this '(' for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}} ^ After: for.cpp:9:14: error: expected ';' in 'for' statement specifier for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}} ^ ; Before (an extreme case): for.cpp:20:10: error: expected ';' in 'for' statement specifier for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ for.cpp:20:22: error: expected expression for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ for.cpp:22:3: error: expected expression for (intt n = 0; n < 10; ++n); // expected-error {{undeclared identifier 'intt'}} ^ for.cpp:22:3: error: expected ')' for.cpp:20:7: note: to match this '(' for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ for.cpp:20:8: warning: expression result unused for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ After: ../src/tools/clang/test/Parser/for.cpp:20:10: error: expected '=' in 'for' init statement for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ = ../src/tools/clang/test/Parser/for.cpp:20:12: error: expected ';' in 'for' statement specifier for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ ; ../src/tools/clang/test/Parser/for.cpp:20:19: error: expected ';' in 'for' statement specifier for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}} ^ ; The patch can be viewed online here: http://codereview.appspot.com/3992046/ Please let me know what I need to fix in order to get this committed. Thanks! Richard -------------- next part -------------- A non-text attachment was scrubbed... Name: clang-for-error.patch Type: text/x-patch Size: 5491 bytes Desc: not available URL: From rafael.espindola at gmail.com Tue Jan 25 11:10:25 2011 From: rafael.espindola at gmail.com (Rafael Espindola) Date: Tue, 25 Jan 2011 19:10:25 -0000 Subject: [cfe-commits] r124210 - in /cfe/trunk/test: CXX/except/except.spec/ CodeGenCXX/ CodeGenObjCXX/ Message-ID: <20110125191025.6C27F2A6C12C@llvm.org> Author: rafael Date: Tue Jan 25 13:10:24 2011 New Revision: 124210 URL: http://llvm.org/viewvc/llvm-project?rev=124210&view=rev Log: Move unnamed_addr after the function arguments on Sabre's request. Modified: cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp cfe/trunk/test/CodeGenCXX/arm.cpp cfe/trunk/test/CodeGenCXX/constructor-init.cpp cfe/trunk/test/CodeGenCXX/constructors.cpp cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis-2.cpp cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis.cpp cfe/trunk/test/CodeGenCXX/default-arg-temps.cpp cfe/trunk/test/CodeGenCXX/default-arguments.cpp cfe/trunk/test/CodeGenCXX/default-constructor-template-member.cpp cfe/trunk/test/CodeGenCXX/delete.cpp cfe/trunk/test/CodeGenCXX/destructors.cpp cfe/trunk/test/CodeGenCXX/eh.cpp cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp cfe/trunk/test/CodeGenCXX/mangle-template.cpp cfe/trunk/test/CodeGenCXX/member-functions.cpp cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp cfe/trunk/test/CodeGenCXX/member-templates.cpp cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp cfe/trunk/test/CodeGenCXX/template-anonymous-types.cpp cfe/trunk/test/CodeGenCXX/template-instantiation.cpp cfe/trunk/test/CodeGenCXX/template-linkage.cpp cfe/trunk/test/CodeGenCXX/value-init.cpp cfe/trunk/test/CodeGenCXX/virt-dtor-gen.cpp cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp cfe/trunk/test/CodeGenCXX/virtual-bases.cpp cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp cfe/trunk/test/CodeGenObjCXX/implicit-copy-constructor.mm Modified: cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp (original) +++ cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp Tue Jan 25 13:10:24 2011 @@ -26,17 +26,17 @@ struct X5 : X0, X4 { }; void test(X2 x2, X3 x3, X5 x5) { - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X2C1ERKS_ + // CHECK: define linkonce_odr void @_ZN2X2C1ERKS_(%struct.X0* %this, %struct.X0*) unnamed_addr // CHECK: call void @_ZN2X2C2ERKS_({{.*}}) nounwind // CHECK-NEXT: ret void // CHECK-NEXT: } X2 x2a(x2); - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X3C1ERKS_ + // CHECK: define linkonce_odr void @_ZN2X3C1ERKS_(%struct.X0* %this, %struct.X0*) unnamed_addr // CHECK: call void @_ZN2X3C2ERKS_({{.*}}) nounwind // CHECK-NEXT: ret void // CHECK-NEXT: } X3 x3a(x3); - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X5C1ERS_ + // CHECK: define linkonce_odr void @_ZN2X5C1ERS_({{.*}}) unnamed_addr // CHECK-NOT: call void @__cxa_call_unexpected // CHECK: ret void X5 x5a(x5); @@ -55,24 +55,24 @@ struct X9 : X6, X7 { }; void test() { - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X8C1Ev + // CHECK: define linkonce_odr void @_ZN2X8C1Ev(%struct.X0* %this) unnamed_addr // CHECK: call void @_ZN2X8C2Ev({{.*}}) nounwind // CHECK-NEXT: ret void X8(); - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X9C1Ev + // CHECK: define linkonce_odr void @_ZN2X9C1Ev(%struct.X0* %this) unnamed_addr // FIXME: check that this is the end of the line here: // CHECK: call void @_ZN2X9C2Ev({{.*}}) // CHECK-NEXT: ret void X9(); - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X9C2Ev + // CHECK: define linkonce_odr void @_ZN2X9C2Ev(%struct.X0* %this) unnamed_addr // CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind // FIXME: and here: // CHECK-NEXT: call void @_ZN2X7C2Ev({{.*}}) // CHECK: ret void - // CHECK: define linkonce_odr unnamed_addr void @_ZN2X8C2Ev + // CHECK: define linkonce_odr void @_ZN2X8C2Ev(%struct.X0* %this) unnamed_addr // CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind // CHECK-NEXT: ret void } Modified: cfe/trunk/test/CodeGenCXX/arm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/arm.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/arm.cpp (original) +++ cfe/trunk/test/CodeGenCXX/arm.cpp Tue Jan 25 13:10:24 2011 @@ -44,7 +44,7 @@ a.bar(); } - // CHECK: define linkonce_odr unnamed_addr [[A]]* @_ZN5test11AC1Ei([[A]]* + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4 // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] @@ -54,7 +54,7 @@ // CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]] // CHECK: ret [[A]]* [[THIS2]] - // CHECK: define linkonce_odr unnamed_addr [[A]]* @_ZN5test11AD1Ev([[A]]* + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4 // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] Modified: cfe/trunk/test/CodeGenCXX/constructor-init.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructor-init.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/constructor-init.cpp (original) +++ cfe/trunk/test/CodeGenCXX/constructor-init.cpp Tue Jan 25 13:10:24 2011 @@ -91,7 +91,7 @@ B(int); }; - // CHECK: define unnamed_addr void @_ZN10InitVTable1BC2Ev( + // CHECK: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr // CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i8*** // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]] // CHECK: [[VTBL:%.*]] = load i32 ([[B]]*)*** {{%.*}} @@ -104,7 +104,7 @@ // CHECK-NEXT: ret void B::B() : A(foo()) {} - // CHECK: define unnamed_addr void @_ZN10InitVTable1BC2Ei( + // CHECK: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr // CHECK: [[ARG:%.*]] = add nsw i32 {{%.*}}, 5 // CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]]) // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i8*** @@ -125,7 +125,7 @@ // Make sure that the instantiated constructor initializes start and // end properly. -// CHECK: define linkonce_odr unnamed_addr void @_ZN1XIiEC2ERKS0_ +// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr // CHECK: {{store.*null}} // CHECK: {{store.*null}} // CHECK: ret Modified: cfe/trunk/test/CodeGenCXX/constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructors.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/constructors.cpp (original) +++ cfe/trunk/test/CodeGenCXX/constructors.cpp Tue Jan 25 13:10:24 2011 @@ -21,18 +21,18 @@ A::A(struct Undeclared &ref) : mem(0) {} // Check that delegation works. -// CHECK: define unnamed_addr void @_ZN1AC1ER10Undeclared( +// CHECK: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1AC2ER10Undeclared( -// CHECK: define unnamed_addr void @_ZN1AC2ER10Undeclared( +// CHECK: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( A::A(ValueClass v) : mem(v.y - v.x) {} -// CHECK: define unnamed_addr void @_ZN1AC1E10ValueClass( +// CHECK: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr // CHECK: call void @_ZN1AC2E10ValueClass( -// CHECK: define unnamed_addr void @_ZN1AC2E10ValueClass( +// CHECK: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( @@ -44,10 +44,10 @@ B::B(struct Undeclared &ref) : A(ref), mem(1) {} -// CHECK: define unnamed_addr void @_ZN1BC1ER10Undeclared( +// CHECK: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1BC2ER10Undeclared( -// CHECK: define unnamed_addr void @_ZN1BC2ER10Undeclared( +// CHECK: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1AC2ER10Undeclared( // CHECK: call void @_ZN6MemberC1Ei( @@ -64,12 +64,12 @@ }; C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {} -// CHECK: define unnamed_addr void @_ZN1CC1Ei( +// CHECK: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( -// CHECK: define unnamed_addr void @_ZN1CC2Ei( +// CHECK: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( @@ -83,12 +83,12 @@ D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} -// CHECK: define unnamed_addr void @_ZN1DC1Eiz( +// CHECK: define void @_ZN1DC1Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( -// CHECK: define unnamed_addr void @_ZN1DC2Eiz( +// CHECK: define void @_ZN1DC2Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( Modified: cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp (original) +++ cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp Tue Jan 25 13:10:24 2011 @@ -21,7 +21,7 @@ Derived(const Other &O); }; - // CHECK: define unnamed_addr void @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE + // CHECK: define void @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.PR8683::A"* %O) unnamed_addr Derived::Derived(const Other &O) // CHECK: call void @_ZNK13no_elide_base5OthercvNS_4BaseEEv // CHECK: call void @_ZN13no_elide_base4BaseC2ERKS0_ Modified: cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis-2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis-2.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis-2.cpp (original) +++ cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis-2.cpp Tue Jan 25 13:10:24 2011 @@ -3,5 +3,5 @@ struct A { virtual void a(); }; A x(A& y) { return y; } -// CHECK: define linkonce_odr unnamed_addr void @_ZN1AC1ERKS_( +// CHECK: define linkonce_odr void @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) Modified: cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis.cpp (original) +++ cfe/trunk/test/CodeGenCXX/copy-constructor-synthesis.cpp Tue Jan 25 13:10:24 2011 @@ -21,7 +21,7 @@ }; -// CHECK: define linkonce_odr unnamed_addr void @_ZN1XC1ERKS_ +// CHECK: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr struct X : M, N, P { // ... X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd), au_i1(1234), au1_4("MASKED") {} @@ -136,7 +136,7 @@ B b2 = b1; } -// CHECK: define linkonce_odr unnamed_addr void @_ZN6PR66281BC2ERKS0_ +// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr // CHECK: call void @_ZN6PR66281TC1Ev // CHECK: call void @_ZN6PR66281TC1Ev // CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_ Modified: cfe/trunk/test/CodeGenCXX/default-arg-temps.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/default-arg-temps.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/default-arg-temps.cpp (original) +++ cfe/trunk/test/CodeGenCXX/default-arg-temps.cpp Tue Jan 25 13:10:24 2011 @@ -61,7 +61,7 @@ C c; A a; - // CHECK: define linkonce_odr unnamed_addr void @_ZN5test11DC2Ev( + // CHECK: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr // CHECK: call void @_ZN5test11BC1Ev( // CHECK-NEXT: call void @_ZN5test11CC1ERKNS_1BE( // CHECK-NEXT: call void @_ZN5test11BD1Ev( Modified: cfe/trunk/test/CodeGenCXX/default-arguments.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/default-arguments.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/default-arguments.cpp (original) +++ cfe/trunk/test/CodeGenCXX/default-arguments.cpp Tue Jan 25 13:10:24 2011 @@ -42,10 +42,10 @@ C(); }; -// CHECK: define unnamed_addr void @_ZN1CC1Ev( +// CHECK: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN1CC2Ev( -// CHECK: define unnamed_addr void @_ZN1CC2Ev( +// CHECK: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN2A1C1Ev( // CHECK: call void @_ZN2A2C1Ev( // CHECK: call void @_ZN1BC1ERK2A1RK2A2( Modified: cfe/trunk/test/CodeGenCXX/default-constructor-template-member.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/default-constructor-template-member.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/default-constructor-template-member.cpp (original) +++ cfe/trunk/test/CodeGenCXX/default-constructor-template-member.cpp Tue Jan 25 13:10:24 2011 @@ -6,5 +6,5 @@ B b; } // CHECK: call void @_ZN1BC1Ev -// CHECK: define linkonce_odr unnamed_addr void @_ZN1BC1Ev +// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN1AIiEC1Ev Modified: cfe/trunk/test/CodeGenCXX/delete.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/delete.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/delete.cpp (original) +++ cfe/trunk/test/CodeGenCXX/delete.cpp Tue Jan 25 13:10:24 2011 @@ -54,7 +54,7 @@ delete a; } - // CHECK: define linkonce_odr unnamed_addr void @_ZN5test01AD1Ev + // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%class.A* %this) unnamed_addr // CHECK: define linkonce_odr void @_ZN5test01AdlEPv } Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/destructors.cpp (original) +++ cfe/trunk/test/CodeGenCXX/destructors.cpp Tue Jan 25 13:10:24 2011 @@ -40,11 +40,11 @@ struct allocator_derived : allocator { }; - // CHECK: define unnamed_addr void @_ZN6PR75269allocatorD2Ev + // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR5529::A"* %this) unnamed_addr // CHECK: call void @__cxa_call_unexpected allocator::~allocator() throw() { foo(); } - // CHECK: define linkonce_odr unnamed_addr void @_ZN6PR752617allocator_derivedD1Ev + // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR5529::A"* %this) unnamed_addr // CHECK-NOT: call void @__cxa_call_unexpected // CHECK: } void foo() { @@ -93,7 +93,7 @@ // complete destructor alias tested above -// CHECK: define unnamed_addr void @_ZN5test01AD2Ev +// CHECK: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -106,7 +106,7 @@ B::~B() try { } catch (int i) {} // It will suppress the delegation optimization here, though. -// CHECK: define unnamed_addr void @_ZN5test01BD1Ev +// CHECK: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -114,7 +114,7 @@ // CHECK: invoke void @_ZN5test05VBaseD2Ev // CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]] -// CHECK: define unnamed_addr void @_ZN5test01BD2Ev +// CHECK: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -142,24 +142,24 @@ O::~O() {} // alias tested above struct P : NonEmpty, A { ~P(); }; - P::~P() {} // CHECK: define unnamed_addr void @_ZN5test11PD2Ev + P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr struct Q : A, B { ~Q(); }; - Q::~Q() {} // CHECK: define unnamed_addr void @_ZN5test11QD2Ev + Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::M"* %this) unnamed_addr struct R : A { ~R(); }; - R::~R() { A a; } // CHECK: define unnamed_addr void @_ZN5test11RD2Ev + R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::M"* %this) unnamed_addr struct S : A { ~S(); int x; }; S::~S() {} // alias tested above struct T : A { ~T(); B x; }; - T::~T() {} // CHECK: define unnamed_addr void @_ZN5test11TD2Ev + T::~T() {} // CHECK: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr // The VTT parameter prevents this. We could still make this work // for calling conventions that are safe against extra parameters. struct U : A, virtual B { ~U(); }; - U::~U() {} // CHECK: define unnamed_addr void @_ZN5test11UD2Ev + U::~U() {} // CHECK: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr } // PR6471 @@ -168,7 +168,7 @@ struct B : A { ~B(); }; B::~B() {} - // CHECK: define unnamed_addr void @_ZN5test21BD2Ev + // CHECK: define void @_ZN5test21BD2Ev(%"struct.test1::M"* %this) unnamed_addr // CHECK: call void @_ZN5test21AD2Ev } @@ -273,7 +273,7 @@ }; C::C() { opaque(); } - // CHECK: define unnamed_addr void @_ZN5test61CC1Ev + // CHECK: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr // CHECK: call void @_ZN5test61BILj2EEC2Ev // CHECK: invoke void @_ZN5test61BILj3EEC2Ev // CHECK: invoke void @_ZN5test61BILj0EEC2Ev @@ -283,7 +283,7 @@ // FIXME: way too much EH cleanup code follows C::~C() { opaque(); } - // CHECK: define unnamed_addr void @_ZN5test61CD1Ev + // CHECK: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr // CHECK: invoke void @_ZN5test61CD2Ev // CHECK: invoke void @_ZN5test61BILj3EED2Ev // CHECK: call void @_ZN5test61BILj2EED2Ev @@ -291,7 +291,7 @@ // CHECK: invoke void @_ZN5test61BILj3EED2Ev // CHECK: invoke void @_ZN5test61BILj2EED2Ev - // CHECK: define unnamed_addr void @_ZN5test61CD2Ev + // CHECK: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr // CHECK: invoke void @_ZN5test66opaqueEv // CHECK: invoke void @_ZN5test61AD1Ev // CHECK: invoke void @_ZN5test61AD1Ev @@ -308,7 +308,7 @@ // Checks from test3: - // CHECK: define internal unnamed_addr void @_ZN5test312_GLOBAL__N_11DD0Ev( + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::::D"* %this) unnamed_addr // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev( // CHECK: call void @_ZdlPv({{.*}}) nounwind // CHECK: ret void @@ -330,7 +330,7 @@ // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev( // CHECK: ret void - // CHECK: define internal unnamed_addr void @_ZN5test312_GLOBAL__N_11CD2Ev( + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::::C"* %this) unnamed_addr // CHECK: invoke void @_ZN5test31BD2Ev( // CHECK: call void @_ZN5test31AD2Ev( // CHECK: ret void @@ -338,7 +338,7 @@ // CHECK: declare void @_ZN5test31BD2Ev( // CHECK: declare void @_ZN5test31AD2Ev( - // CHECK: define internal unnamed_addr void @_ZN5test312_GLOBAL__N_11CD0Ev( + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::::C"* %this) unnamed_addr // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev( // CHECK: call void @_ZdlPv({{.*}}) nounwind // CHECK: ret void Modified: cfe/trunk/test/CodeGenCXX/eh.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/eh.cpp (original) +++ cfe/trunk/test/CodeGenCXX/eh.cpp Tue Jan 25 13:10:24 2011 @@ -197,11 +197,11 @@ struct A { A(); }; - // CHECK: define unnamed_addr void @_ZN5test91AC1Ev + // CHECK: define void @_ZN5test91AC1Ev(%"struct.test10::A"* %this) unnamed_addr // CHECK: call void @_ZN5test91AC2Ev // CHECK-NEXT: ret void - // CHECK: define unnamed_addr void @_ZN5test91AC2Ev( + // CHECK: define void @_ZN5test91AC2Ev(%"struct.test10::A"* %this) unnamed_addr A::A() try { // CHECK: invoke void @_ZN5test96opaqueEv() opaque(); Modified: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp (original) +++ cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp Tue Jan 25 13:10:24 2011 @@ -40,7 +40,7 @@ D d2(d); } -// CHECK: define linkonce_odr unnamed_addr void @_ZN1DC1ERS_ +// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr // CHECK: call void @_ZN1AC1Ev // CHECK: call void @_ZN1CC2ERS_1A // CHECK: call void @_ZN1AD1Ev Modified: cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Tue Jan 25 13:10:24 2011 @@ -14,8 +14,8 @@ namespace std { struct A { A(); }; - // CHECK: define unnamed_addr void @_ZNSt1AC1Ev - // CHECK: define unnamed_addr void @_ZNSt1AC2Ev + // CHECK: define void @_ZNSt1AC1Ev(%"struct.N::std::A"* %this) unnamed_addr + // CHECK: define void @_ZNSt1AC2Ev(%"struct.N::std::A"* %this) unnamed_addr A::A() { } }; Modified: cfe/trunk/test/CodeGenCXX/mangle-template.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-template.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-template.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle-template.cpp Tue Jan 25 13:10:24 2011 @@ -82,7 +82,7 @@ X(U*, typename int_c<(meta::value + meta::value)>::type *) { } }; - // CHECK: define weak_odr unnamed_addr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE + // CHECK: define weak_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE(%"class.test1::T"* %this, double*, float*) unnamed_addr template X::X(double*, float*); } Modified: cfe/trunk/test/CodeGenCXX/member-functions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-functions.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/member-functions.cpp (original) +++ cfe/trunk/test/CodeGenCXX/member-functions.cpp Tue Jan 25 13:10:24 2011 @@ -20,9 +20,9 @@ struct S { - // RUN: grep "define linkonce_odr unnamed_addr void @_ZN1SC1Ev" %t + // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t inline S() { } - // RUN: grep "define linkonce_odr unnamed_addr void @_ZN1SC1Ev" %t + // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t inline ~S() { } Modified: cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp (original) +++ cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp Tue Jan 25 13:10:24 2011 @@ -10,7 +10,7 @@ Foo::Foo(unsigned arg) : file_id(arg = 42) { } -// CHECK: define unnamed_addr void @_ZN3FooC2Ej +// CHECK: define void @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr // CHECK: [[ARG:%.*]] = alloca i32 // CHECK: store i32 42, i32* [[ARG]] // CHECK: store i32 42, i32* %{{.*}} Modified: cfe/trunk/test/CodeGenCXX/member-templates.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-templates.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/member-templates.cpp (original) +++ cfe/trunk/test/CodeGenCXX/member-templates.cpp Tue Jan 25 13:10:24 2011 @@ -15,8 +15,8 @@ template B::B(T) {} -// CHECK: define weak_odr unnamed_addr void @_ZN1BC1IiEET_(%struct.B* %this, i32) -// CHECK: define weak_odr unnamed_addr void @_ZN1BC2IiEET_(%struct.B* %this, i32) +// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr +// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr template B::B(int); template Modified: cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp (original) +++ cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp Tue Jan 25 13:10:24 2011 @@ -120,7 +120,7 @@ A(); }; -// CHECK: define unnamed_addr void @_ZN9ValueInit1AC2Ev +// CHECK: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr // CHECK: store i64 -1, i64* // CHECK: ret void A::A() : a() {} Modified: cfe/trunk/test/CodeGenCXX/template-anonymous-types.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/template-anonymous-types.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/template-anonymous-types.cpp (original) +++ cfe/trunk/test/CodeGenCXX/template-anonymous-types.cpp Tue Jan 25 13:10:24 2011 @@ -29,9 +29,9 @@ // // BAR's instantiation of X: // CHECK: define internal i32 @"_ZN1XIN1S3$_1EE1fEv"(%struct.X* %this) - // CHECK: define internal unnamed_addr void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) + // CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr // // FOO's instantiation of X: // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X* %this) - // CHECK: define internal unnamed_addr void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X* %this, i32 %t) + // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr } Modified: cfe/trunk/test/CodeGenCXX/template-instantiation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/template-instantiation.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/template-instantiation.cpp (original) +++ cfe/trunk/test/CodeGenCXX/template-instantiation.cpp Tue Jan 25 13:10:24 2011 @@ -7,7 +7,7 @@ // CHECK-NOT: _ZTVN5test31SIiEE // CHECK-NOT: _ZTSN5test31SIiEE -// CHECK: define linkonce_odr unnamed_addr void @_ZN5test21CIiEC1Ev( +// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* nocapture %this) unnamed_addr // CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_( // CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd( Modified: cfe/trunk/test/CodeGenCXX/template-linkage.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/template-linkage.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/template-linkage.cpp (original) +++ cfe/trunk/test/CodeGenCXX/template-linkage.cpp Tue Jan 25 13:10:24 2011 @@ -37,7 +37,7 @@ extern template struct X0; extern template struct X1; -// CHECK: define linkonce_odr unnamed_addr void @_ZN2X1IcED1Ev( +// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr void test_X1() { X1 i1c; } Modified: cfe/trunk/test/CodeGenCXX/value-init.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/value-init.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/value-init.cpp (original) +++ cfe/trunk/test/CodeGenCXX/value-init.cpp Tue Jan 25 13:10:24 2011 @@ -133,7 +133,7 @@ X3().f(); } - // CHECK: define linkonce_odr unnamed_addr void @_ZN8zeroinit2X3IiEC2Ev + // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%struct.B* %this) unnamed_addr // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev // CHECK-NEXT: ret void Modified: cfe/trunk/test/CodeGenCXX/virt-dtor-gen.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virt-dtor-gen.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/virt-dtor-gen.cpp (original) +++ cfe/trunk/test/CodeGenCXX/virt-dtor-gen.cpp Tue Jan 25 13:10:24 2011 @@ -7,4 +7,4 @@ }; Foo::~Foo() {} -// CHECK: define unnamed_addr void @_ZN3FooD0Ev +// CHECK: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr Modified: cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp (original) +++ cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp Tue Jan 25 13:10:24 2011 @@ -18,34 +18,34 @@ // basic_iostream's complete dtor calls its base dtor, then its // virtual base's dtor. -// CHECK: define linkonce_odr unnamed_addr void @_ZN14basic_iostreamIcED1Ev +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr // CHECK: call void @_ZN14basic_iostreamIcED2Ev // CHECK: call void @_ZN9basic_iosD2Ev // basic_iostream's base dtor calls its non-virtual base dtor. -// CHECK: define linkonce_odr unnamed_addr void @_ZN14basic_iostreamIcED2Ev +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr // CHECK: call void @_ZN13basic_istreamIcED2Ev // CHECK: } // basic_istream's base dtor is a no-op. -// CHECK: define linkonce_odr unnamed_addr void @_ZN13basic_istreamIcED2Ev +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr // CHECK-NOT: call // CHECK: } // basic_iostream's deleting dtor calls its complete dtor, then // operator delete(). -// CHECK: define linkonce_odr unnamed_addr void @_ZN14basic_iostreamIcED0Ev +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr // CHECK: call void @_ZN14basic_iostreamIcED1Ev // CHECK: call void @_ZdlPv // basic_istream's complete dtor calls the base dtor, // then its virtual base's base dtor. -// CHECK: define linkonce_odr unnamed_addr void @_ZN13basic_istreamIcED1Ev +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr // CHECK: call void @_ZN13basic_istreamIcED2Ev // CHECK: call void @_ZN9basic_iosD2Ev // basic_istream's deleting dtor calls the complete dtor, then // operator delete(). -// CHECK: define linkonce_odr unnamed_addr void @_ZN13basic_istreamIcED0Ev +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr // CHECK: call void @_ZN13basic_istreamIcED1Ev // CHECK: call void @_ZdlPv Modified: cfe/trunk/test/CodeGenCXX/virtual-bases.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-bases.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/virtual-bases.cpp (original) +++ cfe/trunk/test/CodeGenCXX/virtual-bases.cpp Tue Jan 25 13:10:24 2011 @@ -5,23 +5,23 @@ }; // CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev -// CHECK: define unnamed_addr void @_ZN1AC2Ev(%struct.A* %this) +// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr A::A() { } struct B : virtual A { B(); }; -// CHECK: define unnamed_addr void @_ZN1BC1Ev(%struct.B* %this) -// CHECK: define unnamed_addr void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) +// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr B::B() { } struct C : virtual A { C(bool); }; -// CHECK: define unnamed_addr void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) -// CHECK: define unnamed_addr void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext) +// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) unnamed_addr +// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext) unnamed_addr C::C(bool) { } // PR6251 @@ -39,7 +39,7 @@ D(); }; -// CHECK: define unnamed_addr void @_ZN6PR62511DC1Ev +// CHECK: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr // CHECK: call void @_ZN6PR62511AIcEC2Ev // CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev // CHECK: ret void Modified: cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp (original) +++ cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp Tue Jan 25 13:10:24 2011 @@ -21,12 +21,12 @@ // CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev // Deleting dtor: defers to the complete dtor. -// CHECK: define unnamed_addr void @_ZN1BD0Ev +// CHECK: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN1BD1Ev // CHECK: call void @_ZdlPv // Base dtor: actually calls A's base dtor. -// CHECK: define unnamed_addr void @_ZN1BD2Ev +// CHECK: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN6MemberD1Ev // CHECK: call void @_ZN1AD2Ev @@ -41,7 +41,7 @@ // Complete dtor: just an alias (checked above). // Deleting dtor: defers to the complete dtor. -// CHECK: define unnamed_addr void @_ZN1CD0Ev +// CHECK: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN1CD1Ev // CHECK: call void @_ZdlPv Modified: cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp Tue Jan 25 13:10:24 2011 @@ -19,14 +19,14 @@ Field field; }; -// CHECK: define unnamed_addr void @_ZN1AC2Ev( +// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev( // CHECK: ret void A::A() { } -// CHECK: define unnamed_addr void @_ZN1AD2Ev( +// CHECK: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( @@ -41,16 +41,16 @@ void f() { B b; } -// CHECK: define linkonce_odr unnamed_addr void @_ZN1BC1Ev( +// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.A* %this) unnamed_addr // CHECK: call void @_ZN1BC2Ev( -// CHECK: define linkonce_odr unnamed_addr void @_ZN1BD1Ev( +// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.A* %this) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( // CHECK: ret void -// CHECK: define linkonce_odr unnamed_addr void @_ZN1BC2Ev( +// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.A* %this) unnamed_addr // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev Modified: cfe/trunk/test/CodeGenObjCXX/implicit-copy-constructor.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/implicit-copy-constructor.mm?rev=124210&r1=124209&r2=124210&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjCXX/implicit-copy-constructor.mm (original) +++ cfe/trunk/test/CodeGenObjCXX/implicit-copy-constructor.mm Tue Jan 25 13:10:24 2011 @@ -41,7 +41,7 @@ D d2(d); } -// CHECK: define linkonce_odr unnamed_addr void @_ZN1DC1ERS_ +// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr // CHECK: call void @_ZN1AC1Ev // CHECK: call void @_ZN1CC2ERS_1A // CHECK: call void @_ZN1AD1Ev From dgregor at apple.com Tue Jan 25 11:13:19 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 19:13:19 -0000 Subject: [cfe-commits] r124211 - in /cfe/trunk: include/clang/AST/TypeLoc.h lib/AST/ASTContext.cpp lib/AST/TypeLoc.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaType.cpp lib/Sema/TreeTransform.h Message-ID: <20110125191319.342742A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 13:13:18 2011 New Revision: 124211 URL: http://llvm.org/viewvc/llvm-project?rev=124211&view=rev Log: Teach TemplateSpecializationTypeLoc::initializeArgLocs() to actually generate meaningful [*] template argument location information. [*] Well, as meaningful as possible, given that this entire code path is a hack for when we've lost type-source information. Modified: cfe/trunk/include/clang/AST/TypeLoc.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/TypeLoc.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/AST/TypeLoc.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/TypeLoc.h (original) +++ cfe/trunk/include/clang/AST/TypeLoc.h Tue Jan 25 13:13:18 2011 @@ -20,6 +20,7 @@ #include "clang/Basic/Specifiers.h" namespace clang { + class ASTContext; class ParmVarDecl; class TypeSourceInfo; class UnqualTypeLoc; @@ -126,8 +127,8 @@ /// /// This method exists to provide a simple transition for code that /// relies on location-less types. - void initialize(SourceLocation Loc) const { - initializeImpl(*this, Loc); + void initialize(ASTContext &Context, SourceLocation Loc) const { + initializeImpl(Context, *this, Loc); } /// \brief Initializes this by copying its information from another @@ -158,7 +159,7 @@ static bool classof(const TypeLoc *TL) { return true; } private: - static void initializeImpl(TypeLoc TL, SourceLocation Loc); + static void initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc); static TypeLoc getNextTypeLocImpl(TypeLoc TL); static TypeLoc IgnoreParensImpl(TypeLoc TL); static SourceRange getLocalSourceRangeImpl(TypeLoc TL); @@ -207,7 +208,7 @@ /// Initializes the local data of this type source info block to /// provide no information. - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { // do nothing } @@ -407,7 +408,7 @@ SourceRange getLocalSourceRange() const { return SourceRange(getNameLoc(), getNameLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); } @@ -508,7 +509,7 @@ getWrittenBuiltinSpecs().ModeAttr = written; } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setBuiltinLoc(Loc); if (needsExtraLocalData()) { WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs(); @@ -707,7 +708,7 @@ return range; } - void initializeLocal(SourceLocation loc) { + void initializeLocal(ASTContext &Context, SourceLocation loc) { setAttrNameLoc(loc); if (hasAttrExprOperand()) { setAttrOperandParensRange(SourceRange(loc)); @@ -793,7 +794,7 @@ return SourceRange(getLAngleLoc(), getRAngleLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setHasBaseTypeAsWritten(true); setLAngleLoc(Loc); setRAngleLoc(Loc); @@ -837,7 +838,7 @@ return SourceRange(getNameLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); } }; @@ -868,7 +869,7 @@ return SourceRange(getLParenLoc(), getRParenLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLParenLoc(Loc); setRParenLoc(Loc); } @@ -907,7 +908,7 @@ return SourceRange(getSigilLoc(), getSigilLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setSigilLoc(Loc); } @@ -1058,7 +1059,7 @@ return SourceRange(getLParenLoc(), getRParenLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLParenLoc(Loc); setRParenLoc(Loc); setTrailingReturn(false); @@ -1132,7 +1133,7 @@ return SourceRange(getLBracketLoc(), getRBracketLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLBracketLoc(Loc); setRBracketLoc(Loc); setSizeExpr(NULL); @@ -1234,24 +1235,18 @@ return SourceRange(getTemplateNameLoc(), getRAngleLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLAngleLoc(Loc); setRAngleLoc(Loc); setTemplateNameLoc(Loc); - initializeArgLocs(getNumArgs(), getTypePtr()->getArgs(), + initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); } - static void initializeArgLocs(unsigned NumArgs, + static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, const TemplateArgument *Args, TemplateArgumentLocInfo *ArgInfos, - SourceLocation Loc) { - for (unsigned i = 0, e = NumArgs; i != e; ++i) { - // FIXME: We can generate better location info here for type arguments, - // template template arguments, and template template pack expansions (?). - ArgInfos[i] = TemplateArgumentLocInfo(); - } - } + SourceLocation Loc); unsigned getExtraLocalDataSize() const { return getNumArgs() * sizeof(TemplateArgumentLocInfo); @@ -1346,7 +1341,7 @@ return SourceRange(getTypeofLoc(), getRParenLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setTypeofLoc(Loc); setLParenLoc(Loc); setRParenLoc(Loc); @@ -1420,7 +1415,7 @@ return getQualifierRange(); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); } @@ -1485,7 +1480,7 @@ memcpy(Data, Loc.Data, size); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); setNameLoc(Loc); @@ -1569,13 +1564,13 @@ memcpy(Data, Loc.Data, size); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); setNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(getNumArgs(), + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); } @@ -1611,7 +1606,7 @@ return SourceRange(getEllipsisLoc(), getEllipsisLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setEllipsisLoc(Loc); } Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Tue Jan 25 13:13:18 2011 @@ -1127,7 +1127,7 @@ TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, SourceLocation L) const { TypeSourceInfo *DI = CreateTypeSourceInfo(T); - DI->getTypeLoc().initialize(L); + DI->getTypeLoc().initialize(const_cast(*this), L); return DI; } Modified: cfe/trunk/lib/AST/TypeLoc.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/lib/AST/TypeLoc.cpp (original) +++ cfe/trunk/lib/AST/TypeLoc.cpp Tue Jan 25 13:13:18 2011 @@ -77,14 +77,15 @@ /// \brief Initializes a type location, and all of its children /// recursively, as if the entire tree had been written in the /// given location. -void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { +void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc) { while (true) { switch (TL.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case CLASS: { \ CLASS##TypeLoc TLCasted = cast(TL); \ - TLCasted.initializeLocal(Loc); \ + TLCasted.initializeLocal(Context, Loc); \ TL = TLCasted.getNextTypeLoc(); \ if (!TL) return; \ continue; \ @@ -229,3 +230,38 @@ TL = PTL->getInnerLoc(); return TL; } + +void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, + unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc) { + for (unsigned i = 0, e = NumArgs; i != e; ++i) { + switch (Args[i].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Expression: + // FIXME: Can we do better for declarations and integral values? + ArgInfos[i] = TemplateArgumentLocInfo(); + break; + + case TemplateArgument::Type: + ArgInfos[i] = TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(Args[i].getAsType(), + Loc)); + break; + + case TemplateArgument::Template: + ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, + SourceLocation()); + break; + + case TemplateArgument::TemplateExpansion: + ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc); + break; + } + } +} + Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Jan 25 13:13:18 2011 @@ -5901,7 +5901,8 @@ if (InnerTSI) Builder.pushFullCopy(InnerTSI->getTypeLoc()); else - Builder.push(T).initialize(TemplateLoc); + Builder.push(T).initialize(Context, + TemplateLoc); /* Note: NNS already embedded in template specialization type T. */ T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T); @@ -5937,7 +5938,8 @@ for (unsigned I = 0, E = TST->getNumArgs(); I != E; ++I) TL.setArgLocInfo(I, TSTL.getArgLocInfo(I)); } else { - TL.initializeLocal(SourceLocation()); + // FIXME: Poor source-location information here. + TL.initializeLocal(Context, TemplateLoc); } TL.setKeywordLoc(TypenameLoc); TL.setQualifierRange(SS.getRange()); Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 13:13:18 2011 @@ -1972,10 +1972,12 @@ namespace { class TypeSpecLocFiller : public TypeLocVisitor { + ASTContext &Context; const DeclSpec &DS; public: - TypeSpecLocFiller(const DeclSpec &DS) : DS(DS) {} + TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) + : Context(Context), DS(DS) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); @@ -1990,7 +1992,7 @@ // Handle the base type, which might not have been written explicitly. if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { TL.setHasBaseTypeAsWritten(false); - TL.getBaseLoc().initialize(SourceLocation()); + TL.getBaseLoc().initialize(Context, SourceLocation()); } else { TL.setHasBaseTypeAsWritten(true); Visit(TL.getBaseLoc()); @@ -2021,7 +2023,7 @@ // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. if (!TInfo) { - TL.initialize(DS.getTypeSpecTypeLoc()); + TL.initialize(Context, DS.getTypeSpecTypeLoc()); return; } @@ -2114,7 +2116,7 @@ return; } } - TL.initializeLocal(SourceLocation()); + TL.initializeLocal(Context, SourceLocation()); TL.setKeywordLoc(Keyword != ETK_None ? DS.getTypeSpecTypeLoc() : SourceLocation()); @@ -2126,7 +2128,7 @@ void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. - TL.initialize(DS.getTypeSpecTypeLoc()); + TL.initialize(Context, DS.getTypeSpecTypeLoc()); } }; @@ -2231,7 +2233,7 @@ assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL); } return TInfo; Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=124211&r1=124210&r2=124211&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Jan 25 13:13:18 2011 @@ -2980,8 +2980,8 @@ // Temporary workaround. All of these transformations should // eventually turn into transformations on TypeLocs. - TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); - DI->getTypeLoc().initialize(getDerived().getBaseLocation()); + TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T, + getDerived().getBaseLocation()); TypeSourceInfo *NewDI = getDerived().TransformType(DI); @@ -3073,7 +3073,7 @@ return T; TypeSourceInfo *TSI = - SemaRef.Context.getTrivialTypeSourceInfo(T, getBaseLocation()); + SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); TSI = getDerived().TransformTypeInObjectScope(TSI, ObjectType, UnqualLookup, Prefix); From kremenek at apple.com Tue Jan 25 11:13:43 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 19:13:43 -0000 Subject: [cfe-commits] r124212 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp test/Analysis/blocks.m Message-ID: <20110125191343.1EAD22A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 13:13:42 2011 New Revision: 124212 URL: http://llvm.org/viewvc/llvm-project?rev=124212&view=rev Log: Tweak wording of static analyzer diagnostic for a block capturing the value of an uninitialized variable. Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp cfe/trunk/test/Analysis/blocks.m Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp?rev=124212&r1=124211&r2=124212&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp Tue Jan 25 13:13:42 2011 @@ -82,14 +82,14 @@ if (state->getSVal(VR).isUndef()) if (ExplodedNode *N = C.generateSink()) { if (!BT) - BT = new BuiltinBug("Captured block variable is uninitialized"); + BT = new BuiltinBug("uninitialized variable captured by block"); // Generate a bug report. llvm::SmallString<128> buf; llvm::raw_svector_ostream os(buf); - os << "Variable '" << VD->getName() << "' is captured by block with " - "a garbage value"; + os << "Variable '" << VD->getName() + << "' is uninitialized when captured by block"; EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) Modified: cfe/trunk/test/Analysis/blocks.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/blocks.m?rev=124212&r1=124211&r2=124212&view=diff ============================================================================== --- cfe/trunk/test/Analysis/blocks.m (original) +++ cfe/trunk/test/Analysis/blocks.m Tue Jan 25 13:13:42 2011 @@ -73,7 +73,7 @@ void test2() { static int y = 0; int x; - ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is captured by block with a garbage value}} + ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}} } void test2_b() { @@ -86,5 +86,5 @@ void test2_c() { typedef void (^myblock)(void); - myblock f = ^() { f(); }; // expected-warning{{Variable 'f' is captured by block with a garbage value}} + myblock f = ^() { f(); }; // expected-warning{{Variable 'f' is uninitialized when captured by block}} } \ No newline at end of file From kremenek at apple.com Tue Jan 25 11:13:48 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 19:13:48 -0000 Subject: [cfe-commits] r124213 - in /cfe/trunk: include/clang/Analysis/Analyses/UninitializedValuesV2.h include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/UninitializedValuesV2.cpp lib/Sema/AnalysisBasedWarnings.cpp test/Sema/uninit-variables.c Message-ID: <20110125191348.B2FCB2A6C12D@llvm.org> Author: kremenek Date: Tue Jan 25 13:13:48 2011 New Revision: 124213 URL: http://llvm.org/viewvc/llvm-project?rev=124213&view=rev Log: Teach -Wuninitialized-experimental to also warn about uninitialized variables captured by blocks. Modified: cfe/trunk/include/clang/Analysis/Analyses/UninitializedValuesV2.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp cfe/trunk/test/Sema/uninit-variables.c Modified: cfe/trunk/include/clang/Analysis/Analyses/UninitializedValuesV2.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/UninitializedValuesV2.h?rev=124213&r1=124212&r2=124213&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/UninitializedValuesV2.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/UninitializedValuesV2.h Tue Jan 25 13:13:48 2011 @@ -17,9 +17,10 @@ namespace clang { +class AnalysisContext; class CFG; class DeclContext; -class DeclRefExpr; +class Expr; class VarDecl; class UninitVariablesHandler { @@ -27,11 +28,12 @@ UninitVariablesHandler() {} virtual ~UninitVariablesHandler(); - virtual void handleUseOfUninitVariable(const DeclRefExpr *dr, + virtual void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) {} }; void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, UninitVariablesHandler &handler); } Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124213&r1=124212&r2=124213&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 13:13:48 2011 @@ -822,10 +822,12 @@ "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup>; -def warn_var_is_uninit : Warning<"use of uninitialized variable %0">, +def warn_uninit_var : Warning<"use of uninitialized variable %0">, InGroup>, DefaultIgnore; -def note_var_is_uninit : Note< +def note_uninit_var : Note< "variable %0 is possibly uninitialized when used here">; +def note_uninit_var_captured_by_block : Note< + "variable %0 is possibly uninitialized when captured by block">; def note_var_fixit_add_initialization : Note< "add initialization to silence this warning">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp?rev=124213&r1=124212&r2=124213&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp (original) +++ cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Tue Jan 25 13:13:48 2011 @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/Analyses/UninitializedValuesV2.h" #include "clang/Analysis/Support/SaveAndRestore.h" @@ -287,16 +288,22 @@ class TransferFunctions : public CFGRecStmtVisitor { CFGBlockValues &vals; const CFG &cfg; + AnalysisContext ∾ UninitVariablesHandler *handler; const DeclRefExpr *currentDR; + const bool flagBlockUses; public: TransferFunctions(CFGBlockValues &vals, const CFG &cfg, - UninitVariablesHandler *handler) - : vals(vals), cfg(cfg), handler(handler), currentDR(0) {} + AnalysisContext &ac, + UninitVariablesHandler *handler, + bool flagBlockUses) + : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), + flagBlockUses(flagBlockUses) {} const CFG &getCFG() { return cfg; } void reportUninit(const DeclRefExpr *ex, const VarDecl *vd); - + + void VisitBlockExpr(BlockExpr *be); void VisitDeclStmt(DeclStmt *ds); void VisitDeclRefExpr(DeclRefExpr *dr); void VisitUnaryOperator(UnaryOperator *uo); @@ -311,6 +318,20 @@ if (handler) handler->handleUseOfUninitVariable(ex, vd); } +void TransferFunctions::VisitBlockExpr(BlockExpr *be) { + if (!flagBlockUses || !handler) + return; + AnalysisContext::referenced_decls_iterator i, e; + llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl()); + for ( ; i != e; ++i) { + const VarDecl *vd = *i; + if (vd->getAttr() || !vd->hasLocalStorage()) + continue; + if (vals[vd] == Uninitialized) + handler->handleUseOfUninitVariable(be, vd); + } +} + void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); DI != DE; ++DI) { @@ -450,8 +471,9 @@ //====------------------------------------------------------------------------// static bool runOnBlock(const CFGBlock *block, const CFG &cfg, - CFGBlockValues &vals, - UninitVariablesHandler *handler = 0) { + AnalysisContext &ac, CFGBlockValues &vals, + UninitVariablesHandler *handler = 0, + bool flagBlockUses = false) { if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { if (block->pred_size() == 2 && block->succ_size() == 2) { @@ -478,7 +500,7 @@ isFirst = false; } // Apply the transfer function. - TransferFunctions tf(vals, cfg, handler); + TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses); for (CFGBlock::const_iterator I = block->begin(), E = block->end(); I != E; ++I) { if (const CFGStmt *cs = dyn_cast(&*I)) { @@ -490,6 +512,7 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, UninitVariablesHandler &handler) { CFGBlockValues vals(cfg); vals.computeSetOfDeclarations(dc); @@ -502,7 +525,7 @@ while (const CFGBlock *block = worklist.dequeue()) { // Did the block change? - bool changed = runOnBlock(block, cfg, vals); + bool changed = runOnBlock(block, cfg, ac, vals); if (changed || !previouslyVisited[block->getBlockID()]) worklist.enqueueSuccessors(block); previouslyVisited[block->getBlockID()] = true; @@ -510,7 +533,7 @@ // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { - runOnBlock(*BI, cfg, vals, &handler); + runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true); } } Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124213&r1=124212&r2=124213&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Jan 25 13:13:48 2011 @@ -366,7 +366,7 @@ namespace { struct SLocSort { - bool operator()(const DeclRefExpr *a, const DeclRefExpr *b) { + bool operator()(const Expr *a, const Expr *b) { SourceLocation aLoc = a->getLocStart(); SourceLocation bLoc = b->getLocStart(); return aLoc.getRawEncoding() < bLoc.getRawEncoding(); @@ -375,7 +375,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector UsesVec; + typedef llvm::SmallVector UsesVec; typedef llvm::DenseMap UsesMap; UsesMap *uses; @@ -385,7 +385,7 @@ flushDiagnostics(); } - void handleUseOfUninitVariable(const DeclRefExpr *dr, const VarDecl *vd) { + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) { if (!uses) uses = new UsesMap(); @@ -393,7 +393,7 @@ if (!vec) vec = new UsesVec(); - vec->push_back(dr); + vec->push_back(ex); } void flushDiagnostics() { @@ -404,7 +404,7 @@ const VarDecl *vd = i->first; UsesVec *vec = i->second; - S.Diag(vd->getLocStart(), diag::warn_var_is_uninit) + S.Diag(vd->getLocStart(), diag::warn_uninit_var) << vd->getDeclName() << vd->getSourceRange(); // Sort the uses by their SourceLocations. While not strictly @@ -414,9 +414,15 @@ for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) { - const DeclRefExpr *dr = *vi; - S.Diag(dr->getLocStart(), diag::note_var_is_uninit) - << vd->getDeclName() << dr->getSourceRange(); + if (const DeclRefExpr *dr = dyn_cast(*vi)) { + S.Diag(dr->getLocStart(), diag::note_uninit_var) + << vd->getDeclName() << dr->getSourceRange(); + } + else { + const BlockExpr *be = cast(*vi); + S.Diag(be->getLocStart(), diag::note_uninit_var_captured_by_block) + << vd->getDeclName(); + } } // Suggest possible initialization (if any). @@ -514,11 +520,12 @@ if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - if (Diags.getDiagnosticLevel(diag::warn_var_is_uninit, D->getLocStart()) + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) != Diagnostic::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); - runUninitializedVariablesAnalysis(*cast(D), *cfg, reporter); + runUninitializedVariablesAnalysis(*cast(D), *cfg, AC, + reporter); } } } Modified: cfe/trunk/test/Sema/uninit-variables.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124213&r1=124212&r2=124213&view=diff ============================================================================== --- cfe/trunk/test/Sema/uninit-variables.c (original) +++ cfe/trunk/test/Sema/uninit-variables.c Tue Jan 25 13:13:48 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only %s -verify +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify int test1() { int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} @@ -192,3 +192,23 @@ return sizeof(int[len]); // expected-note{{variable 'len' is possibly uninitialized when used here}} } +void test29() { + int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} + (void) ^{ (void) x; }; // expected-note{{variable 'x' is possibly uninitialized when captured by block}} +} + +void test30() { + static int x; // no-warning + (void) ^{ (void) x; }; +} + +void test31() { + __block int x; // no-warning + (void) ^{ (void) x; }; +} + +int test32_x; +void test32() { + (void) ^{ (void) test32_x; }; // no-warning +} + From kremenek at apple.com Tue Jan 25 11:13:54 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 19:13:54 -0000 Subject: [cfe-commits] r124214 - in /cfe/trunk: include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h include/clang/StaticAnalyzer/PathSensitive/GRState.h lib/StaticAnalyzer/Checkers/ExprEngine.cpp lib/StaticAnalyzer/GRState.cpp Message-ID: <20110125191354.915542A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 13:13:54 2011 New Revision: 124214 URL: http://llvm.org/viewvc/llvm-project?rev=124214&view=rev Log: Recycle memory for GRStates that are never referenced by ExplodedNodes. This leads to about a 4-8% reduction in memory footprint when analyzing functions in sqlite3. Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/GRState.h cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/GRState.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h?rev=124214&r1=124213&r2=124214&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h Tue Jan 25 13:13:54 2011 @@ -31,6 +31,7 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/Support/Casting.h" #include "clang/Analysis/Support/BumpVector.h" +#include "clang/StaticAnalyzer/PathSensitive/GRState.h" namespace clang { @@ -38,7 +39,6 @@ namespace ento { -class GRState; class ExplodedGraph; //===----------------------------------------------------------------------===// @@ -115,7 +115,9 @@ public: explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) - : Location(loc), State(state) {} + : Location(loc), State(state) { + const_cast(State)->setReferencedByExplodedNode(); + } /// getLocation - Returns the edge associated with the given node. ProgramPoint getLocation() const { return Location; } Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/GRState.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/GRState.h?rev=124214&r1=124213&r2=124214&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/GRState.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/GRState.h Tue Jan 25 13:13:54 2011 @@ -18,6 +18,7 @@ #include "clang/StaticAnalyzer/PathSensitive/Environment.h" #include "clang/StaticAnalyzer/PathSensitive/Store.h" #include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Casting.h" @@ -78,7 +79,7 @@ friend class GRStateManager; - GRStateManager *StateMgr; + llvm::PointerIntPair stateMgr; Environment Env; // Maps a Stmt to its current SVal. Store St; // Maps a location to its current value. GenericDataMap GDM; // Custom data stored by a client of this class. @@ -92,7 +93,7 @@ /// This ctor is used when creating the first GRState object. GRState(GRStateManager *mgr, const Environment& env, Store st, GenericDataMap gdm) - : StateMgr(mgr), + : stateMgr(mgr, false), Env(env), St(st), GDM(gdm) {} @@ -101,14 +102,23 @@ /// in FoldingSetNode will also get copied. GRState(const GRState& RHS) : llvm::FoldingSetNode(), - StateMgr(RHS.StateMgr), + stateMgr(RHS.stateMgr.getPointer(), false), Env(RHS.Env), St(RHS.St), GDM(RHS.GDM) {} - /// getStateManager - Return the GRStateManager associated with this state. + /// Return the GRStateManager associated with this state. GRStateManager &getStateManager() const { - return *StateMgr; + return *stateMgr.getPointer(); + } + + /// Return true if this state is referenced by a persistent ExplodedNode. + bool referencedByExplodedNode() const { + return stateMgr.getInt(); + } + + void setReferencedByExplodedNode() { + stateMgr.setInt(true); } /// getEnvironment - Return the environment associated with this state. @@ -428,9 +438,16 @@ /// Object that manages the data for all created SVals. llvm::OwningPtr svalBuilder; - /// Alloc - A BumpPtrAllocator to allocate states. + /// A BumpPtrAllocator to allocate states. llvm::BumpPtrAllocator &Alloc; + /// A vector of recently allocated GRStates that can potentially be + /// reused. + std::vector recentlyAllocatedStates; + + /// A vector of GRStates that we can reuse. + std::vector freeStates; + public: GRStateManager(ASTContext& Ctx, StoreManagerCreator CreateStoreManager, @@ -509,6 +526,10 @@ } const GRState* getPersistentState(GRState& Impl); + + /// Periodically called by ExprEngine to recycle GRStates that were + /// created but never used for creating an ExplodedNode. + void recycleUnusedStates(); //==---------------------------------------------------------------------==// // Generic Data Map methods. Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124214&r1=124213&r2=124214&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Tue Jan 25 13:13:54 2011 @@ -574,6 +574,9 @@ } void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { + // Recycle any unused states in the GRStateManager. + StateMgr.recycleUnusedStates(); + currentStmt = S.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), currentStmt->getLocStart(), Modified: cfe/trunk/lib/StaticAnalyzer/GRState.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/GRState.cpp?rev=124214&r1=124213&r2=124214&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/GRState.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/GRState.cpp Tue Jan 25 13:13:54 2011 @@ -285,6 +285,18 @@ return getPersistentState(State); } +void GRStateManager::recycleUnusedStates() { + for (std::vector::iterator i = recentlyAllocatedStates.begin(), + e = recentlyAllocatedStates.end(); i != e; ++i) { + GRState *state = *i; + if (state->referencedByExplodedNode()) + continue; + StateSet.RemoveNode(state); + freeStates.push_back(state); + } + recentlyAllocatedStates.clear(); +} + const GRState* GRStateManager::getPersistentState(GRState& State) { llvm::FoldingSetNodeID ID; @@ -294,10 +306,18 @@ if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) return I; - GRState* I = (GRState*) Alloc.Allocate(); - new (I) GRState(State); - StateSet.InsertNode(I, InsertPos); - return I; + GRState *newState = 0; + if (!freeStates.empty()) { + newState = freeStates.back(); + freeStates.pop_back(); + } + else { + newState = (GRState*) Alloc.Allocate(); + } + new (newState) GRState(State); + StateSet.InsertNode(newState, InsertPos); + recentlyAllocatedStates.push_back(newState); + return newState; } const GRState* GRState::makeWithStore(Store store) const { From dgregor at apple.com Tue Jan 25 11:39:31 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 19:39:31 -0000 Subject: [cfe-commits] r124216 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Message-ID: <20110125193931.640AD2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 13:39:31 2011 New Revision: 124216 URL: http://llvm.org/viewvc/llvm-project?rev=124216&view=rev Log: Fix the ranking of reference bindings during overload resolution (C++0x [over.ics.rank]p3) when one binding is an lvalue reference and the other is an rvalue reference that binds to an rvalue. In particular, we were using the predict "is an rvalue reference" rather than "is an rvalue reference that binds to an rvalue", which was incorrect in the one case where an rvalue reference can bind to an lvalue: function references. This particular issue cropped up with std::forward, where Clang was picking an std::forward overload while forwarding an (lvalue) reference to a function. However (and unfortunately!), the right answer for this code is that the call to std::forward is ambiguous. Clang now gets that right, but we need to revisit the std::forward implementation in libc++. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124216&r1=124215&r2=124216&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 25 13:39:31 2011 @@ -2966,7 +2966,7 @@ ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3036,7 +3036,7 @@ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; return ICS; } Modified: cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp?rev=124216&r1=124215&r2=124216&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Tue Jan 25 13:39:31 2011 @@ -15,7 +15,7 @@ float &k2 = g2(f1()); float &l2 = g2(f2()); - // FIXME: We don't support ref-qualifiers set. + // FIXME: We don't support ref-qualifiers yet. #if 0 struct A { A& operator<<(int); @@ -33,3 +33,27 @@ a.p(); #endif } + +template +struct remove_reference { + typedef T type; +}; + +template +struct remove_reference { + typedef T type; +}; + +template +struct remove_reference { + typedef T type; +}; + +namespace FunctionReferencesOverloading { + template int &f(typename remove_reference::type&); // expected-note{{candidate function [with T = int (&)(int)]}} + template float &f(typename remove_reference::type&&); // expected-note{{candidate function [with T = int (&)(int)]}} + + void test_f(int (&func_ref)(int)) { + f(func_ref); // expected-error{{call to 'f' is ambiguous}} + } +} From jyasskin at google.com Tue Jan 25 12:08:13 2011 From: jyasskin at google.com (Jeffrey Yasskin) Date: Tue, 25 Jan 2011 20:08:13 -0000 Subject: [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 Message-ID: <20110125200813.455432A6C12C@llvm.org> 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 @@
  • Messages on deprecated and unavailable attributes
  • Attributes on enumerators
  • +
  • Attribute to forbid temporaries of a type
  • Checks for Standard Language Features
  • Vectors and Extended Vectors
    • C++ exceptions
    • @@ -341,6 +342,33 @@

      Query for this feature with __has_feature(enumerator_attributes).

      +

      Attribute to forbid temporaries of a type

      + + +

      Clang provides a forbid_temporaries attribute to forbid +temporaries of a particular type.

      + +
      +
      class __attribute__((forbid_temporaries)) scoped_lock {
      +  ...
      +};
      +
      + +

      This prevents mistakes like

      + +
      +
      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.
      +};
      +
      + +

      Query for this feature with __has_attribute(forbid_temporaries). +Use -Wno-forbid-temporaries to disable the resulting warning.

      + +

      Checks for Standard Language Features

      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>; // 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(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(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(RT->getDecl()); + if (RD->getAttr()) + 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(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 +class __attribute__((forbid_temporaries)) NotATemporaryTpl { +}; + +template +void bar_tpl(const NotATemporaryTpl&); + +void tpl_user() { + NotATemporaryTpl this_is_fine; + bar_tpl(NotATemporaryTpl()); // expected-warning {{must not create temporaries of type 'NotATemporaryTpl'}} + NotATemporaryTpl(); // expected-warning {{must not create temporaries of type 'NotATemporaryTpl'}} +} + + +// Test that a specialization can override the template's default. +struct TemporariesOk; +template<> class NotATemporaryTpl { +}; + +void specialization_user() { + NotATemporaryTpl this_is_fine; + bar_tpl(NotATemporaryTpl()); + NotATemporaryTpl(); +} From nicolasweber at gmx.de Tue Jan 25 12:34:14 2011 From: nicolasweber at gmx.de (Nico Weber) Date: Tue, 25 Jan 2011 20:34:14 -0000 Subject: [cfe-commits] r124227 - in /cfe/trunk: include/clang/AST/ASTMutationListener.h include/clang/CodeGen/CodeGenAction.h include/clang/Driver/CC1Options.td include/clang/Frontend/FrontendAction.h include/clang/Frontend/FrontendOptions.h include/clang/Frontend/MultiplexConsumer.h lib/CodeGen/CodeGenAction.cpp lib/Frontend/CompilerInvocation.cpp lib/Frontend/FrontendAction.cpp lib/Frontend/MultiplexConsumer.cpp Message-ID: <20110125203414.B60032A6C12C@llvm.org> Author: nico Date: Tue Jan 25 14:34:14 2011 New Revision: 124227 URL: http://llvm.org/viewvc/llvm-project?rev=124227&view=rev Log: Add -add-plugin flag, which runs plugins in addition to codegen. Added: cfe/trunk/include/clang/Frontend/MultiplexConsumer.h cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h cfe/trunk/include/clang/CodeGen/CodeGenAction.h cfe/trunk/include/clang/Driver/CC1Options.td cfe/trunk/include/clang/Frontend/FrontendAction.h cfe/trunk/include/clang/Frontend/FrontendOptions.h cfe/trunk/lib/CodeGen/CodeGenAction.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/Frontend/FrontendAction.cpp Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTMutationListener.h (original) +++ cfe/trunk/include/clang/AST/ASTMutationListener.h Tue Jan 25 14:34:14 2011 @@ -15,6 +15,7 @@ namespace clang { class Decl; + class DeclContext; class TagDecl; class CXXRecordDecl; class ClassTemplateDecl; Modified: cfe/trunk/include/clang/CodeGen/CodeGenAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/CodeGenAction.h?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/include/clang/CodeGen/CodeGenAction.h (original) +++ cfe/trunk/include/clang/CodeGen/CodeGenAction.h Tue Jan 25 14:34:14 2011 @@ -18,6 +18,7 @@ } namespace clang { +class BackendConsumer; class CodeGenAction : public ASTFrontendAction { private: @@ -42,6 +43,8 @@ /// takeModule - Take the generated LLVM module, for use after the action has /// been run. The result may be null on failure. llvm::Module *takeModule(); + + BackendConsumer *BEConsumer; }; class EmitAssemblyAction : public CodeGenAction { Modified: cfe/trunk/include/clang/Driver/CC1Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td (original) +++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Jan 25 14:34:14 2011 @@ -290,10 +290,12 @@ def load : Separate<"-load">, MetaVarName<"">, HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<"-plugin">, MetaVarName<"">, - HelpText<"Use the named plugin action (use \"help\" to list available options)">; + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, MetaVarName<" ">, HelpText<"Pass to plugin ">; +def add_plugin : Separate<"-add-plugin">, MetaVarName<"">, + HelpText<"Use the named plugin action in addition to the default action">; def resource_dir : Separate<"-resource-dir">, HelpText<"The directory which holds the compiler resource files">; def version : Flag<"-version">, Modified: cfe/trunk/include/clang/Frontend/FrontendAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/FrontendAction.h (original) +++ cfe/trunk/include/clang/Frontend/FrontendAction.h Tue Jan 25 14:34:14 2011 @@ -52,6 +52,10 @@ CompilerInstance *Instance; friend class ASTMergeAction; +private: + ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); + protected: /// @name Implementation Action Interface /// @{ Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original) +++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Tue Jan 25 14:34:14 2011 @@ -103,6 +103,9 @@ /// Arg to pass to the plugin std::vector PluginArgs; + /// The list of plugin actions to run in addition to the normal action. + std::vector AddPluginActions; + /// The list of plugins to load. std::vector Plugins; Added: cfe/trunk/include/clang/Frontend/MultiplexConsumer.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/MultiplexConsumer.h?rev=124227&view=auto ============================================================================== --- cfe/trunk/include/clang/Frontend/MultiplexConsumer.h (added) +++ cfe/trunk/include/clang/Frontend/MultiplexConsumer.h Tue Jan 25 14:34:14 2011 @@ -0,0 +1,54 @@ +//===-- MultiplexConsumer.h - AST Consumer for PCH Generation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MultiplexConsumer class, which can be used to +// multiplex ASTConsumer and SemaConsumer messages to many consumers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaConsumer.h" +#include "llvm/ADT/OwningPtr.h" +#include + +namespace clang { + +class MultiplexASTMutationListener; +class MultiplexASTDeserializationListener; + +// Has a list of ASTConsumers and calls each of them. Owns its children. +class MultiplexConsumer : public SemaConsumer { +public: + // Takes ownership of the pointers in C. + MultiplexConsumer(const std::vector& C); + ~MultiplexConsumer(); + + // ASTConsumer + virtual void Initialize(ASTContext &Context); + virtual void HandleTopLevelDecl(DeclGroupRef D); + virtual void HandleInterestingDecl(DeclGroupRef D); + virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual void HandleTagDeclDefinition(TagDecl *D); + virtual void CompleteTentativeDefinition(VarDecl *D); + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired); + virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTDeserializationListener *GetASTDeserializationListener(); + virtual void PrintStats(); + + // SemaConsumer + virtual void InitializeSema(Sema &S); + virtual void ForgetSema(); + + static bool classof(const MultiplexConsumer *) { return true; } +private: + std::vector Consumers; // Owns these. + llvm::OwningPtr MutationListener; + llvm::OwningPtr DeserializationListener; +}; + +} // end namespace clang Modified: cfe/trunk/lib/CodeGen/CodeGenAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenAction.cpp?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenAction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenAction.cpp Tue Jan 25 14:34:14 2011 @@ -28,7 +28,7 @@ using namespace clang; using namespace llvm; -namespace { +namespace clang { class BackendConsumer : public ASTConsumer { Diagnostic &Diags; BackendAction Action; @@ -236,10 +236,7 @@ return; // Steal the module from the consumer. - BackendConsumer *Consumer = static_cast( - &getCompilerInstance().getASTConsumer()); - - TheModule.reset(Consumer->takeModule()); + TheModule.reset(BEConsumer->takeModule()); } llvm::Module *CodeGenAction::takeModule() { @@ -274,10 +271,12 @@ if (BA != Backend_EmitNothing && !OS) return 0; - return new BackendConsumer(BA, CI.getDiagnostics(), - CI.getCodeGenOpts(), CI.getTargetOpts(), - CI.getFrontendOpts().ShowTimers, InFile, OS.take(), - CI.getLLVMContext()); + BEConsumer = + new BackendConsumer(BA, CI.getDiagnostics(), + CI.getCodeGenOpts(), CI.getTargetOpts(), + CI.getFrontendOpts().ShowTimers, InFile, OS.take(), + CI.getLLVMContext()); + return BEConsumer; } void CodeGenAction::ExecuteAction() { Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Jan 25 14:34:14 2011 @@ -433,6 +433,10 @@ Res.push_back("-load"); Res.push_back(Opts.Plugins[i]); } + for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { + Res.push_back("-add-plugin"); + Res.push_back(Opts.AddPluginActions[i]); + } for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); @@ -1098,6 +1102,8 @@ } } + Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = ParsedSourceLocation::FromString(A->getValue(Args)); Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=124227&r1=124226&r2=124227&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/FrontendAction.cpp (original) +++ cfe/trunk/lib/Frontend/FrontendAction.cpp Tue Jan 25 14:34:14 2011 @@ -10,11 +10,14 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclGroup.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "llvm/Support/MemoryBuffer.h" @@ -85,6 +88,39 @@ CurrentASTUnit.reset(AST); } +ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + ASTConsumer* Consumer = CreateASTConsumer(CI, InFile); + if (!Consumer) + return 0; + + if (CI.getFrontendOpts().AddPluginActions.size() == 0) + return Consumer; + + // Make sure the non-plugin consumer is first, so that plugins can't + // modifiy the AST. + std::vector Consumers(1, Consumer); + + for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size(); + i != e; ++i) { + // This is O(|plugins| * |add_plugins|), but since both numbers are + // way below 50 in practice, that's ok. + for (FrontendPluginRegistry::iterator + it = FrontendPluginRegistry::begin(), + ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) { + llvm::OwningPtr P(it->instantiate()); + FrontendAction* c = P.get(); + if (P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) + Consumers.push_back(c->CreateASTConsumer(CI, InFile)); + } + } + } + + return new MultiplexConsumer(Consumers); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, llvm::StringRef Filename, InputKind InputKind) { @@ -122,7 +158,7 @@ goto failure; /// Create the AST consumer. - CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + CI.setASTConsumer(CreateWrappedASTConsumer(CI, Filename)); if (!CI.hasASTConsumer()) goto failure; @@ -166,7 +202,8 @@ if (!usesPreprocessorOnly()) { CI.createASTContext(); - llvm::OwningPtr Consumer(CreateASTConsumer(CI, Filename)); + llvm::OwningPtr Consumer( + CreateWrappedASTConsumer(CI, Filename)); if (!Consumer) goto failure; Added: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=124227&view=auto ============================================================================== --- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (added) +++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Tue Jan 25 14:34:14 2011 @@ -0,0 +1,221 @@ +//===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MultiplexConsumer class. It also declares and defines +// MultiplexASTDeserializationListener and MultiplexASTMutationListener, which +// are implementation details of MultiplexConsumer. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/MultiplexConsumer.h" + +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Serialization/ASTDeserializationListener.h" + +using namespace clang; + +namespace clang { + +// This ASTDeserializationListener forwards its notifications to a set of +// child listeners. +class MultiplexASTDeserializationListener + : public ASTDeserializationListener { +public: + // Does NOT take ownership of the elements in L. + MultiplexASTDeserializationListener( + const std::vector& L); + virtual void ReaderInitialized(ASTReader *Reader); + virtual void IdentifierRead(serialization::IdentID ID, + IdentifierInfo *II); + virtual void TypeRead(serialization::TypeIdx Idx, QualType T); + virtual void DeclRead(serialization::DeclID ID, const Decl *D); + virtual void SelectorRead(serialization::SelectorID iD, Selector Sel); + virtual void MacroDefinitionRead(serialization::MacroID, + MacroDefinition *MD); +private: + std::vector Listeners; +}; + +MultiplexASTDeserializationListener::MultiplexASTDeserializationListener( + const std::vector& L) + : Listeners(L) { +} + +void MultiplexASTDeserializationListener::ReaderInitialized( + ASTReader *Reader) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->ReaderInitialized(Reader); +} + +void MultiplexASTDeserializationListener::IdentifierRead( + serialization::IdentID ID, IdentifierInfo *II) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->IdentifierRead(ID, II); +} + +void MultiplexASTDeserializationListener::TypeRead( + serialization::TypeIdx Idx, QualType T) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->TypeRead(Idx, T); +} + +void MultiplexASTDeserializationListener::DeclRead( + serialization::DeclID ID, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->DeclRead(ID, D); +} + +void MultiplexASTDeserializationListener::SelectorRead( + serialization::SelectorID ID, Selector Sel) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->SelectorRead(ID, Sel); +} + +void MultiplexASTDeserializationListener::MacroDefinitionRead( + serialization::MacroID ID, MacroDefinition *MD) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->MacroDefinitionRead(ID, MD); +} + +// This ASTMutationListener forwards its notifications to a set of +// child listeners. +class MultiplexASTMutationListener : public ASTMutationListener { +public: + // Does NOT take ownership of the elements in L. + MultiplexASTMutationListener(const std::vector& L); + virtual void CompletedTagDefinition(const TagDecl *D); + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D); + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D); +private: + std::vector Listeners; +}; + +MultiplexASTMutationListener::MultiplexASTMutationListener( + const std::vector& L) + : Listeners(L) { +} + +void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->CompletedTagDefinition(D); +} + +void MultiplexASTMutationListener::AddedVisibleDecl( + const DeclContext *DC, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedVisibleDecl(DC, D); +} + +void MultiplexASTMutationListener::AddedCXXImplicitMember( + const CXXRecordDecl *RD, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXImplicitMember(RD, D); +} +void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXTemplateSpecialization(TD, D); +} + +} // end namespace clang + + +MultiplexConsumer::MultiplexConsumer(const std::vector& C) + : Consumers(C), MutationListener(0), DeserializationListener(0) { + // Collect the mutation listeners and deserialization listeners of all + // children, and create a multiplex listener each if so. + std::vector mutationListeners; + std::vector serializationListeners; + for (size_t i = 0, e = Consumers.size(); i != e; ++i) { + ASTMutationListener* mutationListener = + Consumers[i]->GetASTMutationListener(); + if (mutationListener) + mutationListeners.push_back(mutationListener); + ASTDeserializationListener* serializationListener = + Consumers[i]->GetASTDeserializationListener(); + if (serializationListener) + serializationListeners.push_back(serializationListener); + } + if (mutationListeners.size()) { + MutationListener.reset(new MultiplexASTMutationListener(mutationListeners)); + } + if (serializationListeners.size()) { + DeserializationListener.reset( + new MultiplexASTDeserializationListener(serializationListeners)); + } +} + +MultiplexConsumer::~MultiplexConsumer() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + delete Consumers[i]; +} + +void MultiplexConsumer::Initialize(ASTContext &Context) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->Initialize(Context); +} + +void MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTopLevelDecl(D); +} + +void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleInterestingDecl(D); +} + +void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTranslationUnit(Ctx); +} + +void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTagDeclDefinition(D); +} + +void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->CompleteTentativeDefinition(D); +} + +void MultiplexConsumer::HandleVTable( + CXXRecordDecl *RD, bool DefinitionRequired) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleVTable(RD, DefinitionRequired); +} + +ASTMutationListener *MultiplexConsumer::GetASTMutationListener() { + return MutationListener.get(); +} + +ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() { + return DeserializationListener.get(); +} + +void MultiplexConsumer::PrintStats() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->PrintStats(); +} + +void MultiplexConsumer::InitializeSema(Sema &S) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + if (SemaConsumer *SC = dyn_cast(Consumers[i])) + SC->InitializeSema(S); +} + +void MultiplexConsumer::ForgetSema() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + if (SemaConsumer *SC = dyn_cast(Consumers[i])) + SC->ForgetSema(); +} From kremenek at apple.com Tue Jan 25 13:08:48 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 21:08:48 -0000 Subject: [cfe-commits] r124228 - in /cfe/trunk: lib/StaticAnalyzer/SymbolManager.cpp test/Analysis/misc-ps-region-store.m Message-ID: <20110125210848.2CE472A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 15:08:47 2011 New Revision: 124228 URL: http://llvm.org/viewvc/llvm-project?rev=124228&view=rev Log: Don't try and symbolicate unions; we don't reason about them yet. Fixes crash reported in PR 9049. Modified: cfe/trunk/lib/StaticAnalyzer/SymbolManager.cpp cfe/trunk/test/Analysis/misc-ps-region-store.m Modified: cfe/trunk/lib/StaticAnalyzer/SymbolManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/SymbolManager.cpp?rev=124228&r1=124227&r2=124228&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/SymbolManager.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/SymbolManager.cpp Tue Jan 25 15:08:47 2011 @@ -233,13 +233,15 @@ SymbolManager::~SymbolManager() {} bool SymbolManager::canSymbolicate(QualType T) { + T = T.getCanonicalType(); + if (Loc::IsLocType(T)) return true; if (T->isIntegerType()) return T->isScalarType(); - if (T->isRecordType()) + if (T->isRecordType() && !T->isUnionType()) return true; return false; Modified: cfe/trunk/test/Analysis/misc-ps-region-store.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/misc-ps-region-store.m?rev=124228&r1=124227&r2=124228&view=diff ============================================================================== --- cfe/trunk/test/Analysis/misc-ps-region-store.m (original) +++ cfe/trunk/test/Analysis/misc-ps-region-store.m Tue Jan 25 15:08:47 2011 @@ -1217,3 +1217,23 @@ vals[index] = foo_rdar8848957(); return vals[index].x; // no-warning } + +// PR 9049 - crash on symbolicating unions. This test exists solely to +// test that the analyzer doesn't crash. +typedef struct pr9048_cdev *pr9048_cdev_t; +typedef union pr9048_abstracted_disklabel { void *opaque; } pr9048_disklabel_t; +struct pr9048_diskslice { pr9048_disklabel_t ds_label; }; +struct pr9048_diskslices { + int dss_secmult; + struct pr9048_diskslice dss_slices[16]; +}; +void pr9048(pr9048_cdev_t dev, struct pr9048_diskslices * ssp, unsigned int slice) +{ + pr9048_disklabel_t lp; + struct pr9048_diskslice *sp; + sp = &ssp->dss_slices[slice]; + if (ssp->dss_secmult == 1) { + } else if ((lp = sp->ds_label).opaque != ((void *) 0)) { + } +} + From anton.yartsev at gmail.com Tue Jan 25 13:45:12 2011 From: anton.yartsev at gmail.com (Anton Yartsev) Date: Wed, 26 Jan 2011 00:45:12 +0300 Subject: [cfe-commits] [PATCH][Review request] correct initialization of AltiVec vectors In-Reply-To: <87A3C667-726E-4C41-B463-8614B8B295D7@apple.com> References: <4CF32459.2000700@Gmail.com> <4D1BCEFC.8020303@Gmail.com> <87A3C667-726E-4C41-B463-8614B8B295D7@apple.com> Message-ID: <4D3F4468.1030000@Gmail.com> On 17.01.2011 21:59, Douglas Gregor wrote: > On Dec 29, 2010, at 4:14 PM, Anton Yartsev wrote: > >> Hi all, >> >> made changes according to the rules for the '(...)' form of vector initialization in AltiVec: the number of initializers must be one or must match the size of the vector. If a single value is specified in the initializer then it will be replicated to all the components of the vector. >> >> Can I commit the patch? > + // '(...)' form of vector initialization in AltiVec: the number of > + // initializers must be one or must match the size of the vector. > + // If a single value is specified in the initializer then it will be > + // replicated to all the components of the vector > + if (Ty->getAs()->getVectorKind() == > + VectorType::AltiVecVector) { > + unsigned numElems = Ty->getAs()->getNumElements(); > + // The number of initializers must be one or must match the size of the > + // vector. If a single value is specified in the initializer then it will > + // be replicated to all the components of the vector > + if (PE->getNumExprs() == 1) { > + Expr* initExpr = PE->getExpr(0); > + for (unsigned i = 0; i != numElems; ++i) > + initExprs.push_back(initExpr); > > This is effectively just a vector splat, so why not model it as an explicit C-style cast with kind CK_VectorSplat? That would more accurately describe what's happening than making this look like a vector initialization. > > - Doug Done! This solution, however, does not work in global scope for some reason. Investigating the problem. -- Anton -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: AltiVec_vector_init_fix_2.patch URL: From kremenek at apple.com Tue Jan 25 14:10:37 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 22:10:37 -0000 Subject: [cfe-commits] r124235 - /cfe/trunk/lib/Frontend/CMakeLists.txt Message-ID: <20110125221038.042312A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 16:10:37 2011 New Revision: 124235 URL: http://llvm.org/viewvc/llvm-project?rev=124235&view=rev Log: Unbreak CMake build. Modified: cfe/trunk/lib/Frontend/CMakeLists.txt Modified: cfe/trunk/lib/Frontend/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=124235&r1=124234&r2=124235&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CMakeLists.txt (original) +++ cfe/trunk/lib/Frontend/CMakeLists.txt Tue Jan 25 16:10:37 2011 @@ -27,6 +27,7 @@ InitHeaderSearch.cpp InitPreprocessor.cpp LangStandards.cpp + MultiplexConsumer.cpp PrintPreprocessedOutput.cpp StmtXML.cpp TextDiagnosticBuffer.cpp From dgregor at apple.com Tue Jan 25 14:19:32 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 22:19:32 -0000 Subject: [cfe-commits] r124236 - in /cfe/trunk: include/clang/Sema/Overload.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Message-ID: <20110125221932.B71BB2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 16:19:32 2011 New Revision: 124236 URL: http://llvm.org/viewvc/llvm-project?rev=124236&view=rev Log: Speculatively implement a tweak to the C++0x overload resolution rules for reference binding (C++ [over.rank.ics]p3b1sb4), so that we prefer the binding of an lvalue reference to a function lvalue over the binding of an rvalue reference. This change resolves the ambiguity with std::forward and lvalue references to function types in a way that seems consistent with the original rvalue references proposal. My proposed wording for this change is shown in isBetterReferenceBindingKind(); we'll try to get this change adopted in the C++0x working paper as well. Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124236&r1=124235&r2=124236&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Tue Jan 25 16:19:32 2011 @@ -133,24 +133,30 @@ /// Deprecated - Whether this the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - bool DeprecatedStringLiteralToCharPtr : 1; + unsigned DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). - bool IncompatibleObjC : 1; + unsigned IncompatibleObjC : 1; /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). - bool ReferenceBinding : 1; + unsigned ReferenceBinding : 1; /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). - bool DirectBinding : 1; - - /// RRefBinding - True when this is a reference binding of an rvalue - /// reference to an rvalue (C++0x [over.ics.rank]p3b4). - bool RRefBinding : 1; + unsigned DirectBinding : 1; + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124236&r1=124235&r2=124236&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 25 16:19:32 2011 @@ -170,7 +170,9 @@ DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; - RRefBinding = false; + IsLvalueReference = true; + BindsToFunctionLvalue = false; + BindsToRvalue = false; CopyConstructor = 0; } @@ -2324,6 +2326,33 @@ return ImplicitConversionSequence::Indistinguishable; } +/// \brief Determine whether one of the given reference bindings is better +/// than the other based on what kind of bindings they are. +static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, + const StandardConversionSequence &SCS2) { + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and *either* S1 binds an rvalue reference + // to an rvalue and S2 binds an lvalue reference *or S1 binds an + // lvalue reference to a function lvalue and S2 binds an rvalue + // reference*. + // + // FIXME: Rvalue references. We're going rogue with the above edits, + // because the semantics in the current C++0x working paper (N3225 at the + // time of this writing) break the standard definition of std::forward + // and std::reference_wrapper when dealing with references to functions. + // Proposed wording changes submitted to CWG for consideration. + // + // FIXME: Rvalue references. We don't know if we're dealing with the + // implicit object parameter, or if the member function in this case has a + // ref qualifier. (Of course, we don't have ref qualifiers yet.) + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && + SCS2.IsLvalueReference) || + (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && + !SCS2.IsLvalueReference); +} + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -2429,18 +2458,12 @@ return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { - // C++0x [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an - // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and S1 binds an rvalue reference to an - // rvalue and S2 binds an lvalue reference. - // FIXME: Rvalue references. We don't know if we're dealing with the - // implicit object parameter, or if the member function in this case has a - // ref qualifier. (Of course, we don't have ref qualifiers yet.) - if (SCS1.RRefBinding != SCS2.RRefBinding) - return SCS1.RRefBinding ? ImplicitConversionSequence::Better - : ImplicitConversionSequence::Worse; - + // Check for a better reference binding based on the kind of bindings. + if (isBetterReferenceBindingKind(SCS1, SCS2)) + return ImplicitConversionSequence::Better; + else if (isBetterReferenceBindingKind(SCS2, SCS1)) + return ImplicitConversionSequence::Worse; + // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -2966,7 +2989,9 @@ ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = false; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3036,7 +3061,9 @@ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3114,10 +3141,14 @@ // Of course, that's still a reference binding. if (ICS.isStandard()) { ICS.Standard.ReferenceBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; - ICS.UserDefined.After.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } return ICS; @@ -3212,7 +3243,11 @@ ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = false; + + // FIXME: Rvalue references. + ICS.Standard.IsLvalueReference = true; + ICS.Standard.BindsToFunctionLvalue = false; + ICS.Standard.BindsToRvalue = false; return ICS; } Modified: cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp?rev=124236&r1=124235&r2=124236&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Tue Jan 25 16:19:32 2011 @@ -50,10 +50,10 @@ }; namespace FunctionReferencesOverloading { - template int &f(typename remove_reference::type&); // expected-note{{candidate function [with T = int (&)(int)]}} - template float &f(typename remove_reference::type&&); // expected-note{{candidate function [with T = int (&)(int)]}} + template int &f(typename remove_reference::type&); + template float &f(typename remove_reference::type&&); void test_f(int (&func_ref)(int)) { - f(func_ref); // expected-error{{call to 'f' is ambiguous}} + int &ir = f(func_ref); } } From kremenek at apple.com Tue Jan 25 14:50:47 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 22:50:47 -0000 Subject: [cfe-commits] r124238 - in /cfe/trunk: lib/Sema/AnalysisBasedWarnings.cpp test/SemaCXX/return-noreturn-XFAIL.cpp test/SemaCXX/return-noreturn.cpp Message-ID: <20110125225047.E46582A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 16:50:47 2011 New Revision: 124238 URL: http://llvm.org/viewvc/llvm-project?rev=124238&view=rev Log: Fix regression in -Wreturn-type caused by not handling all CFGElement kinds. While writing the test case, it turned out that return-noreturn.cpp wasn't actually testing anything since it has the wrong -W flag. That uncovered another regression with the handling of destructors marked noreturn. WIP. Added: cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp - copied, changed from r124236, cfe/trunk/test/SemaCXX/return-noreturn.cpp Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp cfe/trunk/test/SemaCXX/return-noreturn.cpp Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124238&r1=124237&r2=124238&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Jan 25 16:50:47 2011 @@ -132,21 +132,12 @@ continue; } CFGElement CE = B[B.size()-1]; - if (CFGInitializer CI = CE.getAs()) { - // A base or member initializer. - HasPlainEdge = true; - continue; - } - if (CFGMemberDtor MD = CE.getAs()) { - // A member destructor. - HasPlainEdge = true; - continue; - } - if (CFGBaseDtor BD = CE.getAs()) { - // A base destructor. + + if (!isa(CE)) { HasPlainEdge = true; continue; } + CFGStmt CS = CE.getAs(); if (!CS.isValid()) continue; Copied: cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp (from r124236, cfe/trunk/test/SemaCXX/return-noreturn.cpp) URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp?p2=cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp&p1=cfe/trunk/test/SemaCXX/return-noreturn.cpp&r1=124236&r2=124238&rev=124238&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/return-noreturn.cpp (original) +++ cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp Tue Jan 25 16:50:47 2011 @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wmissing-noreturn -Wno-unreachable-code +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wno-unreachable-code +// XFAIL: * // A destructor may be marked noreturn and should still influence the CFG. namespace PR6884 { Modified: cfe/trunk/test/SemaCXX/return-noreturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/return-noreturn.cpp?rev=124238&r1=124237&r2=124238&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/return-noreturn.cpp (original) +++ cfe/trunk/test/SemaCXX/return-noreturn.cpp Tue Jan 25 16:50:47 2011 @@ -1,17 +1,11 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wmissing-noreturn -Wno-unreachable-code +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wno-unreachable-code -// A destructor may be marked noreturn and should still influence the CFG. -namespace PR6884 { - struct abort_struct { - abort_struct() {} // Make this non-POD so the destructor is invoked. - ~abort_struct() __attribute__((noreturn)); - }; +// - Properly handle CFGs with destructors. +struct rdar8875247 { + ~rdar8875247 (); +}; +void rdar8875247_aux(); - int f() { - abort_struct(); - } - - int f2() { - abort_struct s; - } -} +int rdar8875247_test() { + rdar8875247 f; +} // expected-warning{{control reaches end of non-void function}} From kremenek at apple.com Tue Jan 25 14:57:41 2011 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 25 Jan 2011 22:57:41 -0000 Subject: [cfe-commits] r124239 - in /cfe/trunk/test/SemaCXX: return-noreturn-XFAIL.cpp return-noreturn.cpp warn-missing-noreturn.cpp Message-ID: <20110125225741.CD6942A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 16:57:41 2011 New Revision: 124239 URL: http://llvm.org/viewvc/llvm-project?rev=124239&view=rev Log: Tweak return-noreturn.cpp test to have its original contents, with the additional warning flag (and still marked XFAIL). Removed: cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp Modified: cfe/trunk/test/SemaCXX/return-noreturn.cpp cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp Removed: cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp?rev=124238&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp (original) +++ cfe/trunk/test/SemaCXX/return-noreturn-XFAIL.cpp (removed) @@ -1,18 +0,0 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wno-unreachable-code -// XFAIL: * - -// A destructor may be marked noreturn and should still influence the CFG. -namespace PR6884 { - struct abort_struct { - abort_struct() {} // Make this non-POD so the destructor is invoked. - ~abort_struct() __attribute__((noreturn)); - }; - - int f() { - abort_struct(); - } - - int f2() { - abort_struct s; - } -} Modified: cfe/trunk/test/SemaCXX/return-noreturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/return-noreturn.cpp?rev=124239&r1=124238&r2=124239&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/return-noreturn.cpp (original) +++ cfe/trunk/test/SemaCXX/return-noreturn.cpp Tue Jan 25 16:57:41 2011 @@ -1,11 +1,18 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wno-unreachable-code +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code +// XFAIL: * -// - Properly handle CFGs with destructors. -struct rdar8875247 { - ~rdar8875247 (); -}; -void rdar8875247_aux(); +// A destructor may be marked noreturn and should still influence the CFG. +namespace PR6884 { + struct abort_struct { + abort_struct() {} // Make this non-POD so the destructor is invoked. + ~abort_struct() __attribute__((noreturn)); + }; -int rdar8875247_test() { - rdar8875247 f; -} // expected-warning{{control reaches end of non-void function}} + int f() { + abort_struct(); + } + + int f2() { + abort_struct s; + } +} Modified: cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp?rev=124239&r1=124238&r2=124239&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp Tue Jan 25 16:57:41 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -Wmissing-noreturn +// RUN: %clang_cc1 -fsyntax-only -verify %s -Wmissing-noreturn -Wreturn-type void f() __attribute__((noreturn)); template void g(T) { // expected-warning {{function could be attribute 'noreturn'}} @@ -82,3 +82,14 @@ ~C() { } }; } + +// - Properly handle CFGs with destructors. +struct rdar8875247 { + ~rdar8875247 (); +}; +void rdar8875247_aux(); + +int rdar8875247_test() { + rdar8875247 f; +} // expected-warning{{control reaches end of non-void function}} + From dgregor at apple.com Tue Jan 25 15:11:15 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 23:11:15 -0000 Subject: [cfe-commits] [libcxx] r124241 - /libcxx/trunk/include/functional Message-ID: <20110125231115.A065D2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 17:11:15 2011 New Revision: 124241 URL: http://llvm.org/viewvc/llvm-project?rev=124241&view=rev Log: Remove an (incorrect) compiler workaround in the __mu function. The workaround relied on rvalue references binding to non-function lvalues, while the original formulation (with std::forward) does the right thing. Modified: libcxx/trunk/include/functional Modified: libcxx/trunk/include/functional URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/functional?rev=124241&r1=124240&r2=124241&view=diff ============================================================================== --- libcxx/trunk/include/functional (original) +++ libcxx/trunk/include/functional Tue Jan 25 17:11:15 2011 @@ -1559,10 +1559,7 @@ __mu(_Ti&, _Uj& __uj) { const size_t _Indx = is_placeholder<_Ti>::value - 1; - // compiler bug workaround - typename tuple_element<_Indx, _Uj>::type __t = get<_Indx>(__uj); - return __t; -// return _STD::forward::type>(get<_Indx>(__uj)); + return _STD::forward::type>(get<_Indx>(__uj)); } template From akyrtzi at gmail.com Tue Jan 25 15:16:33 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 23:16:33 -0000 Subject: [cfe-commits] r124242 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaType.cpp test/Sema/block-return.c Message-ID: <20110125231633.B88752A6C12C@llvm.org> Author: akirtzidis Date: Tue Jan 25 17:16:33 2011 New Revision: 124242 URL: http://llvm.org/viewvc/llvm-project?rev=124242&view=rev Log: Change error "function cannot return array type" -> "blocks cannot return array type" when blocks are involved. Addresses rdar://8876238. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Sema/block-return.c Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124242&r1=124241&r2=124242&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 17:16:33 2011 @@ -3381,8 +3381,8 @@ def err_expected_block_lbrace : Error<"expected '{' in block literal">; def err_return_in_block_expression : Error< "return not allowed in block expression literal">; -def err_block_returns_array : Error< - "block declared as returning an array">; +def err_block_returning_array_function : Error< + "block cannot return %select{array|function}0 type %1">; // CFString checking Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124242&r1=124241&r2=124242&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 17:16:33 2011 @@ -1621,8 +1621,10 @@ // For conversion functions, we'll diagnose this particular error later. if ((T->isArrayType() || T->isFunctionType()) && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { - Diag(DeclType.Loc, diag::err_func_returning_array_function) - << T->isFunctionType() << T; + unsigned diagID = diag::err_func_returning_array_function; + if (D.getContext() == Declarator::BlockLiteralContext) + diagID = diag::err_block_returning_array_function; + Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } Modified: cfe/trunk/test/Sema/block-return.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-return.c?rev=124242&r1=124241&r2=124242&view=diff ============================================================================== --- cfe/trunk/test/Sema/block-return.c (original) +++ cfe/trunk/test/Sema/block-return.c Tue Jan 25 17:16:33 2011 @@ -97,7 +97,7 @@ } int (*funcptr3[5])(long); -int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{function cannot return array type}} expected-warning {{incompatible pointer to integer conversion}} +int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{block cannot return array type}} expected-warning {{incompatible pointer to integer conversion}} void foo6() { int (^b)(int) __attribute__((noreturn)); From akyrtzi at gmail.com Tue Jan 25 15:16:36 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 23:16:36 -0000 Subject: [cfe-commits] r124243 - in /cfe/trunk: lib/Sema/SemaExpr.cpp test/SemaCXX/arrow-operator.cpp Message-ID: <20110125231636.EAA722A6C12D@llvm.org> Author: akirtzidis Date: Tue Jan 25 17:16:36 2011 New Revision: 124243 URL: http://llvm.org/viewvc/llvm-project?rev=124243&view=rev Log: Fix infinite loop during error diagnostics. Fixes rdar://8875304. Modified: cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/SemaCXX/arrow-operator.cpp Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124243&r1=124242&r2=124243&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jan 25 17:16:36 2011 @@ -3814,7 +3814,7 @@ // - 'type' is an Objective C type // - 'bar' is a pseudo-destructor name which happens to refer to // the appropriate pointer type - } else if (Ptr->getPointeeType()->isRecordType() && + } else if (!IsArrow && Ptr->getPointeeType()->isRecordType() && MemberName.getNameKind() != DeclarationName::CXXDestructorName) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << int(IsArrow) << BaseExpr->getSourceRange() Modified: cfe/trunk/test/SemaCXX/arrow-operator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/arrow-operator.cpp?rev=124243&r1=124242&r2=124243&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/arrow-operator.cpp (original) +++ cfe/trunk/test/SemaCXX/arrow-operator.cpp Tue Jan 25 17:16:36 2011 @@ -23,3 +23,16 @@ d->f(); e->f(); // expected-error{{incomplete definition of type}} } + +// rdar://8875304 +namespace rdar8875304 { +class Point {}; +class Line_Segment{ public: Line_Segment(const Point&){} }; +class Node { public: Point Location(){ Point p; return p; } }; + +void f() +{ + Node** node1; + Line_Segment(node1->Location()); // expected-error {{not a structure or union}} +} +} From akyrtzi at gmail.com Tue Jan 25 15:16:40 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 23:16:40 -0000 Subject: [cfe-commits] r124244 - in /cfe/trunk: lib/Sema/SemaType.cpp test/Sema/stdcall-fastcall.c Message-ID: <20110125231640.35F0F2A6C12E@llvm.org> Author: akirtzidis Date: Tue Jan 25 17:16:40 2011 New Revision: 124244 URL: http://llvm.org/viewvc/llvm-project?rev=124244&view=rev Log: Diagnose calling convention attribute incompatibilities. Fixes rdar://8876096. Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Sema/stdcall-fastcall.c Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124244&r1=124243&r2=124244&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 17:16:40 2011 @@ -2560,6 +2560,17 @@ if (!unwrapped.isFunctionType()) return false; + // Diagnose regparm with fastcall. + const FunctionType *fn = unwrapped.get(); + CallingConv CC = fn->getCallConv(); + if (CC == CC_X86FastCall) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << FunctionType::getNameForCallConv(CC) + << "regparm"; + attr.setInvalid(); + return true; + } + FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withRegParm(value); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); @@ -2578,7 +2589,8 @@ CallingConv CCOld = fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == S.Context.getCanonicalCallConv(CCOld)) { - attr.setInvalid(); + FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } @@ -2607,6 +2619,15 @@ attr.setInvalid(); return true; } + + // Also diagnose fastcall with regparm. + if (fn->getRegParmType()) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << "regparm" + << FunctionType::getNameForCallConv(CC); + attr.setInvalid(); + return true; + } } FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); Modified: cfe/trunk/test/Sema/stdcall-fastcall.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/stdcall-fastcall.c?rev=124244&r1=124243&r2=124244&view=diff ============================================================================== --- cfe/trunk/test/Sema/stdcall-fastcall.c (original) +++ cfe/trunk/test/Sema/stdcall-fastcall.c Tue Jan 25 17:16:40 2011 @@ -8,3 +8,13 @@ void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{fastcall and stdcall attributes are not compatible}} void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}} void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}} + +// rdar://8876096 +void rdar8876096foo1(int i, int j) __attribute__((fastcall, cdecl)); // expected-error {{not compatible}} +void rdar8876096foo2(int i, int j) __attribute__((fastcall, stdcall)); // expected-error {{not compatible}} +void rdar8876096foo3(int i, int j) __attribute__((fastcall, regparm(2))); // expected-error {{not compatible}} +void rdar8876096foo4(int i, int j) __attribute__((stdcall, cdecl)); // expected-error {{not compatible}} +void rdar8876096foo5(int i, int j) __attribute__((stdcall, fastcall)); // expected-error {{not compatible}} +void rdar8876096foo6(int i, int j) __attribute__((cdecl, fastcall)); // expected-error {{not compatible}} +void rdar8876096foo7(int i, int j) __attribute__((cdecl, stdcall)); // expected-error {{not compatible}} +void rdar8876096foo8(int i, int j) __attribute__((regparm(2), fastcall)); // expected-error {{not compatible}} From dgregor at apple.com Tue Jan 25 15:49:36 2011 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 25 Jan 2011 23:49:36 -0000 Subject: [cfe-commits] r124247 - in /cfe/trunk: include/clang/Sema/Overload.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Message-ID: <20110125234937.172952A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 17:49:36 2011 New Revision: 124247 URL: http://llvm.org/viewvc/llvm-project?rev=124247&view=rev Log: Speculatively revert r124236 Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124247&r1=124246&r2=124247&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Tue Jan 25 17:49:36 2011 @@ -133,30 +133,24 @@ /// Deprecated - Whether this the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - unsigned DeprecatedStringLiteralToCharPtr : 1; + bool DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). - unsigned IncompatibleObjC : 1; + bool IncompatibleObjC : 1; /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). - unsigned ReferenceBinding : 1; + bool ReferenceBinding : 1; /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). - unsigned DirectBinding : 1; + bool DirectBinding : 1; + + /// RRefBinding - True when this is a reference binding of an rvalue + /// reference to an rvalue (C++0x [over.ics.rank]p3b4). + bool RRefBinding : 1; - /// \brief Whether this is an lvalue reference binding (otherwise, it's - /// an rvalue reference binding). - unsigned IsLvalueReference : 1; - - /// \brief Whether we're binding to a function lvalue. - unsigned BindsToFunctionLvalue : 1; - - /// \brief Whether we're binding to an rvalue. - unsigned BindsToRvalue : 1; - /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124247&r1=124246&r2=124247&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 25 17:49:36 2011 @@ -170,9 +170,7 @@ DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; - IsLvalueReference = true; - BindsToFunctionLvalue = false; - BindsToRvalue = false; + RRefBinding = false; CopyConstructor = 0; } @@ -2326,33 +2324,6 @@ return ImplicitConversionSequence::Indistinguishable; } -/// \brief Determine whether one of the given reference bindings is better -/// than the other based on what kind of bindings they are. -static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, - const StandardConversionSequence &SCS2) { - // C++0x [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an - // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and *either* S1 binds an rvalue reference - // to an rvalue and S2 binds an lvalue reference *or S1 binds an - // lvalue reference to a function lvalue and S2 binds an rvalue - // reference*. - // - // FIXME: Rvalue references. We're going rogue with the above edits, - // because the semantics in the current C++0x working paper (N3225 at the - // time of this writing) break the standard definition of std::forward - // and std::reference_wrapper when dealing with references to functions. - // Proposed wording changes submitted to CWG for consideration. - // - // FIXME: Rvalue references. We don't know if we're dealing with the - // implicit object parameter, or if the member function in this case has a - // ref qualifier. (Of course, we don't have ref qualifiers yet.) - return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && - SCS2.IsLvalueReference) || - (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && - !SCS2.IsLvalueReference); -} - /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -2458,12 +2429,18 @@ return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { - // Check for a better reference binding based on the kind of bindings. - if (isBetterReferenceBindingKind(SCS1, SCS2)) - return ImplicitConversionSequence::Better; - else if (isBetterReferenceBindingKind(SCS2, SCS1)) - return ImplicitConversionSequence::Worse; - + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and S1 binds an rvalue reference to an + // rvalue and S2 binds an lvalue reference. + // FIXME: Rvalue references. We don't know if we're dealing with the + // implicit object parameter, or if the member function in this case has a + // ref qualifier. (Of course, we don't have ref qualifiers yet.) + if (SCS1.RRefBinding != SCS2.RRefBinding) + return SCS1.RRefBinding ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -2989,9 +2966,7 @@ ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = false; + ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3061,9 +3036,7 @@ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = InitCategory.isRValue(); + ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3141,14 +3114,10 @@ // Of course, that's still a reference binding. if (ICS.isStandard()) { ICS.Standard.ReferenceBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = true; + ICS.Standard.RRefBinding = isRValRef; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = true; + ICS.UserDefined.After.RRefBinding = isRValRef; } return ICS; @@ -3243,11 +3212,7 @@ ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - - // FIXME: Rvalue references. - ICS.Standard.IsLvalueReference = true; - ICS.Standard.BindsToFunctionLvalue = false; - ICS.Standard.BindsToRvalue = false; + ICS.Standard.RRefBinding = false; return ICS; } Modified: cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp?rev=124247&r1=124246&r2=124247&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Tue Jan 25 17:49:36 2011 @@ -50,10 +50,10 @@ }; namespace FunctionReferencesOverloading { - template int &f(typename remove_reference::type&); - template float &f(typename remove_reference::type&&); + template int &f(typename remove_reference::type&); // expected-note{{candidate function [with T = int (&)(int)]}} + template float &f(typename remove_reference::type&&); // expected-note{{candidate function [with T = int (&)(int)]}} void test_f(int (&func_ref)(int)) { - int &ir = f(func_ref); + f(func_ref); // expected-error{{call to 'f' is ambiguous}} } } From akyrtzi at gmail.com Tue Jan 25 15:54:44 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Tue, 25 Jan 2011 23:54:44 -0000 Subject: [cfe-commits] r124249 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp test/Analysis/self-init.m Message-ID: <20110125235444.8F8332A6C12C@llvm.org> Author: akirtzidis Date: Tue Jan 25 17:54:44 2011 New Revision: 124249 URL: http://llvm.org/viewvc/llvm-project?rev=124249&view=rev Log: [analyzer] Do the self-init check only on NSObject subclasses. Patch by Jean-Daniel Dupas! Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp cfe/trunk/test/Analysis/self-init.m Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp?rev=124249&r1=124248&r2=124249&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Tue Jan 25 17:54:44 2011 @@ -270,11 +270,23 @@ const ObjCMethodDecl *MD = dyn_cast(ND); if (!MD) return false; - if (!MD->getClassInterface()->getSuperClass()) - return false; if (!isInitializationMethod(MD)) return false; + // self = [super init] applies only to NSObject subclasses. + // For instance, NSProxy doesn't implement -init. + ASTContext& Ctx = MD->getASTContext(); + IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); + ObjCInterfaceDecl* ID = MD->getClassInterface()->getSuperClass(); + for ( ; ID ; ID = ID->getSuperClass()) { + IdentifierInfo *II = ID->getIdentifier(); + + if (II == NSObjectII) + break; + } + if (!ID) + return false; + return true; } Modified: cfe/trunk/test/Analysis/self-init.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/self-init.m?rev=124249&r1=124248&r2=124249&view=diff ============================================================================== --- cfe/trunk/test/Analysis/self-init.m (original) +++ cfe/trunk/test/Analysis/self-init.m Tue Jan 25 17:54:44 2011 @@ -17,6 +17,9 @@ -(id)init; -(id)release; @end + at interface NSProxy {} + at end + //#import "Foundation/NSObject.h" typedef unsigned NSUInteger; typedef int NSInteger; @@ -48,6 +51,10 @@ -(void)doSomething; @end + at interface MyProxyObj : NSProxy {} +-(id)init; + at end + @implementation MyObj -(id)init { @@ -137,3 +144,9 @@ -(void)doSomething {} @end + + at implementation MyProxyObj + +- (id)init { return self; } + + at end From hhinnant at apple.com Tue Jan 25 16:06:59 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Wed, 26 Jan 2011 00:06:59 -0000 Subject: [cfe-commits] [libcxx] r124252 - /libcxx/trunk/include/string Message-ID: <20110126000659.EC17B2A6C12C@llvm.org> Author: hhinnant Date: Tue Jan 25 18:06:59 2011 New Revision: 124252 URL: http://llvm.org/viewvc/llvm-project?rev=124252&view=rev Log: Add always_inline to string move constructors Modified: libcxx/trunk/include/string Modified: libcxx/trunk/include/string URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/string?rev=124252&r1=124251&r2=124252&view=diff ============================================================================== --- libcxx/trunk/include/string (original) +++ libcxx/trunk/include/string Tue Jan 25 18:06:59 2011 @@ -1033,7 +1033,9 @@ basic_string(const basic_string& __str); basic_string(const basic_string& __str, const allocator_type& __a); #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + _LIBCPP_INLINE_VISIBILITY basic_string(basic_string&& __str); + _LIBCPP_INLINE_VISIBILITY basic_string(basic_string&& __str, const allocator_type& __a); #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY basic_string(const_pointer __s); From dgregor at apple.com Tue Jan 25 16:12:48 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 00:12:48 -0000 Subject: [cfe-commits] [libcxx] r124255 - /libcxx/trunk/include/iterator Message-ID: <20110126001248.DA4BB2A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 18:12:48 2011 New Revision: 124255 URL: http://llvm.org/viewvc/llvm-project?rev=124255&view=rev Log: Teach move_iterator that rvalue references cannot bind to non-function lvalues, nor can one take the address of an xvalue, by adding appropriate static_cast's (in the first case) and a temporary (in the second case). Modified: libcxx/trunk/include/iterator Modified: libcxx/trunk/include/iterator URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/iterator?rev=124255&r1=124254&r2=124255&view=diff ============================================================================== --- libcxx/trunk/include/iterator (original) +++ libcxx/trunk/include/iterator Tue Jan 25 18:12:48 2011 @@ -902,8 +902,13 @@ template _LIBCPP_INLINE_VISIBILITY move_iterator(const move_iterator<_Up>& __u) : __i(__u.base()) {} _LIBCPP_INLINE_VISIBILITY _Iter base() const {return __i;} - _LIBCPP_INLINE_VISIBILITY reference operator*() const {return *__i;} - _LIBCPP_INLINE_VISIBILITY pointer operator->() const {return &(operator*());} + _LIBCPP_INLINE_VISIBILITY reference operator*() const { + return static_cast(*__i); + } + _LIBCPP_INLINE_VISIBILITY pointer operator->() const { + typename iterator_traits::reference __ref = *__i; + return &__ref; + } _LIBCPP_INLINE_VISIBILITY move_iterator& operator++() {++__i; return *this;} _LIBCPP_INLINE_VISIBILITY move_iterator operator++(int) {move_iterator __tmp(*this); ++__i; return __tmp;} @@ -919,7 +924,9 @@ _LIBCPP_INLINE_VISIBILITY move_iterator& operator-=(difference_type __n) {__i -= __n; return *this;} _LIBCPP_INLINE_VISIBILITY reference operator[](difference_type __n) const - {return __i[__n];} + { + return static_cast(__i[__n]); + } }; template From jyasskin at google.com Tue Jan 25 16:18:08 2011 From: jyasskin at google.com (Jeffrey Yasskin) Date: Wed, 26 Jan 2011 00:18:08 -0000 Subject: [cfe-commits] r124256 - /cfe/trunk/include/clang/Frontend/CompilerInstance.h Message-ID: <20110126001808.F19382A6C12C@llvm.org> Author: jyasskin Date: Tue Jan 25 18:18:08 2011 New Revision: 124256 URL: http://llvm.org/viewvc/llvm-project?rev=124256&view=rev Log: Remove CompilerInstance::getOutputFileList because it is unimplemented and unused. Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=124256&r1=124255&r2=124256&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original) +++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Tue Jan 25 18:18:08 2011 @@ -454,11 +454,6 @@ /// @name Output Files /// { - /// getOutputFileList - Get the list of (path, output stream) pairs of output - /// files; the path may be empty but the stream will always be non-null. - const std::list< std::pair > &getOutputFileList() const; - /// addOutputFile - Add an output file onto the list of tracked output files. /// /// \param OutFile - The output file info. From fjahanian at apple.com Tue Jan 25 16:57:01 2011 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 26 Jan 2011 00:57:01 -0000 Subject: [cfe-commits] r124258 - in /cfe/trunk: lib/Sema/SemaExpr.cpp test/SemaObjC/synth-provisional-ivars-1.m Message-ID: <20110126005701.82D052A6C12C@llvm.org> Author: fjahanian Date: Tue Jan 25 18:57:01 2011 New Revision: 124258 URL: http://llvm.org/viewvc/llvm-project?rev=124258&view=rev Log: Tweak the rule for deciding if a provisional ivar is needed in default ivar synthesis. Fixes // rdar://8913053. Added: cfe/trunk/test/SemaObjC/synth-provisional-ivars-1.m Modified: cfe/trunk/lib/Sema/SemaExpr.cpp Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124258&r1=124257&r2=124258&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jan 25 18:57:01 2011 @@ -1354,7 +1354,8 @@ LookForIvars = false; else LookForIvars = (Lookup.isSingleResult() && - Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); + Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod() && + (Lookup.getAsSingle() != 0)); if (!LookForIvars) return 0; Added: cfe/trunk/test/SemaObjC/synth-provisional-ivars-1.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/synth-provisional-ivars-1.m?rev=124258&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/synth-provisional-ivars-1.m (added) +++ cfe/trunk/test/SemaObjC/synth-provisional-ivars-1.m Tue Jan 25 18:57:01 2011 @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s +// rdar://8913053 + +typedef unsigned char BOOL; + + at interface MailApp +{ + BOOL _isAppleInternal; +} + at property(assign) BOOL isAppleInternal; + at end + +static BOOL isAppleInternal() {return 0; } + + at implementation MailApp + +- (BOOL)isAppleInternal { + return _isAppleInternal; +} + +- (void)setIsAppleInternal:(BOOL)flag { + _isAppleInternal= !!flag; +} + +- (void) Meth { + self.isAppleInternal = isAppleInternal(); +} + at end From akyrtzi at gmail.com Tue Jan 25 17:26:41 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Wed, 26 Jan 2011 01:26:41 -0000 Subject: [cfe-commits] r124263 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp test/Analysis/self-init.m Message-ID: <20110126012641.3AAE92A6C12C@llvm.org> Author: akirtzidis Date: Tue Jan 25 19:26:41 2011 New Revision: 124263 URL: http://llvm.org/viewvc/llvm-project?rev=124263&view=rev Log: [analyzer] Improve the diagnostic for the self-init checker. Suggestion by Ted! Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp cfe/trunk/test/Analysis/self-init.m Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp?rev=124263&r1=124262&r2=124263&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Tue Jan 25 19:26:41 2011 @@ -102,8 +102,8 @@ class InitSelfBug : public BugType { const std::string desc; public: - InitSelfBug() : BugType("missing \"self = [{initializer}]\"", - "missing \"self = [{initializer}]\"") {} + InitSelfBug() : BugType("missing \"self = [(super or self) init...]\"", + "missing \"self = [(super or self) init...]\"") {} }; } // end anonymous namespace @@ -209,7 +209,8 @@ return; checkForInvalidSelf(E->getBase(), C, - "Using an ivar before setting 'self' to the result of an initializer"); + "Instance variable used before setting 'self' to the result of " + "'[(super or self) init...]'"); } void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C, @@ -220,7 +221,8 @@ return; checkForInvalidSelf(S->getRetValue(), C, - "Returning 'self' before setting it to the result of an initializer"); + "Returning 'self' before setting it to the result of " + "'[(super or self) init...]'"); } // When a call receives a reference to 'self', [Pre/Post]VisitGenericCall pass Modified: cfe/trunk/test/Analysis/self-init.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/self-init.m?rev=124263&r1=124262&r2=124263&view=diff ============================================================================== --- cfe/trunk/test/Analysis/self-init.m (original) +++ cfe/trunk/test/Analysis/self-init.m Tue Jan 25 19:26:41 2011 @@ -97,7 +97,7 @@ } -(id)init6 { - [NSBundle loadNibNamed:@"Window" owner:myivar]; // expected-warning {{Using an ivar}} + [NSBundle loadNibNamed:@"Window" owner:myivar]; // expected-warning {{Instance variable used}} return [self initWithSomething:0]; } @@ -121,7 +121,7 @@ } -(id)init10 { - myivar = 0; // expected-warning {{Using an ivar}} + myivar = 0; // expected-warning {{Instance variable used}} return self; } @@ -136,7 +136,7 @@ -(id)init13 { if ((self == [super init])) { - myivar = 0; // expected-warning {{Using an ivar}} + myivar = 0; // expected-warning {{Instance variable used}} } return self; // expected-warning {{Returning 'self'}} } From akyrtzi at gmail.com Tue Jan 25 17:26:44 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Wed, 26 Jan 2011 01:26:44 -0000 Subject: [cfe-commits] r124264 - in /cfe/trunk: lib/Sema/SemaType.cpp test/Sema/block-return.c Message-ID: <20110126012644.707802A6C12D@llvm.org> Author: akirtzidis Date: Tue Jan 25 19:26:44 2011 New Revision: 124264 URL: http://llvm.org/viewvc/llvm-project?rev=124264&view=rev Log: Correct r124242 making sure function chunk that gets diagnosed is really about the block. Clairvoyance by John! Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Sema/block-return.c Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124264&r1=124263&r2=124264&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 19:26:44 2011 @@ -1622,7 +1622,10 @@ if ((T->isArrayType() || T->isFunctionType()) && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { unsigned diagID = diag::err_func_returning_array_function; - if (D.getContext() == Declarator::BlockLiteralContext) + // Last processing chunk in block context means this function chunk + // represents the block. + if (chunkIndex == 0 && + D.getContext() == Declarator::BlockLiteralContext) diagID = diag::err_block_returning_array_function; Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; Modified: cfe/trunk/test/Sema/block-return.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-return.c?rev=124264&r1=124263&r2=124264&view=diff ============================================================================== --- cfe/trunk/test/Sema/block-return.c (original) +++ cfe/trunk/test/Sema/block-return.c Tue Jan 25 19:26:44 2011 @@ -98,6 +98,7 @@ int (*funcptr3[5])(long); int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{block cannot return array type}} expected-warning {{incompatible pointer to integer conversion}} +int sz9 = sizeof(^int(*())()[3]{ }); // expected-error {{function cannot return array type}} void foo6() { int (^b)(int) __attribute__((noreturn)); From akyrtzi at gmail.com Tue Jan 25 17:26:50 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Wed, 26 Jan 2011 01:26:50 -0000 Subject: [cfe-commits] r124266 - in /cfe/trunk: include/clang/Driver/CC1Options.td include/clang/Frontend/AnalyzerOptions.h lib/Driver/Tools.cpp lib/Frontend/CompilerInvocation.cpp lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp lib/StaticAnalyzer/Checkers/ExprEngine.cpp test/Analysis/self-init.m Message-ID: <20110126012650.6470E2A6C12E@llvm.org> Author: akirtzidis Date: Tue Jan 25 19:26:50 2011 New Revision: 124266 URL: http://llvm.org/viewvc/llvm-project?rev=124266&view=rev Log: [analyzer] Enable the self-init checker under command-line option '-analyzer-check-objc-self-init' which by default is enabled by the driver for '--analyze'. Modified: cfe/trunk/include/clang/Driver/CC1Options.td cfe/trunk/include/clang/Frontend/AnalyzerOptions.h cfe/trunk/lib/Driver/Tools.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp cfe/trunk/test/Analysis/self-init.m Modified: cfe/trunk/include/clang/Driver/CC1Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td (original) +++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Jan 25 19:26:50 2011 @@ -64,6 +64,8 @@ HelpText<"Warn about private ivars that are never used">; def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">, HelpText<"Run the [Core] Foundation reference count checker">; +def analysis_WarnObjCSelfInit : Flag<"-analyzer-check-objc-self-init">, + HelpText<"Warn about missing initialization of 'self' in an initializer">; def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">; def analysis_WarnIdempotentOps : Flag<"-analyzer-check-idempotent-operations">, Modified: cfe/trunk/include/clang/Frontend/AnalyzerOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/AnalyzerOptions.h?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/AnalyzerOptions.h (original) +++ cfe/trunk/include/clang/Frontend/AnalyzerOptions.h Tue Jan 25 19:26:50 2011 @@ -68,6 +68,7 @@ unsigned AnalyzerStats : 1; unsigned EagerlyAssume : 1; unsigned IdempotentOps : 1; + unsigned ObjCSelfInitCheck : 1; unsigned BufferOverflows : 1; unsigned PurgeDead : 1; unsigned TrimGraph : 1; @@ -91,6 +92,7 @@ AnalyzerStats = 0; EagerlyAssume = 0; IdempotentOps = 0; + ObjCSelfInitCheck = 0; BufferOverflows = 0; PurgeDead = 1; TrimGraph = 0; Modified: cfe/trunk/lib/Driver/Tools.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Tools.cpp (original) +++ cfe/trunk/lib/Driver/Tools.cpp Tue Jan 25 19:26:50 2011 @@ -910,6 +910,7 @@ if (types::isObjC(InputType)) { CmdArgs.push_back("-analyzer-check-objc-methodsigs"); CmdArgs.push_back("-analyzer-check-objc-unused-ivars"); + CmdArgs.push_back("-analyzer-check-objc-self-init"); // Do not enable the missing -dealloc check. // '-analyzer-check-objc-missing-dealloc', } Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Jan 25 19:26:50 2011 @@ -118,6 +118,8 @@ Res.push_back("-analyzer-experimental-internal-checks"); if (Opts.IdempotentOps) Res.push_back("-analyzer-check-idempotent-operations"); + if (Opts.ObjCSelfInitCheck) + Res.push_back("-analyzer-check-objc-self-init"); if (Opts.BufferOverflows) Res.push_back("-analyzer-check-buffer-overflows"); } @@ -868,6 +870,7 @@ Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); Opts.IdempotentOps = Args.hasArg(OPT_analysis_WarnIdempotentOps); + Opts.ObjCSelfInitCheck = Args.hasArg(OPT_analysis_WarnObjCSelfInit); Opts.BufferOverflows = Args.hasArg(OPT_analysis_WarnBufferOverflows); } Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp Tue Jan 25 19:26:50 2011 @@ -357,6 +357,9 @@ if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); + if (C.Opts.ObjCSelfInitCheck && isa(D)) + registerObjCSelfInitChecker(Eng); + // Enable idempotent operation checking if it was explicitly turned on, or if // we are running experimental checks (i.e. everything) if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Tue Jan 25 19:26:50 2011 @@ -309,7 +309,6 @@ RegisterUndefResultChecker(Eng); RegisterStackAddrLeakChecker(Eng); RegisterObjCAtSyncChecker(Eng); - registerObjCSelfInitChecker(Eng); // This is not a checker yet. RegisterNoReturnFunctionChecker(Eng); Modified: cfe/trunk/test/Analysis/self-init.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/self-init.m?rev=124266&r1=124265&r2=124266&view=diff ============================================================================== --- cfe/trunk/test/Analysis/self-init.m (original) +++ cfe/trunk/test/Analysis/self-init.m Tue Jan 25 19:26:50 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -verify +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-check-objc-self-init %s -verify @class NSZone, NSCoder; @protocol NSObject From kd at kendyck.com Tue Jan 25 18:17:09 2011 From: kd at kendyck.com (Ken Dyck) Date: Wed, 26 Jan 2011 02:17:09 -0000 Subject: [cfe-commits] r124274 - /cfe/trunk/lib/AST/ExprConstant.cpp Message-ID: <20110126021709.0E97A2A6C12C@llvm.org> Author: kjdyck Date: Tue Jan 25 20:17:08 2011 New Revision: 124274 URL: http://llvm.org/viewvc/llvm-project?rev=124274&view=rev Log: Use RecordLayout::getBaseClassOffset() where CharUnits are needed instead of converting getBaseClassOffsetInBits() to CharUnits. Modified: cfe/trunk/lib/AST/ExprConstant.cpp Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=124274&r1=124273&r2=124274&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Jan 25 20:17:08 2011 @@ -549,7 +549,7 @@ // Now figure out the necessary offset to add to the baseLV to get from // the derived class to the base class. - uint64_t Offset = 0; + CharUnits Offset = CharUnits::Zero(); QualType Ty = E->getSubExpr()->getType(); const CXXRecordDecl *DerivedDecl = @@ -567,13 +567,12 @@ const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); - Offset += Layout.getBaseClassOffsetInBits(BaseDecl); + Offset += Layout.getBaseClassOffset(BaseDecl); DerivedDecl = BaseDecl; } Result.Base = BaseLV.getLValueBase(); - Result.Offset = BaseLV.getLValueOffset() + - Info.Ctx.toCharUnitsFromBits(Offset); + Result.Offset = BaseLV.getLValueOffset() + Offset; return true; } @@ -1595,9 +1594,7 @@ return false; // Add the offset to the base. - Result += Info.Ctx.toCharUnitsFromBits( - RL.getBaseClassOffsetInBits( - cast(BaseRT->getDecl()))); + Result += RL.getBaseClassOffset(cast(BaseRT->getDecl())); break; } } From dgregor at apple.com Tue Jan 25 19:43:54 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 03:43:54 -0000 Subject: [cfe-commits] r124276 - in /cfe/trunk: include/clang/Sema/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaType.cpp test/CXX/dcl.decl/p4-0x.cpp Message-ID: <20110126034354.878242A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 21:43:54 2011 New Revision: 124276 URL: http://llvm.org/viewvc/llvm-project?rev=124276&view=rev Log: Rvalue references for *this: parse ref-qualifiers. Added: cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp (with props) Modified: cfe/trunk/include/clang/Sema/DeclSpec.h cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Sema/DeclSpec.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaType.cpp Modified: cfe/trunk/include/clang/Sema/DeclSpec.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) +++ cfe/trunk/include/clang/Sema/DeclSpec.h Tue Jan 25 21:43:54 2011 @@ -898,6 +898,10 @@ /// contains the location of the ellipsis. unsigned isVariadic : 1; + /// \brief Whether the ref-qualifier (if any) is an lvalue reference. + /// Otherwise, it's an rvalue reference. + unsigned RefQualifierIsLValueRef : 1; + /// The type qualifiers: const/volatile/restrict. /// The qualifier bitmask values are the same as in QualType. unsigned TypeQuals : 3; @@ -922,6 +926,11 @@ /// the function has one. unsigned NumExceptions; + /// \brief The location of the ref-qualifier, if any. + /// + /// If this is an invalid location, there is no ref-qualifier. + unsigned RefQualifierLoc; + /// ThrowLoc - When hasExceptionSpec is true, the location of the throw /// keyword introducing the spec. unsigned ThrowLoc; @@ -970,6 +979,15 @@ SourceLocation getThrowLoc() const { return SourceLocation::getFromRawEncoding(ThrowLoc); } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getRefQualifierLoc() const { + return SourceLocation::getFromRawEncoding(RefQualifierLoc); + } + + /// \brief Determine whether this function declaration contains a + /// ref-qualifier. + bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } }; struct BlockPointerTypeInfo : TypeInfoCommon { @@ -1084,7 +1102,10 @@ bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, - unsigned TypeQuals, bool hasExceptionSpec, + unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, + bool hasExceptionSpec, SourceLocation ThrowLoc, bool hasAnyExceptionSpec, ParsedType *Exceptions, Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Jan 25 21:43:54 2011 @@ -3064,8 +3064,8 @@ /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// -/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]" -/// and "exception-specification[opt]". +/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]", +/// C++0x "ref-qualifier[opt]" and "exception-specification[opt]". /// void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParsedAttributes &attrs, @@ -3085,6 +3085,8 @@ // cv-qualifier-seq[opt]. DeclSpec DS; + SourceLocation RefQualifierLoc; + bool RefQualifierIsLValueRef = true; bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; @@ -3097,6 +3099,16 @@ if (!DS.getSourceRange().getEnd().isInvalid()) EndLoc = DS.getSourceRange().getEnd(); + // Parse ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_rvalue_reference); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + EndLoc = RefQualifierLoc; + } + // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; @@ -3121,6 +3133,8 @@ SourceLocation(), /*arglist*/ 0, 0, DS.getTypeQualifiers(), + RefQualifierIsLValueRef, + RefQualifierLoc, hasExceptionSpec, ThrowLoc, hasAnyExceptionSpec, Exceptions.data(), @@ -3320,6 +3334,8 @@ SourceLocation EndLoc = RParenLoc; DeclSpec DS; + SourceLocation RefQualifierLoc; + bool RefQualifierIsLValueRef = true; bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; @@ -3334,6 +3350,16 @@ if (!DS.getSourceRange().getEnd().isInvalid()) EndLoc = DS.getSourceRange().getEnd(); + // Parse ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_rvalue_reference); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + EndLoc = RefQualifierLoc; + } + // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; @@ -3362,6 +3388,8 @@ EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), + RefQualifierIsLValueRef, + RefQualifierLoc, hasExceptionSpec, ThrowLoc, hasAnyExceptionSpec, Exceptions.data(), @@ -3443,6 +3471,7 @@ SourceLocation(), &ParamInfo[0], ParamInfo.size(), /*TypeQuals*/0, + true, SourceLocation(), /*exception*/false, SourceLocation(), false, 0, 0, 0, LParenLoc, RLoc, D), Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Jan 25 21:43:54 2011 @@ -1859,6 +1859,7 @@ true, false, SourceLocation(), 0, 0, 0, + true, SourceLocation(), false, SourceLocation(), false, 0, 0, 0, CaretLoc, CaretLoc, Modified: cfe/trunk/lib/Sema/DeclSpec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/lib/Sema/DeclSpec.cpp (original) +++ cfe/trunk/lib/Sema/DeclSpec.cpp Tue Jan 25 21:43:54 2011 @@ -52,6 +52,8 @@ ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, bool hasExceptionSpec, SourceLocation ThrowLoc, bool hasAnyExceptionSpec, @@ -74,6 +76,8 @@ I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; I.Fun.ArgInfo = 0; + I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; + I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.hasExceptionSpec = hasExceptionSpec; I.Fun.ThrowLoc = ThrowLoc.getRawEncoding(); I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jan 25 21:43:54 2011 @@ -5539,7 +5539,8 @@ Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), false, false, SourceLocation(), 0, - 0, 0, false, SourceLocation(), + 0, 0, true, SourceLocation(), + false, SourceLocation(), false, 0,0,0, Loc, Loc, D), SourceLocation()); D.SetIdentifier(&II, Loc); Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124276&r1=124275&r2=124276&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 21:43:54 2011 @@ -520,6 +520,7 @@ /*variadic*/ false, SourceLocation(), /*args*/ 0, 0, /*type quals*/ 0, + /*ref-qualifier*/true, SourceLocation(), /*EH*/ false, SourceLocation(), false, 0, 0, 0, /*parens*/ loc, loc, declarator)); Added: cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp?rev=124276&view=auto ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp (added) +++ cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp Tue Jan 25 21:43:54 2011 @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +struct X { + void f() &; + void g() &&; +}; + +void (X::*pmf)() & = &X::f; Propchange: cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/dcl.decl/p4-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From rjmccall at apple.com Tue Jan 25 20:00:11 2011 From: rjmccall at apple.com (John McCall) Date: Wed, 26 Jan 2011 04:00:11 -0000 Subject: [cfe-commits] r124277 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CGTemporaries.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/volatile-1.cpp Message-ID: <20110126040011.E1FFF2A6C12C@llvm.org> Author: rjmccall Date: Tue Jan 25 22:00:11 2011 New Revision: 124277 URL: http://llvm.org/viewvc/llvm-project?rev=124277&view=rev Log: Better framework for conditional cleanups; untested as yet. I'm separately committing this because it incidentally changes some block orderings and minor IR issues, like using a phi instead of an unnecessary alloca. Modified: cfe/trunk/lib/CodeGen/CGException.cpp cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/lib/CodeGen/CGExprAgg.cpp cfe/trunk/lib/CodeGen/CGExprComplex.cpp cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/CodeGen/CGTemporaries.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h cfe/trunk/test/CodeGenCXX/volatile-1.cpp Modified: cfe/trunk/lib/CodeGen/CGException.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGException.cpp (original) +++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jan 25 22:00:11 2011 @@ -172,6 +172,22 @@ BranchFixups.pop_back(); } +llvm::Value *CodeGenFunction::initFullExprCleanup() { + // Create a variable to decide whether the cleanup needs to be run. + llvm::AllocaInst *run = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond"); + + // Initialize it to false at a site that's guaranteed to be run + // before each evaluation. + llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); + new llvm::StoreInst(Builder.getFalse(), run, + block->getFirstNonPHIOrDbg()); + + // Initialize it to true at the current location. + Builder.CreateStore(Builder.getTrue(), run); + + return run; +} + static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); @@ -1656,3 +1672,23 @@ EHScopeStack::Cleanup::~Cleanup() { llvm_unreachable("Cleanup is indestructable"); } + +void EHScopeStack::ConditionalCleanup::Emit(CodeGenFunction &CGF, + bool IsForEHCleanup) { + // Determine whether we should run the cleanup. + llvm::Value *condVal = CGF.Builder.CreateLoad(cond, "cond.should-run"); + + llvm::BasicBlock *cleanup = CGF.createBasicBlock("cond-cleanup.run"); + llvm::BasicBlock *cont = CGF.createBasicBlock("cond-cleanup.cont"); + + // If we shouldn't run the cleanup, jump directly to the continuation block. + CGF.Builder.CreateCondBr(condVal, cleanup, cont); + CGF.EmitBlock(cleanup); + + // Emit the core of the cleanup. + EmitImpl(CGF, IsForEHCleanup); + assert(CGF.HaveInsertPoint() && "cleanup didn't end with valid IP!"); + + // Fall into the continuation block. + CGF.EmitBlock(cont); +} Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Jan 25 22:00:11 2011 @@ -1692,6 +1692,8 @@ llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); + + ConditionalEvaluation eval(*this); if (E->getLHS()) EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); @@ -1705,35 +1707,34 @@ } // Any temporaries created here are conditional. - BeginConditionalBranch(); EmitBlock(LHSBlock); + eval.begin(*this); LValue LHS = EmitLValue(E->getTrueExpr()); - - EndConditionalBranch(); + eval.end(*this); if (!LHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); - // FIXME: We shouldn't need an alloca for this. - llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp"); - Builder.CreateStore(LHS.getAddress(), Temp); - EmitBranch(ContBlock); + LHSBlock = Builder.GetInsertBlock(); + Builder.CreateBr(ContBlock); // Any temporaries created here are conditional. - BeginConditionalBranch(); EmitBlock(RHSBlock); + eval.begin(*this); LValue RHS = EmitLValue(E->getRHS()); - EndConditionalBranch(); + eval.end(*this); if (!RHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); - - Builder.CreateStore(RHS.getAddress(), Temp); - EmitBranch(ContBlock); + RHSBlock = Builder.GetInsertBlock(); EmitBlock(ContBlock); - - Temp = Builder.CreateLoad(Temp, "lv"); - return MakeAddrLValue(Temp, E->getType()); + + llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(), + "cond-lvalue"); + phi->reserveOperandSpace(2); + phi->addIncoming(LHS.getAddress(), LHSBlock); + phi->addIncoming(RHS.getAddress(), RHSBlock); + return MakeAddrLValue(phi, E->getType()); } // ?: here should be an aggregate. Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Jan 25 22:00:11 2011 @@ -367,8 +367,8 @@ } void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { + CodeGenFunction::StmtExprEvaluation eval(CGF); CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest); - CGF.EnsureInsertPoint(); } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { @@ -423,20 +423,19 @@ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); + CodeGenFunction::ConditionalEvaluation eval(CGF); CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - CGF.BeginConditionalBranch(); - CGF.EmitBlock(LHSBlock); - // Save whether the destination's lifetime is externally managed. bool DestLifetimeManaged = Dest.isLifetimeExternallyManaged(); + eval.begin(CGF); + CGF.EmitBlock(LHSBlock); Visit(E->getLHS()); - CGF.EndConditionalBranch(); - CGF.EmitBranch(ContBlock); + eval.end(CGF); - CGF.BeginConditionalBranch(); - CGF.EmitBlock(RHSBlock); + assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!"); + CGF.Builder.CreateBr(ContBlock); // If the result of an agg expression is unused, then the emission // of the LHS might need to create a destination slot. That's fine @@ -444,9 +443,10 @@ // we shouldn't claim that its lifetime is externally managed. Dest.setLifetimeExternallyManaged(DestLifetimeManaged); + eval.begin(CGF); + CGF.EmitBlock(RHSBlock); Visit(E->getRHS()); - CGF.EndConditionalBranch(); - CGF.EmitBranch(ContBlock); + eval.end(CGF); CGF.EmitBlock(ContBlock); } Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Tue Jan 25 22:00:11 2011 @@ -325,9 +325,8 @@ } ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) { - RValue result = CGF.EmitCompoundStmt(*E->getSubStmt(), true); - CGF.EnsureInsertPoint(); - return result.getComplexVal(); + CodeGenFunction::StmtExprEvaluation eval(CGF); + return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal(); } /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. @@ -647,29 +646,32 @@ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); + CodeGenFunction::ConditionalEvaluation eval(CGF); + if (E->getLHS()) CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); else { Expr *save = E->getSAVE(); assert(save && "VisitConditionalOperator - save is null"); - // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] !! + // Intentionally not doing direct assignment to ConditionalSaveExprs[save] !! ComplexPairTy SaveVal = Visit(save); CGF.ConditionalSaveComplexExprs[save] = SaveVal; CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); } + eval.begin(CGF); CGF.EmitBlock(LHSBlock); ComplexPairTy LHS = Visit(E->getTrueExpr()); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); + eval.end(CGF); + eval.begin(CGF); CGF.EmitBlock(RHSBlock); - ComplexPairTy RHS = Visit(E->getRHS()); RHSBlock = Builder.GetInsertBlock(); - CGF.EmitBranch(ContBlock); - CGF.EmitBlock(ContBlock); + eval.end(CGF); // Create a PHI node for the real part. llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r"); Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Jan 25 22:00:11 2011 @@ -1204,10 +1204,9 @@ } Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { - RValue value = CGF.EmitCompoundStmt(*E->getSubStmt(), - !E->getType()->isVoidType()); - CGF.EnsureInsertPoint(); - return value.getScalarVal(); + CodeGenFunction::StmtExprEvaluation eval(CGF); + return CGF.EmitCompoundStmt(*E->getSubStmt(), !E->getType()->isVoidType()) + .getScalarVal(); } Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { @@ -2226,6 +2225,8 @@ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs"); + CodeGenFunction::ConditionalEvaluation eval(CGF); + // Branch on the LHS first. If it is false, go to the failure (cont) block. CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock); @@ -2239,10 +2240,10 @@ PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); - CGF.BeginConditionalBranch(); + eval.begin(CGF); CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.EndConditionalBranch(); + eval.end(CGF); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -2276,6 +2277,8 @@ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs"); + CodeGenFunction::ConditionalEvaluation eval(CGF); + // Branch on the LHS first. If it is true, go to the success (cont) block. CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock); @@ -2289,13 +2292,13 @@ PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); - CGF.BeginConditionalBranch(); + eval.begin(CGF); // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.EndConditionalBranch(); + eval.end(CGF); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -2425,6 +2428,8 @@ llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); + + CodeGenFunction::ConditionalEvaluation eval(CGF); // If we don't have the GNU missing condition extension, emit a branch on bool // the normal way. @@ -2456,24 +2461,20 @@ Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); } - CGF.BeginConditionalBranch(); CGF.EmitBlock(LHSBlock); - - // Handle the GNU extension for missing LHS. + eval.begin(CGF); Value *LHS = Visit(E->getTrueExpr()); + eval.end(CGF); - CGF.EndConditionalBranch(); LHSBlock = Builder.GetInsertBlock(); - CGF.EmitBranch(ContBlock); + Builder.CreateBr(ContBlock); - CGF.BeginConditionalBranch(); CGF.EmitBlock(RHSBlock); - + eval.begin(CGF); Value *RHS = Visit(E->getRHS()); - CGF.EndConditionalBranch(); - RHSBlock = Builder.GetInsertBlock(); - CGF.EmitBranch(ContBlock); + eval.end(CGF); + RHSBlock = Builder.GetInsertBlock(); CGF.EmitBlock(ContBlock); // If the LHS or RHS is a throw expression, it will be legitimately null. Modified: cfe/trunk/lib/CodeGen/CGTemporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGTemporaries.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGTemporaries.cpp (original) +++ cfe/trunk/lib/CodeGen/CGTemporaries.cpp Tue Jan 25 22:00:11 2011 @@ -60,7 +60,7 @@ // Check if temporaries need to be conditional. If so, we'll create a // condition boolean, initialize it to 0 and - if (ConditionalBranchLevel != 0) { + if (isInConditionalBranch()) { CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); // Initialize it to false. This initialization takes place right after Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Jan 25 22:00:11 2011 @@ -41,7 +41,7 @@ SwitchInsn(0), CaseRangeBlock(0), DidCallStackSave(false), UnreachableBlock(0), CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), - ConditionalBranchLevel(0), TerminateLandingPad(0), TerminateHandler(0), + OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { // Get some frequently used types. @@ -447,13 +447,15 @@ // Emit the LHS as a conditional. If the LHS conditional is false, we // want to jump to the FalseBlock. llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true"); + + ConditionalEvaluation eval(*this); EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock); EmitBlock(LHSTrue); // Any temporaries created here are conditional. - BeginConditionalBranch(); + eval.begin(*this); EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); - EndConditionalBranch(); + eval.end(*this); return; } else if (CondBOp->getOpcode() == BO_LOr) { @@ -474,13 +476,15 @@ // Emit the LHS as a conditional. If the LHS conditional is true, we // want to jump to the TrueBlock. llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false"); + + ConditionalEvaluation eval(*this); EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse); EmitBlock(LHSFalse); // Any temporaries created here are conditional. - BeginConditionalBranch(); + eval.begin(*this); EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); - EndConditionalBranch(); + eval.end(*this); return; } @@ -500,11 +504,20 @@ // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f)) llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); + + ConditionalEvaluation cond(*this); EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock); + + cond.begin(*this); EmitBlock(LHSBlock); EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock); + cond.end(*this); + + cond.begin(*this); EmitBlock(RHSBlock); EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock); + cond.end(*this); + return; } } Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jan 25 22:00:11 2011 @@ -97,6 +97,24 @@ llvm::BranchInst *InitialBranch; }; +/// A metaprogramming class which decides whether a type is a subclass +/// of llvm::Value that needs to be saved if it's used in a +/// conditional cleanup. +template + >::value + && !llvm::is_base_of >::value + && !llvm::is_base_of >::value> +struct SavedValueInCond { + typedef T type; + typedef T saved_type; + static bool needsSaving(type value) { return false; } + static saved_type save(CodeGenFunction &CGF, type value) { return value; } + static type restore(CodeGenFunction &CGF, saved_type value) { return value; } +}; +// Partial specialization for true arguments at end of file. + enum CleanupKind { EHCleanup = 0x1, NormalCleanup = 0x2, @@ -175,6 +193,52 @@ virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0; }; + /// A helper class for cleanups that execute conditionally. + class ConditionalCleanup : public Cleanup { + /// Either an i1 which directly indicates whether the cleanup + /// should be run or an i1* from which that should be loaded. + llvm::Value *cond; + + public: + virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup); + + protected: + ConditionalCleanup(llvm::Value *cond) : cond(cond) {} + + /// Emit the non-conditional code for the cleanup. + virtual void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) = 0; + }; + + /// UnconditionalCleanupN stores its N parameters and just passes + /// them to the real cleanup function. + template + class UnconditionalCleanup2 : public Cleanup { + A0 a0; A1 a1; + UnconditionalCleanup2(A0 a0, A1 a1) : a0(a0), a1(a1) {} + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + T::Emit(CGF, IsForEHCleanup, a0, a1); + } + }; + + /// ConditionalCleanupN stores the saved form of its N parameters, + /// then restores them and performs the cleanup. + template + class ConditionalCleanup2 : public ConditionalCleanup { + typedef typename SavedValueInCond::saved_type A0_saved; + typedef typename SavedValueInCond::saved_type A1_saved; + A0_saved a0; A1_saved a1; + + void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) { + A0 a0 = SavedValueInCond::restore(CGF, a0); + A1 a1 = SavedValueInCond::restore(CGF, a1); + T::Emit(CGF, IsForEHCleanup, a0, a1); + } + + public: + ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1) + : ConditionalCleanup(cond), a0(a0), a1(a1) {} + }; + private: // The implementation for this class is in CGException.h and // CGException.cpp; the definition is here because it's used as a @@ -536,6 +600,14 @@ llvm::BasicBlock *getInvokeDestImpl(); + /// Sets up a condition for a full-expression cleanup. + llvm::Value *initFullExprCleanup(); + + template + typename SavedValueInCond::saved_type saveValueInCond(T value) { + return SavedValueInCond::save(*this, value); + } + public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. @@ -552,6 +624,28 @@ llvm::Constant *RethrowFn); void ExitFinallyBlock(FinallyInfo &FinallyInfo); + /// pushFullExprCleanup - Push a cleanup to be run at the end of the + /// current full-expression. Safe against the possibility that + /// we're currently inside a conditionally-evaluated expression. + template + void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) { + // If we're not in a conditional branch, or if none of the + // arguments requires saving, then use the unconditional cleanup. + if (!(isInConditionalBranch() || + SavedValueInCond::needsSaving(a0) || + SavedValueInCond::needsSaving(a1))) { + typedef EHScopeStack::UnconditionalCleanup2 CleanupType; + return EHStack.pushCleanup(kind, a0, a1); + } + + llvm::Value *condVar = initFullExprCleanup(); + typename SavedValueInCond::saved_type a0_saved = saveValueInCond(a0); + typename SavedValueInCond::saved_type a1_saved = saveValueInCond(a1); + + typedef EHScopeStack::ConditionalCleanup2 CleanupType; + EHStack.pushCleanup(kind, condVar, a0_saved, a1_saved); + } + /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the /// given address. Does nothing if T is not a C++ class type with a @@ -659,30 +753,58 @@ /// destination. UnwindDest getRethrowDest(); - /// BeginConditionalBranch - Should be called before a conditional part of an - /// expression is emitted. For example, before the RHS of the expression below - /// is emitted: - /// - /// b && f(T()); - /// - /// This is used to make sure that any temporaries created in the conditional - /// branch are only destroyed if the branch is taken. - void BeginConditionalBranch() { - ++ConditionalBranchLevel; - } + /// An object to manage conditionally-evaluated expressions. + class ConditionalEvaluation { + llvm::BasicBlock *StartBB; - /// EndConditionalBranch - Should be called after a conditional part of an - /// expression has been emitted. - void EndConditionalBranch() { - assert(ConditionalBranchLevel != 0 && - "Conditional branch mismatch!"); + public: + ConditionalEvaluation(CodeGenFunction &CGF) + : StartBB(CGF.Builder.GetInsertBlock()) {} - --ConditionalBranchLevel; - } + void begin(CodeGenFunction &CGF) { + assert(CGF.OutermostConditional != this); + if (!CGF.OutermostConditional) + CGF.OutermostConditional = this; + } + + void end(CodeGenFunction &CGF) { + assert(CGF.OutermostConditional != 0); + if (CGF.OutermostConditional == this) + CGF.OutermostConditional = 0; + } + + /// Returns a block which will be executed prior to each + /// evaluation of the conditional code. + llvm::BasicBlock *getStartingBlock() const { + return StartBB; + } + }; /// isInConditionalBranch - Return true if we're currently emitting /// one branch or the other of a conditional expression. - bool isInConditionalBranch() const { return ConditionalBranchLevel != 0; } + bool isInConditionalBranch() const { return OutermostConditional != 0; } + + /// An RAII object to record that we're evaluating a statement + /// expression. + class StmtExprEvaluation { + CodeGenFunction &CGF; + + /// We have to save the outermost conditional: cleanups in a + /// statement expression aren't conditional just because the + /// StmtExpr is. + ConditionalEvaluation *SavedOutermostConditional; + + public: + StmtExprEvaluation(CodeGenFunction &CGF) + : CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) { + CGF.OutermostConditional = 0; + } + + ~StmtExprEvaluation() { + CGF.OutermostConditional = SavedOutermostConditional; + CGF.EnsureInsertPoint(); + } + }; /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field /// number that holds the value. @@ -750,10 +872,10 @@ ImplicitParamDecl *CXXVTTDecl; llvm::Value *CXXVTTValue; - /// ConditionalBranchLevel - Contains the nesting level of the current - /// conditional branch. This is used so that we know if a temporary should be - /// destroyed conditionally. - unsigned ConditionalBranchLevel; + /// OutermostConditional - Points to the outermost active + /// conditional control. This is used so that we know if a + /// temporary should be destroyed conditionally. + ConditionalEvaluation *OutermostConditional; /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM @@ -1786,6 +1908,48 @@ void EmitDeclMetadata(); }; +/// Helper class with most of the code for saving a value for a +/// conditional expression cleanup. +struct SavedValueInCondImpl { + typedef llvm::PointerIntPair saved_type; + + /// Answer whether the given value needs extra work to be saved. + static bool needsSaving(llvm::Value *value) { + // If it's not an instruction, we don't need to save. + if (!isa(value)) return false; + + // If it's an instruction in the entry block, we don't need to save. + llvm::BasicBlock *block = cast(value)->getParent(); + return (block != &block->getParent()->getEntryBlock()); + } + + /// Try to save the given value. + static saved_type save(CodeGenFunction &CGF, llvm::Value *value) { + if (!needsSaving(value)) return saved_type(value, false); + + // Otherwise we need an alloca. + llvm::Value *alloca = + CGF.CreateTempAlloca(value->getType(), "cond-cleanup.save"); + CGF.Builder.CreateStore(value, alloca); + + return saved_type(alloca, true); + } + + static llvm::Value *restore(CodeGenFunction &CGF, saved_type value) { + if (!value.getInt()) return value.getPointer(); + return CGF.Builder.CreateLoad(value.getPointer()); + } +}; + +/// Partial specialization of SavedValueInCond for when a value really +/// requires saving. +template struct SavedValueInCond : SavedValueInCondImpl { + typedef T type; + static type restore(CodeGenFunction &CGF, saved_type value) { + return static_cast(SavedValueInCondImpl::restore(CGF, value)); + } +}; + /// CGBlockInfo - Information to generate a block literal. class CGBlockInfo { public: Modified: cfe/trunk/test/CodeGenCXX/volatile-1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/volatile-1.cpp?rev=124277&r1=124276&r2=124277&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/volatile-1.cpp (original) +++ cfe/trunk/test/CodeGenCXX/volatile-1.cpp Tue Jan 25 22:00:11 2011 @@ -143,20 +143,17 @@ // CHECK-NEXT: volatile load // CHECK-NEXT: volatile store - // FIXME: the phi-equivalent is unnecessary k ? (i=i) : (j=j); // CHECK-NEXT: volatile load // CHECK-NEXT: icmp // CHECK-NEXT: br i1 // CHECK: volatile load // CHECK-NEXT: volatile store - // CHECK-NEXT: store [[INT]]* @i // CHECK-NEXT: br label // CHECK: volatile load // CHECK-NEXT: volatile store - // CHECK-NEXT: store [[INT]]* @j // CHECK-NEXT: br label - // CHECK: load [[INT]]** + // CHECK: phi (void)(i,(i=i)); // CHECK-NEXT: volatile load From kremenek at apple.com Tue Jan 25 20:49:43 2011 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 26 Jan 2011 04:49:43 -0000 Subject: [cfe-commits] r124278 - in /cfe/trunk: lib/Analysis/UninitializedValuesV2.cpp test/Sema/uninit-variables.c Message-ID: <20110126044943.9DC012A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 22:49:43 2011 New Revision: 124278 URL: http://llvm.org/viewvc/llvm-project?rev=124278&view=rev Log: Tweak -Wuninitialized-experimental to not emit a warning for uses of an uninitialized variable when the use is a void cast, e.g. (void) x. Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp cfe/trunk/test/Sema/uninit-variables.c Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp?rev=124278&r1=124277&r2=124278&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp (original) +++ cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Tue Jan 25 22:49:43 2011 @@ -291,6 +291,7 @@ AnalysisContext ∾ UninitVariablesHandler *handler; const DeclRefExpr *currentDR; + const Expr *currentVoidCast; const bool flagBlockUses; public: TransferFunctions(CFGBlockValues &vals, const CFG &cfg, @@ -298,7 +299,7 @@ UninitVariablesHandler *handler, bool flagBlockUses) : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), - flagBlockUses(flagBlockUses) {} + currentVoidCast(0), flagBlockUses(flagBlockUses) {} const CFG &getCFG() { return cfg; } void reportUninit(const DeclRefExpr *ex, const VarDecl *vd); @@ -446,14 +447,23 @@ SaveAndRestore lastDR(currentDR, res.getDeclRefExpr()); Visit(ce->getSubExpr()); - if (vals[vd] == Uninitialized) { + if (currentVoidCast != ce && vals[vd] == Uninitialized) { reportUninit(res.getDeclRefExpr(), vd); // Don't cascade warnings. vals[vd] = Initialized; } return; } - } + } + else if (CStyleCastExpr *cse = dyn_cast(ce)) { + if (cse->getType()->isVoidType()) { + // e.g. (void) x; + SaveAndRestore + lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens()); + Visit(cse->getSubExpr()); + return; + } + } Visit(ce->getSubExpr()); } Modified: cfe/trunk/test/Sema/uninit-variables.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124278&r1=124277&r2=124278&view=diff ============================================================================== --- cfe/trunk/test/Sema/uninit-variables.c (original) +++ cfe/trunk/test/Sema/uninit-variables.c Tue Jan 25 22:49:43 2011 @@ -212,3 +212,14 @@ (void) ^{ (void) test32_x; }; // no-warning } +void test_33() { + int x; // no-warning + (void) x; +} + +int test_34() { + int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} + (void) x; + return x; // expected-note{{variable 'x' is possibly uninitialized when used here}} +} + From kremenek at apple.com Tue Jan 25 20:49:48 2011 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 26 Jan 2011 04:49:48 -0000 Subject: [cfe-commits] r124279 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td test/Preprocessor/pragma_diagnostic_sections.cpp test/Sema/uninit-variables.c test/SemaCXX/uninit-variables.cpp Message-ID: <20110126044948.77A142A6C12D@llvm.org> Author: kremenek Date: Tue Jan 25 22:49:48 2011 New Revision: 124279 URL: http://llvm.org/viewvc/llvm-project?rev=124279&view=rev Log: Merge -Wuninitialized-experimental into -Wuninitialized. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp cfe/trunk/test/Sema/uninit-variables.c cfe/trunk/test/SemaCXX/uninit-variables.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124279&r1=124278&r2=124279&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 22:49:48 2011 @@ -821,9 +821,9 @@ def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field is uninitialized when used here">, - InGroup>; + InGroup; def warn_uninit_var : Warning<"use of uninitialized variable %0">, - InGroup>, DefaultIgnore; + InGroup, DefaultIgnore; def note_uninit_var : Note< "variable %0 is possibly uninitialized when used here">; def note_uninit_var_captured_by_block : Note< Modified: cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp?rev=124279&r1=124278&r2=124279&view=diff ============================================================================== --- cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp (original) +++ cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp Tue Jan 25 22:49:48 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -Wno-uninitialized -verify %s // rdar://8365684 struct S { Modified: cfe/trunk/test/Sema/uninit-variables.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124279&r1=124278&r2=124279&view=diff ============================================================================== --- cfe/trunk/test/Sema/uninit-variables.c (original) +++ cfe/trunk/test/Sema/uninit-variables.c Tue Jan 25 22:49:48 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fblocks %s -verify int test1() { int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} Modified: cfe/trunk/test/SemaCXX/uninit-variables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninit-variables.cpp?rev=124279&r1=124278&r2=124279&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/uninit-variables.cpp (original) +++ cfe/trunk/test/SemaCXX/uninit-variables.cpp Tue Jan 25 22:49:48 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only %s -verify +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only %s -verify int test1_aux(int &x); int test1() { From kremenek at apple.com Tue Jan 25 20:49:52 2011 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 26 Jan 2011 04:49:52 -0000 Subject: [cfe-commits] r124280 - in /cfe/trunk: lib/Sema/AnalysisBasedWarnings.cpp test/SemaCXX/warn-missing-noreturn.cpp Message-ID: <20110126044952.761742A6C12C@llvm.org> Author: kremenek Date: Tue Jan 25 22:49:52 2011 New Revision: 124280 URL: http://llvm.org/viewvc/llvm-project?rev=124280&view=rev Log: Teach -Wreturn-type that destructors can appear after a 'return' in a CFGBlock. This accidentally was working before, but the false assumption that 'return' always appeared at the end of the block was uncovered by a recent change. Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124280&r1=124279&r2=124280&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Jan 25 22:49:52 2011 @@ -121,26 +121,29 @@ const CFGBlock& B = **I; if (!live[B.getBlockID()]) continue; - if (B.size() == 0) { + + // Destructors can appear after the 'return' in the CFG. This is + // normal. We need to look pass the destructors for the return + // statement (if it exists). + CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); + for ( ; ri != re ; ++ri) { + CFGElement CE = *ri; + if (isa(CE)) + break; + } + + // No more CFGElements in the block? + if (ri == re) { if (B.getTerminator() && isa(B.getTerminator())) { HasAbnormalEdge = true; continue; } - // A labeled empty statement, or the entry block... HasPlainEdge = true; continue; } - CFGElement CE = B[B.size()-1]; - - if (!isa(CE)) { - HasPlainEdge = true; - continue; - } - CFGStmt CS = CE.getAs(); - if (!CS.isValid()) - continue; + CFGStmt CS = cast(*ri); Stmt *S = CS.getStmt(); if (isa(S)) { HasLiveReturn = true; Modified: cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp?rev=124280&r1=124279&r2=124280&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-missing-noreturn.cpp Tue Jan 25 22:49:52 2011 @@ -93,3 +93,13 @@ rdar8875247 f; } // expected-warning{{control reaches end of non-void function}} +struct rdar8875247_B { + rdar8875247_B(); + ~rdar8875247_B(); +}; + +rdar8875247_B test_rdar8875247_B() { + rdar8875247_B f; + return f; +} // no-warning + From dgregor at apple.com Tue Jan 25 21:01:58 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 05:01:58 -0000 Subject: [cfe-commits] r124281 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaType.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp test/CXX/special/class.ctor/p4-0x.cpp test/CXX/special/class.dtor/p2-0x.cpp Message-ID: <20110126050159.414702A6C12C@llvm.org> Author: dgregor Date: Tue Jan 25 23:01:58 2011 New Revision: 124281 URL: http://llvm.org/viewvc/llvm-project?rev=124281&view=rev Log: Rvalue references for *this: - Add ref-qualifiers to the type system; they are part of the canonical type. Print & profile ref-qualifiers - Translate the ref-qualifier from the Declarator chunk for functions to the function type. - Diagnose mis-uses of ref-qualifiers w.r.t. static member functions, free functions, constructors, destructors, etc. - Add serialization and deserialization of ref-qualifiers. Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (with props) cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp (with props) cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp (with props) Modified: cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/AST/TypePrinter.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Tue Jan 25 23:01:58 2011 @@ -823,6 +823,18 @@ } }; +/// \brief The kind of C++0x ref-qualifier associated with a function type, +/// which determines whether a member function's "this" object can be an +/// lvalue, rvalue, or neither. +enum RefQualifierKind { + /// \brief No ref-qualifier was provided. + RQ_None = 0, + /// \brief An lvalue ref-qualifier was provided (\c &). + RQ_LValue, + /// \brief An rvalue ref-qualifier was provided (\c &&). + RQ_RValue +}; + /// Type - This is the base class of the type hierarchy. A central concept /// with types is that each type always has a canonical type. A canonical type /// is the type with any typedef names stripped out of it or the types it @@ -961,6 +973,11 @@ /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. unsigned TypeQuals : 3; + + /// \brief The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; }; class ObjCObjectTypeBitfields { @@ -2267,7 +2284,8 @@ protected: FunctionType(TypeClass tc, QualType res, bool variadic, - unsigned typeQuals, QualType Canonical, bool Dependent, + unsigned typeQuals, RefQualifierKind RefQualifier, + QualType Canonical, bool Dependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) : Type(tc, Canonical, Dependent, VariablyModified, @@ -2276,9 +2294,15 @@ FunctionTypeBits.ExtInfo = Info.Bits; FunctionTypeBits.Variadic = variadic; FunctionTypeBits.TypeQuals = typeQuals; + FunctionTypeBits.RefQualifier = static_cast(RefQualifier); } bool isVariadic() const { return FunctionTypeBits.Variadic; } unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } + + RefQualifierKind getRefQualifier() const { + return static_cast(FunctionTypeBits.RefQualifier); + } + public: QualType getResultType() const { return ResultType; } @@ -2307,7 +2331,7 @@ /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) - : FunctionType(FunctionNoProto, Result, false, 0, Canonical, + : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical, /*Dependent=*/false, Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} @@ -2345,13 +2369,14 @@ struct ExtProtoInfo { ExtProtoInfo() : Variadic(false), HasExceptionSpec(false), HasAnyExceptionSpec(false), - TypeQuals(0), NumExceptions(0), Exceptions(0) {} + TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0) {} FunctionType::ExtInfo ExtInfo; bool Variadic; bool HasExceptionSpec; bool HasAnyExceptionSpec; unsigned char TypeQuals; + RefQualifierKind RefQualifier; unsigned NumExceptions; const QualType *Exceptions; }; @@ -2405,6 +2430,7 @@ EPI.HasExceptionSpec = hasExceptionSpec(); EPI.HasAnyExceptionSpec = hasAnyExceptionSpec(); EPI.TypeQuals = static_cast(getTypeQuals()); + EPI.RefQualifier = getRefQualifier(); EPI.NumExceptions = NumExceptions; EPI.Exceptions = exception_begin(); return EPI; @@ -2434,6 +2460,12 @@ unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + + /// \brief Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return FunctionType::getRefQualifier(); + } + typedef const QualType *arg_type_iterator; arg_type_iterator arg_type_begin() const { return reinterpret_cast(this+1); Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 23:01:58 2011 @@ -730,6 +730,9 @@ def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; +def err_ref_qualifier_constructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; + def err_constructor_return_type : Error< "constructor cannot have a return type">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">; @@ -749,6 +752,8 @@ def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; +def err_ref_qualifier_destructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; def err_destructor_redeclared : Error<"destructor cannot be redeclared">; def err_destructor_with_params : Error<"destructor cannot have any parameters">; @@ -2461,11 +2466,17 @@ "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< "type qualifier is not allowed on this function">; +def err_invalid_ref_qualifier_function_type : Error< + "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions," + " member function pointers, and typedefs of function types">; def err_invalid_qualified_function_pointer : Error< "type qualifier is not allowed on this function %select{pointer|reference}0">; def err_invalid_qualified_typedef_function_type_use : Error< "a qualified function type cannot be used to declare a " "%select{static member|nonmember}0 function">; +def err_invalid_ref_qualifier_typedef_function_type_use : Error< + "%select{static member|nonmember}0 function cannot have a ref-qualifier " + "'%select{&&|&}1'">; def err_invalid_non_static_member_use : Error< "invalid use of nonstatic data member %0">; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Jan 25 23:01:58 2011 @@ -620,7 +620,8 @@ SourceLocation AttrLoc); QualType BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, - bool Variadic, unsigned Quals, + bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, FunctionType::ExtInfo Info); QualType BuildMemberPointerType(QualType T, QualType Class, Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Tue Jan 25 23:01:58 2011 @@ -1112,7 +1112,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, unsigned numArgs, QualType canonical, const ExtProtoInfo &epi) - : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, canonical, + : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, + epi.RefQualifier, canonical, result->isDependentType(), result->isVariablyModifiedType(), result->containsUnexpandedParameterPack(), @@ -1162,6 +1163,7 @@ ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddBoolean(epi.Variadic); ID.AddInteger(epi.TypeQuals); + ID.AddInteger(epi.RefQualifier); if (epi.HasExceptionSpec) { ID.AddBoolean(epi.HasAnyExceptionSpec); for (unsigned i = 0; i != epi.NumExceptions; ++i) Modified: cfe/trunk/lib/AST/TypePrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/AST/TypePrinter.cpp (original) +++ cfe/trunk/lib/AST/TypePrinter.cpp Tue Jan 25 23:01:58 2011 @@ -354,6 +354,21 @@ S += " __attribute__((regparm (" + llvm::utostr_32(Info.getRegParm()) + ")))"; + AppendTypeQualList(S, T->getTypeQuals()); + + switch (T->getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + S += " &"; + break; + + case RQ_RValue: + S += " &&"; + break; + } + if (T->hasExceptionSpec()) { S += " throw("; if (T->hasAnyExceptionSpec()) @@ -370,8 +385,6 @@ S += ")"; } - AppendTypeQualList(S, T->getTypeQuals()); - print(T->getResultType(), S); } Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jan 25 23:01:58 2011 @@ -3023,6 +3023,15 @@ D.setInvalidType(); } + // C++0x [class.ctor]p4: + // A constructor shall not be declared with a ref-qualifier. + if (FTI.hasRefQualifier()) { + Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor) + << FTI.RefQualifierIsLValueRef + << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); + D.setInvalidType(); + } + // Rebuild the function type "R" without any type qualifiers (in // case any of the errors above fired) and with "void" as the // return type, since constructors don't have return types. @@ -3032,7 +3041,8 @@ FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.TypeQuals = 0; - + EPI.RefQualifier = RQ_None; + return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), Proto->getNumArgs(), EPI); } @@ -3173,6 +3183,15 @@ D.setInvalidType(); } + // C++0x [class.dtor]p2: + // A destructor shall not be declared with a ref-qualifier. + if (FTI.hasRefQualifier()) { + Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor) + << FTI.RefQualifierIsLValueRef + << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); + D.setInvalidType(); + } + // Make sure we don't have any parameters. if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) { Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); @@ -3199,6 +3218,7 @@ FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.Variadic = false; EPI.TypeQuals = 0; + EPI.RefQualifier = RQ_None; return Context.getFunctionType(Context.VoidTy, 0, 0, EPI); } Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Jan 25 23:01:58 2011 @@ -2106,6 +2106,7 @@ ParamTypes.data(), ParamTypes.size(), Proto->isVariadic(), Proto->getTypeQuals(), + Proto->getRefQualifier(), Function->getLocation(), Function->getDeclName(), Proto->getExtInfo()); Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jan 25 23:01:58 2011 @@ -1269,6 +1269,7 @@ QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, FunctionType::ExtInfo Info) { if (T->isArrayType() || T->isFunctionType()) { @@ -1294,6 +1295,7 @@ FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = Variadic; EPI.TypeQuals = Quals; + EPI.RefQualifier = RefQualifier; EPI.ExtInfo = Info; return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI); @@ -1722,7 +1724,10 @@ FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = FTI.isVariadic; EPI.TypeQuals = FTI.TypeQuals; - + EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None + : FTI.RefQualifierIsLValueRef? RQ_LValue + : RQ_RValue; + // Otherwise, we have a function with an argument list that is // potentially variadic. llvm::SmallVector ArgTys; @@ -1876,21 +1881,44 @@ FreeFunction = (DC && !DC->isRecord()); } - if (FnTy->getTypeQuals() != 0 && + // C++0x [dcl.fct]p6: + // A ref-qualifier shall only be part of the function type for a + // non-static member function, the function type to which a pointer to + // member refers, or the top-level function type of a function typedef + // declaration. + if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && (FreeFunction || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { - if (D.isFunctionDeclarator()) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); - else - Diag(D.getIdentifierLoc(), - diag::err_invalid_qualified_typedef_function_type_use) - << FreeFunction; - - // Strip the cv-quals from the type. + if (FnTy->getTypeQuals() != 0) { + if (D.isFunctionDeclarator()) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); + else + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_typedef_function_type_use) + << FreeFunction; + } + + if (FnTy->getRefQualifier()) { + if (D.isFunctionDeclarator()) { + SourceLocation Loc + = D.getTypeObject(D.getNumTypeObjects()-1).Fun.getRefQualifierLoc(); + Diag(Loc, diag::err_invalid_ref_qualifier_function_type) + << (FnTy->getRefQualifier() == RQ_LValue) + << FixItHint::CreateRemoval(Loc); + } else { + Diag(D.getIdentifierLoc(), + diag::err_invalid_ref_qualifier_typedef_function_type_use) + << FreeFunction + << (FnTy->getRefQualifier() == RQ_LValue); + } + } + + // Strip the cv-quals and ref-qualifier from the type. FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); EPI.TypeQuals = 0; - + EPI.RefQualifier = RQ_None; + T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), EPI); } Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Jan 25 23:01:58 2011 @@ -633,6 +633,7 @@ QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, const FunctionType::ExtInfo &Info); /// \brief Build a new unprototyped function type. @@ -3796,6 +3797,7 @@ ParamTypes.size(), T->isVariadic(), T->getTypeQuals(), + T->getRefQualifier(), T->getExtInfo()); if (Result.isNull()) return QualType(); @@ -7178,7 +7180,7 @@ ParamTypes.data(), ParamTypes.size(), BD->isVariadic(), - 0, + 0, RQ_None, BExprFunctionType->getExtInfo()); CurBlock->FunctionType = FunctionType; @@ -7373,9 +7375,10 @@ unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, const FunctionType::ExtInfo &Info) { return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals, + Quals, RefQualifier, getDerived().getBaseLocation(), getDerived().getBaseEntity(), Info); Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Jan 25 23:01:58 2011 @@ -2873,6 +2873,7 @@ EPI.Variadic = Record[Idx++]; EPI.TypeQuals = Record[Idx++]; + EPI.RefQualifier = static_cast(Record[Idx++]); EPI.HasExceptionSpec = Record[Idx++]; EPI.HasAnyExceptionSpec = Record[Idx++]; EPI.NumExceptions = Record[Idx++]; Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=124281&r1=124280&r2=124281&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Jan 25 23:01:58 2011 @@ -176,6 +176,7 @@ Writer.AddTypeRef(T->getArgType(I), Record); Record.push_back(T->isVariadic()); Record.push_back(T->getTypeQuals()); + Record.push_back(static_cast(T->getRefQualifier())); Record.push_back(T->hasExceptionSpec()); Record.push_back(T->hasAnyExceptionSpec()); Record.push_back(T->getNumExceptions()); Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp?rev=124281&view=auto ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (added) +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Tue Jan 25 23:01:58 2011 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}} +void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}} + +struct X { + void f0() &; + void f1() &&; + static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}} + static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}} +}; + +typedef void func_type_lvalue() &; +typedef void func_type_rvalue() &&; + +func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}} +func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}} + +struct Y { + func_type_lvalue f0; + func_type_rvalue f1; +}; + +void (X::*mpf1)() & = &X::f0; +void (X::*mpf2)() && = &X::f1; + Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp?rev=124281&view=auto ============================================================================== --- cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp (added) +++ cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp Tue Jan 25 23:01:58 2011 @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// A constructor shall not be declared with a ref-qualifier. +struct X { + X() &; // expected-error{{ref-qualifier '&' is not allowed on a constructor}} + X(int) &&; // expected-error{{ref-qualifier '&&' is not allowed on a constructor}} +}; Propchange: cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/special/class.ctor/p4-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp?rev=124281&view=auto ============================================================================== --- cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp (added) +++ cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp Tue Jan 25 23:01:58 2011 @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// A destructor shall not be declared with a ref-qualifier. +struct X { + ~X() &; // expected-error{{ref-qualifier '&' is not allowed on a destructor}} +}; + +struct Y { + ~Y() &&; // expected-error{{ref-qualifier '&&' is not allowed on a destructor}} +}; Propchange: cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/special/class.dtor/p2-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From echristo at apple.com Tue Jan 25 22:48:08 2011 From: echristo at apple.com (Eric Christopher) Date: Tue, 25 Jan 2011 22:48:08 -0800 Subject: [cfe-commits] r124280 - in /cfe/trunk: lib/Sema/AnalysisBasedWarnings.cpp test/SemaCXX/warn-missing-noreturn.cpp In-Reply-To: <20110126044952.761742A6C12C@llvm.org> References: <20110126044952.761742A6C12C@llvm.org> Message-ID: <2882AF0A-542C-487E-8F4A-EC4B5D82AC28@apple.com> On Jan 25, 2011, at 8:49 PM, Ted Kremenek wrote: > Author: kremenek > Date: Tue Jan 25 22:49:52 2011 > New Revision: 124280 > > URL: http://llvm.org/viewvc/llvm-project?rev=124280&view=rev > Log: > Teach -Wreturn-type that destructors can appear > after a 'return' in a CFGBlock. This accidentally > was working before, but the false assumption that > 'return' always appeared at the end of the block > was uncovered by a recent change. Thanks Ted! -eric From zaffanella at cs.unipr.it Wed Jan 26 01:41:47 2011 From: zaffanella at cs.unipr.it (Enea Zaffanella) Date: Wed, 26 Jan 2011 10:41:47 +0100 Subject: [cfe-commits] r123959 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/Basic/Attr.td include/clang/Basic/AttrKinds.h lib/Sema/SemaDecl.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp In-Reply-To: <20110121020837.29CD32A6C12C@llvm.org> References: <20110121020837.29CD32A6C12C@llvm.org> Message-ID: <4D3FEC5B.1000304@cs.unipr.it> Il 21/01/2011 03:08, Peter Collingbourne ha scritto: > Author: pcc > Date: Thu Jan 20 20:08:36 2011 > New Revision: 123959 > > URL: http://llvm.org/viewvc/llvm-project?rev=123959&view=rev > Log: > Generalise support for non-inheritable attributes [...] > The patch introduces a new Attr subclass, InheritableAttr, from > which all inheritable attributes derive. Non-inheritable attributes > simply derive from Attr. [...] > - bool isInherited() const { return Inherited; } Why removing this query method from the base class Attr? May I suggest to make it virtual (with a default implementation returning false) and then override it in InheritableAttr? Otherwise, a client going through the list of all attributes (such as a pretty printer) will have to manually do some RTTI just to know if the attribute was written in the sources. Enea. From dgregor at apple.com Wed Jan 26 06:52:12 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 14:52:12 -0000 Subject: [cfe-commits] r124290 - in /cfe/trunk: include/clang/Sema/Overload.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Message-ID: <20110126145212.A9F622A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 08:52:12 2011 New Revision: 124290 URL: http://llvm.org/viewvc/llvm-project?rev=124290&view=rev Log: Reinstate r124236 (tweaking the rvalue-reference overload resolution rules), now that we've actually have a clean build for me to sully. Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124290&r1=124289&r2=124290&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 26 08:52:12 2011 @@ -133,24 +133,30 @@ /// Deprecated - Whether this the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - bool DeprecatedStringLiteralToCharPtr : 1; + unsigned DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). - bool IncompatibleObjC : 1; + unsigned IncompatibleObjC : 1; /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). - bool ReferenceBinding : 1; + unsigned ReferenceBinding : 1; /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). - bool DirectBinding : 1; - - /// RRefBinding - True when this is a reference binding of an rvalue - /// reference to an rvalue (C++0x [over.ics.rank]p3b4). - bool RRefBinding : 1; + unsigned DirectBinding : 1; + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124290&r1=124289&r2=124290&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 08:52:12 2011 @@ -170,7 +170,9 @@ DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; - RRefBinding = false; + IsLvalueReference = true; + BindsToFunctionLvalue = false; + BindsToRvalue = false; CopyConstructor = 0; } @@ -2324,6 +2326,33 @@ return ImplicitConversionSequence::Indistinguishable; } +/// \brief Determine whether one of the given reference bindings is better +/// than the other based on what kind of bindings they are. +static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, + const StandardConversionSequence &SCS2) { + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and *either* S1 binds an rvalue reference + // to an rvalue and S2 binds an lvalue reference *or S1 binds an + // lvalue reference to a function lvalue and S2 binds an rvalue + // reference*. + // + // FIXME: Rvalue references. We're going rogue with the above edits, + // because the semantics in the current C++0x working paper (N3225 at the + // time of this writing) break the standard definition of std::forward + // and std::reference_wrapper when dealing with references to functions. + // Proposed wording changes submitted to CWG for consideration. + // + // FIXME: Rvalue references. We don't know if we're dealing with the + // implicit object parameter, or if the member function in this case has a + // ref qualifier. (Of course, we don't have ref qualifiers yet.) + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && + SCS2.IsLvalueReference) || + (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && + !SCS2.IsLvalueReference); +} + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -2429,18 +2458,12 @@ return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { - // C++0x [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an - // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and S1 binds an rvalue reference to an - // rvalue and S2 binds an lvalue reference. - // FIXME: Rvalue references. We don't know if we're dealing with the - // implicit object parameter, or if the member function in this case has a - // ref qualifier. (Of course, we don't have ref qualifiers yet.) - if (SCS1.RRefBinding != SCS2.RRefBinding) - return SCS1.RRefBinding ? ImplicitConversionSequence::Better - : ImplicitConversionSequence::Worse; - + // Check for a better reference binding based on the kind of bindings. + if (isBetterReferenceBindingKind(SCS1, SCS2)) + return ImplicitConversionSequence::Better; + else if (isBetterReferenceBindingKind(SCS2, SCS1)) + return ImplicitConversionSequence::Worse; + // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -2966,7 +2989,9 @@ ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = false; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3036,7 +3061,9 @@ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3114,10 +3141,14 @@ // Of course, that's still a reference binding. if (ICS.isStandard()) { ICS.Standard.ReferenceBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; - ICS.UserDefined.After.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } return ICS; @@ -3212,7 +3243,11 @@ ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = false; + + // FIXME: Rvalue references. + ICS.Standard.IsLvalueReference = true; + ICS.Standard.BindsToFunctionLvalue = false; + ICS.Standard.BindsToRvalue = false; return ICS; } Modified: cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp?rev=124290&r1=124289&r2=124290&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp Wed Jan 26 08:52:12 2011 @@ -50,10 +50,10 @@ }; namespace FunctionReferencesOverloading { - template int &f(typename remove_reference::type&); // expected-note{{candidate function [with T = int (&)(int)]}} - template float &f(typename remove_reference::type&&); // expected-note{{candidate function [with T = int (&)(int)]}} + template int &f(typename remove_reference::type&); + template float &f(typename remove_reference::type&&); void test_f(int (&func_ref)(int)) { - f(func_ref); // expected-error{{call to 'f' is ambiguous}} + int &ir = f(func_ref); } } From dgregor at apple.com Wed Jan 26 07:36:04 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 15:36:04 -0000 Subject: [cfe-commits] r124291 - in /cfe/trunk: include/clang/Sema/Overload.h lib/Lex/PPMacroExpansion.cpp test/Lexer/has_feature_cxx0x.cpp Message-ID: <20110126153604.1D0542A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 09:36:03 2011 New Revision: 124291 URL: http://llvm.org/viewvc/llvm-project?rev=124291&view=rev Log: Clean up the C++0x __has_feature tests. Specifically: - Don't publicize a C++0x feature through __has_feature if we aren't in C++0x mode (even if the feature is available only with a warning). - "auto" is not implemented well enough for its __has_feature to be turned on. - Fix the test of C++0x __has_feature to actually test what we're trying to test. Searching for the substring "foo" when our options are "foo" and "no_foo" doesn't work :) Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124291&r1=124290&r2=124291&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 26 09:36:03 2011 @@ -130,7 +130,7 @@ /// Third - The third conversion can be a qualification conversion. ImplicitConversionKind Third : 8; - /// Deprecated - Whether this the deprecated conversion of a + /// \brief Whether this is the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). unsigned DeprecatedStringLiteralToCharPtr : 1; Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124291&r1=124290&r2=124291&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Jan 26 09:36:03 2011 @@ -540,26 +540,27 @@ .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) .Case("blocks", LangOpts.Blocks) - .Case("cxx_attributes", LangOpts.CPlusPlus0x) - .Case("cxx_auto_type", LangOpts.CPlusPlus0x) - .Case("cxx_decltype", LangOpts.CPlusPlus0x) - .Case("cxx_deleted_functions", true) // Accepted as an extension. .Case("cxx_exceptions", LangOpts.Exceptions) .Case("cxx_rtti", LangOpts.RTTI) - .Case("cxx_strong_enums", LangOpts.CPlusPlus0x) - .Case("cxx_static_assert", LangOpts.CPlusPlus0x) - .Case("cxx_trailing_return", LangOpts.CPlusPlus0x) .Case("enumerator_attributes", true) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) - .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) + // C++0x features + .Case("cxx_attributes", LangOpts.CPlusPlus0x) + //.Case("cxx_auto_type", false) + .Case("cxx_decltype", LangOpts.CPlusPlus0x) + .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) + .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) //.Case("cxx_nullptr", false) - .Case("cxx_rvalue_references", LangOpts.CPlusPlus) - .Case("cxx_variadic_templates", LangOpts.CPlusPlus) + .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x) + .Case("cxx_strong_enums", LangOpts.CPlusPlus0x) + .Case("cxx_static_assert", LangOpts.CPlusPlus0x) + .Case("cxx_trailing_return", LangOpts.CPlusPlus0x) + .Case("cxx_variadic_templates", LangOpts.CPlusPlus0x) .Case("tls", PP.getTargetInfo().isTLSSupported()) .Default(false); } Modified: cfe/trunk/test/Lexer/has_feature_cxx0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/has_feature_cxx0x.cpp?rev=124291&r1=124290&r2=124291&view=diff ============================================================================== --- cfe/trunk/test/Lexer/has_feature_cxx0x.cpp (original) +++ cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Wed Jan 26 09:36:03 2011 @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-0X %s #if __has_feature(cxx_lambdas) -int lambdas(); +int has_lambdas(); #else int no_lambdas(); #endif @@ -32,22 +32,23 @@ #if __has_feature(cxx_auto_type) -int auto_type(); +int has_auto_type(); #else int no_auto_type(); #endif -// CHECK-0X: auto_type +// FIXME: We don't implement "auto" well enough to turn on this feature test +// CHECK-0X: no_auto_type // CHECK-NO-0X: no_auto_type #if __has_feature(cxx_attributes) -int attributes(); +int has_attributes(); #else int no_attributes(); #endif -// CHECK-0X: attributes +// CHECK-0X: has_attributes // CHECK-NO-0X: no_attributes @@ -60,43 +61,41 @@ // CHECK-0X: has_static_assert // CHECK-NO-0X: no_static_assert -// We accept this as an extension. #if __has_feature(cxx_deleted_functions) -int deleted_functions(); +int has_deleted_functions(); #else int no_deleted_functions(); #endif -// CHECK-0X: deleted_functions -// CHECK-NO-0X: deleted_functions +// CHECK-0X: has_deleted_functions +// CHECK-NO-0X: no_deleted_functions #if __has_feature(cxx_rvalue_references) -int rvalue_references(); +int has_rvalue_references(); #else int no_rvalue_references(); #endif -// CHECK-0X: rvalue_references -// CHECK-NO-0X: rvalue_references +// CHECK-0X: has_rvalue_references +// CHECK-NO-0X: no_rvalue_references #if __has_feature(cxx_variadic_templates) -int variadic_templates(); +int has_variadic_templates(); #else int no_variadic_templates(); #endif -// CHECK-0X: variadic_templates -// Note: We allow variadic templates in C++98/03 with a warning. -// CHECK-NO-0X: variadic_templates +// CHECK-0X: has_variadic_templates +// CHECK-NO-0X: no_variadic_templates #if __has_feature(cxx_inline_namespaces) -int inline_namespaces(); +int has_inline_namespaces(); #else int no_inline_namespaces(); #endif -// CHECK-0X: inline_namespaces -// CHECK-NO-0X: inline_namespaces +// CHECK-0X: has_inline_namespaces +// CHECK-NO-0X: no_inline_namespaces From dgregor at apple.com Wed Jan 26 07:39:56 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 15:39:56 -0000 Subject: [cfe-commits] [libcxx] r124293 - /libcxx/trunk/include/__config Message-ID: <20110126153956.59D2B2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 09:39:56 2011 New Revision: 124293 URL: http://llvm.org/viewvc/llvm-project?rev=124293&view=rev Log: Inline namespaces are always available in Clang. Rely on that without testing via __has_feature, since __has_feature for C++0x features no longer evaluates true in C++98/03 mode. Also, eliminate the redundant using directive. Inline namespaces make their members visible in the enclosing namespace automatically. Modified: libcxx/trunk/include/__config Modified: libcxx/trunk/include/__config URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=124293&r1=124292&r2=124293&view=diff ============================================================================== --- libcxx/trunk/include/__config (original) +++ libcxx/trunk/include/__config Wed Jan 26 09:39:56 2011 @@ -148,22 +148,15 @@ #define _LIBCPP_HAS_NO_TRAILING_RETURN #endif -#if __has_feature(cxx_inline_namespaces) +// Inline namespaces are available in Clang regardless of C++ dialect. #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std {inline namespace _LIBCPP_NAMESPACE { #define _LIBCPP_END_NAMESPACE_STD } } #define _STD std::_LIBCPP_NAMESPACE namespace std { -inline namespace _LIBCPP_NAMESPACE { + inline namespace _LIBCPP_NAMESPACE { + } } -using namespace _LIBCPP_NAMESPACE; -} - -#else // __has_feature(cxx_inline_namespaces) -#define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { -#define _LIBCPP_END_NAMESPACE_STD } -#define _STD std -#endif // __has_feature(cxx_inline_namespaces) #if !(__has_feature(cxx_constexpr)) #define _LIBCPP_HAS_NO_CONSTEXPR From dgregor at apple.com Wed Jan 26 08:40:18 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 16:40:18 -0000 Subject: [cfe-commits] r124294 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExprCXX.cpp test/CXX/expr/expr.mptr.oper/p6-0x.cpp Message-ID: <20110126164018.F033C2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 10:40:18 2011 New Revision: 124294 URL: http://llvm.org/viewvc/llvm-project?rev=124294&view=rev Log: Reference qualifiers for *this: implement C++0x [expr.mptr.oper]p6, the restrictions on .* and ->* for ref-qualified pointer-to-member functions. Added: cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp (with props) Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124294&r1=124293&r2=124294&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jan 26 10:40:18 2011 @@ -1581,6 +1581,9 @@ "address non-type template argument cannot be surrounded by parentheses">; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; +def err_pointer_to_member_oper_value_classify: Error< + "pointer-to-member function type %0 can only be called on an " + "%select{rvalue|lvalue}1">; // C++ template specialization def err_template_spec_unknown_kind : Error< Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124294&r1=124293&r2=124294&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 26 10:40:18 2011 @@ -2557,6 +2557,32 @@ QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + // C++0x [expr.mptr.oper]p6: + // In a .* expression whose object expression is an rvalue, the program is + // ill-formed if the second operand is a pointer to member function with + // ref-qualifier &. In a ->* expression or in a .* expression whose object + // expression is an lvalue, the program is ill-formed if the second operand + // is a pointer to member function with ref-qualifier &&. + if (const FunctionProtoType *Proto = Result->getAs()) { + switch (Proto->getRefQualifier()) { + case RQ_None: + // Do nothing + break; + + case RQ_LValue: + if (!isIndirect && !lex->Classify(Context).isLValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 1 << lex->getSourceRange(); + break; + + case RQ_RValue: + if (isIndirect || !lex->Classify(Context).isRValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 0 << lex->getSourceRange(); + break; + } + } + // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its Added: cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp?rev=124294&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp Wed Jan 26 10:40:18 2011 @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +struct X { }; + +template T& lvalue(); +template T&& xvalue(); +template T prvalue(); + +// In a .* expression whose object expression is an rvalue, the +// program is ill-formed if the second operand is a pointer to member +// function with ref-qualifier &. In a ->* expression or in a .* +// expression whose object expression is an lvalue, the program is +// ill-formed if the second operand is a pointer to member function +// with ref-qualifier &&. +void test(X *xp, int (X::*pmf)(int), int (X::*l_pmf)(int) &, + int (X::*r_pmf)(int) &&) { + // No ref-qualifier. + (lvalue().*pmf)(17); + (xvalue().*pmf)(17); + (prvalue().*pmf)(17); + (xp->*pmf)(17); + + // Lvalue ref-qualifier. + (lvalue().*l_pmf)(17); + (xvalue().*l_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &' can only be called on an lvalue}} + (prvalue().*l_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &' can only be called on an lvalue}} + (xp->*l_pmf)(17); + + // Rvalue ref-qualifier. + (lvalue().*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}} + (xvalue().*r_pmf)(17); + (prvalue().*r_pmf)(17); + (xp->*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}} +} Propchange: cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/expr/expr.mptr.oper/p6-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From peter at pcc.me.uk Wed Jan 26 08:48:23 2011 From: peter at pcc.me.uk (Peter Collingbourne) Date: Wed, 26 Jan 2011 16:48:23 +0000 Subject: [cfe-commits] r123959 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/Basic/Attr.td include/clang/Basic/AttrKinds.h lib/Sema/SemaDecl.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp In-Reply-To: <4D3FEC5B.1000304@cs.unipr.it> References: <20110121020837.29CD32A6C12C@llvm.org> <4D3FEC5B.1000304@cs.unipr.it> Message-ID: <20110126164823.GA29571@pcc.me.uk> On Wed, Jan 26, 2011 at 10:41:47AM +0100, Enea Zaffanella wrote: > Il 21/01/2011 03:08, Peter Collingbourne ha scritto: > > Author: pcc > > Date: Thu Jan 20 20:08:36 2011 > > New Revision: 123959 > > > > URL: http://llvm.org/viewvc/llvm-project?rev=123959&view=rev > > Log: > > Generalise support for non-inheritable attributes > [...] > > The patch introduces a new Attr subclass, InheritableAttr, from > > which all inheritable attributes derive. Non-inheritable attributes > > simply derive from Attr. > [...] > > - bool isInherited() const { return Inherited; } > > Why removing this query method from the base class Attr? > > May I suggest to make it virtual (with a default implementation > returning false) and then override it in InheritableAttr? It seems best for efficiency reasons to move isInherited to Attr while leaving setInherited in InheritableAttr. I'll do it. Thanks, -- Peter From scshunt at csclub.uwaterloo.ca Wed Jan 26 08:51:01 2011 From: scshunt at csclub.uwaterloo.ca (Sean Hunt) Date: Wed, 26 Jan 2011 11:51:01 -0500 Subject: [cfe-commits] [libcxx] r124293 - /libcxx/trunk/include/__config In-Reply-To: <20110126153956.59D2B2A6C12C@llvm.org> References: <20110126153956.59D2B2A6C12C@llvm.org> Message-ID: <4D4050F5.1000202@csclub.uwaterloo.ca> On 11-01-26 10:39 AM, Douglas Gregor wrote: > Author: dgregor > Date: Wed Jan 26 09:39:56 2011 > New Revision: 124293 > > URL: http://llvm.org/viewvc/llvm-project?rev=124293&view=rev > Log: > Inline namespaces are always available in Clang. Rely on that without > testing via __has_feature, since __has_feature for C++0x features no > longer evaluates true in C++98/03 mode. > > Also, eliminate the redundant using directive. Inline namespaces make > their members visible in the enclosing namespace automatically. I think if we always provide inline namespaces, their __has_feature should be true irrespective of C++0x mode. Sean From dgregor at apple.com Wed Jan 26 08:50:54 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 16:50:54 -0000 Subject: [cfe-commits] r124295 - in /cfe/trunk: lib/Parse/ParseTentative.cpp lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp Message-ID: <20110126165054.3E2A32A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 10:50:54 2011 New Revision: 124295 URL: http://llvm.org/viewvc/llvm-project?rev=124295&view=rev Log: Rvalue references for *this: tentative parsing and template argument deduction. Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp (with props) Modified: cfe/trunk/lib/Parse/ParseTentative.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Modified: cfe/trunk/lib/Parse/ParseTentative.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=124295&r1=124294&r2=124295&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTentative.cpp (original) +++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed Jan 26 10:50:54 2011 @@ -1222,6 +1222,10 @@ Tok.is(tok::kw_restrict) ) ConsumeToken(); + // ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) + ConsumeToken(); + // exception-specification if (Tok.is(tok::kw_throw)) { ConsumeToken(); Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=124295&r1=124294&r2=124295&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jan 26 10:50:54 2011 @@ -1154,11 +1154,11 @@ const FunctionProtoType *FunctionProtoParam = cast(Param); - if (FunctionProtoParam->getTypeQuals() != - FunctionProtoArg->getTypeQuals()) - return Sema::TDK_NonDeducedMismatch; - - if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) + if (FunctionProtoParam->getTypeQuals() + != FunctionProtoArg->getTypeQuals() || + FunctionProtoParam->getRefQualifier() + != FunctionProtoArg->getRefQualifier() || + FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; // Check return types. Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp?rev=124295&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp Wed Jan 26 10:50:54 2011 @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// Deductions specific to C++0x. + +template +struct member_pointer_kind { + static const unsigned value = 0; +}; + +template +struct member_pointer_kind { + static const unsigned value = 1; +}; + +template +struct member_pointer_kind { + static const unsigned value = 2; +}; + +template +struct member_pointer_kind { + static const unsigned value = 3; +}; + +template +struct member_pointer_kind { + static const unsigned value = 4; +}; + +template +struct member_pointer_kind { + static const unsigned value = 5; +}; + +template +struct member_pointer_kind { + static const unsigned value = 6; +}; + +struct X { }; + +static_assert(member_pointer_kind::value == 1, ""); +static_assert(member_pointer_kind::value == 2, ""); +static_assert(member_pointer_kind::value == 3, ""); +static_assert(member_pointer_kind::value == 4, ""); +static_assert(member_pointer_kind::value == 5, ""); +static_assert(member_pointer_kind::value == 6, ""); Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Wed Jan 26 09:03:25 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 09:03:25 -0800 Subject: [cfe-commits] [libcxx] r124293 - /libcxx/trunk/include/__config In-Reply-To: <4D4050F5.1000202@csclub.uwaterloo.ca> References: <20110126153956.59D2B2A6C12C@llvm.org> <4D4050F5.1000202@csclub.uwaterloo.ca> Message-ID: <1CD132E7-F6E3-4C3D-A739-F17AADBEFD5D@apple.com> On Jan 26, 2011, at 8:51 AM, Sean Hunt wrote: > On 11-01-26 10:39 AM, Douglas Gregor wrote: >> Author: dgregor >> Date: Wed Jan 26 09:39:56 2011 >> New Revision: 124293 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=124293&view=rev >> Log: >> Inline namespaces are always available in Clang. Rely on that without >> testing via __has_feature, since __has_feature for C++0x features no >> longer evaluates true in C++98/03 mode. >> >> Also, eliminate the redundant using directive. Inline namespaces make >> their members visible in the enclosing namespace automatically. > > I think if we always provide inline namespaces, their __has_feature > should be true irrespective of C++0x mode. We always provide rvalue references, variadic templates, and a number of other features, but complain about them with extension warnings. However, we shouldn't advertise a C++0x feature to programs unless we're actually in C++0x mode, since that entices programmers into writing non-conformant code. - Doug From dgregor at apple.com Wed Jan 26 09:36:29 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 17:36:29 -0000 Subject: [cfe-commits] r124296 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/ItaniumMangle.cpp test/CodeGenCXX/mangle-ref-qualifiers.cpp Message-ID: <20110126173629.2F85D2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 11:36:28 2011 New Revision: 124296 URL: http://llvm.org/viewvc/llvm-project?rev=124296&view=rev Log: Rvalue references for *this: add name mangling for ref-qualifiers, using rules that I just made up this morning. This encoding has now been proposed to the Itanium C++ ABI group for inclusion, but of course it's still possible that the mangling will change. Added: cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp (with props) Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/lib/AST/ItaniumMangle.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=124296&r1=124295&r2=124296&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Jan 26 11:36:28 2011 @@ -1096,6 +1096,20 @@ return getType()->getAs()->getTypeQuals(); } + /// \brief Retrieve the ref-qualifier associated with this method. + /// + /// In the following example, \c f() has an lvalue ref-qualifier, \c g() + /// has an rvalue ref-qualifier, and \c h() has no ref-qualifier. + /// \code + /// struct X { + /// void f() &; + /// void g() &&; + /// void h(); + /// }; + RefQualifierKind getRefQualifier() const { + return getType()->getAs()->getRefQualifier(); + } + bool hasInlineBody() const; // Implement isa/cast/dyncast/etc. Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=124296&r1=124295&r2=124296&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Jan 26 11:36:28 2011 @@ -228,6 +228,7 @@ void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); + void mangleRefQualifier(RefQualifierKind RefQualifier); void mangleObjCMethodName(const ObjCMethodDecl *MD); @@ -817,13 +818,17 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, const DeclContext *DC, bool NoFunction) { - // ::= N [] E - // ::= N [] E + // + // ::= N [] [] E + // ::= N [] [] + // E Out << 'N'; - if (const CXXMethodDecl *Method = dyn_cast(ND)) + if (const CXXMethodDecl *Method = dyn_cast(ND)) { mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); - + mangleRefQualifier(Method->getRefQualifier()); + } + // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { @@ -1162,6 +1167,24 @@ // FIXME: For now, just drop all extension qualifiers on the floor. } +void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { + // ::= R # lvalue reference + // ::= O # rvalue-reference + // Proposal to Itanium C++ ABI list on 1/26/11 + switch (RefQualifier) { + case RQ_None: + break; + + case RQ_LValue: + Out << 'R'; + break; + + case RQ_RValue: + Out << 'O'; + break; + } +} + void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { llvm::SmallString<64> Buffer; Context.mangleObjCMethodName(MD, Buffer); @@ -1364,6 +1387,7 @@ QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast(PointeeType)) { mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals())); + mangleRefQualifier(FPT->getRefQualifier()); mangleType(FPT); // Itanium C++ ABI 5.1.8: Added: cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp?rev=124296&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp (added) +++ cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp Wed Jan 26 11:36:28 2011 @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +struct X { + int f() &; + int g() &&; + int h() const &&; +}; + +// CHECK: define i32 @_ZNR1X1fEv +int X::f() & { return 0; } +// CHECK: define i32 @_ZNO1X1gEv +int X::g() && { return 0; } +// CHECK: define i32 @_ZNKO1X1hEv +int X::h() const && { return 0; } + +// CHECK: define void @_Z1fM1XRFivEMS_OFivEMS_KOFivE +void f(int (X::*)() &, int (X::*)() &&, int (X::*)() const&&) { } Propchange: cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CodeGenCXX/mangle-ref-qualifiers.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Wed Jan 26 09:47:49 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 17:47:49 -0000 Subject: [cfe-commits] r124297 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/CXX/over/over.load/p2-0x.cpp Message-ID: <20110126174749.4C9FD2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 11:47:49 2011 New Revision: 124297 URL: http://llvm.org/viewvc/llvm-project?rev=124297&view=rev Log: Rvalue references for *this: allow functions to be overloaded based on the presence and form of a ref-qualifier. Note that we do *not* yet implement the restriction in C++0x [over.load]p2 that requires either all non-static functions with a given parameter-type-list to have a ref-qualifier or none of them to have a ref-qualifier. Added: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp (with props) Modified: cfe/trunk/lib/Sema/SemaOverload.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124297&r1=124296&r2=124297&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 11:47:49 2011 @@ -681,7 +681,7 @@ return true; // If the function is a class member, its signature includes the - // cv-qualifiers (if any) on the function itself. + // cv-qualifiers (if any) and ref-qualifier (if any) on the function itself. // // As part of this, also check whether one of the member functions // is static, in which case they are not overloads (C++ @@ -692,7 +692,8 @@ CXXMethodDecl* NewMethod = dyn_cast(New); if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic() && - OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) + (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() || + OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) return true; // The signatures match; this is not an overload. Added: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.load/p2-0x.cpp?rev=124297&view=auto ============================================================================== --- cfe/trunk/test/CXX/over/over.load/p2-0x.cpp (added) +++ cfe/trunk/test/CXX/over/over.load/p2-0x.cpp Wed Jan 26 11:47:49 2011 @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// Member function declarations with the same name and the same +// parameter-type-list as well as mem- ber function template +// declarations with the same name, the same parameter-type-list, and +// the same template parameter lists cannot be overloaded if any of +// them, but not all, have a ref-qualifier (8.3.5). + +class Y { + void h() &; + void h() const &; + void h() &&; + void i() &; + void i() const; // FIXME: expected an error here! + + template void f(T*) &; + template void f(T*) &&; + + template void g(T*) &; + template void g(T*); // FIXME: expected an error here +}; Propchange: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From peter at pcc.me.uk Wed Jan 26 10:07:07 2011 From: peter at pcc.me.uk (Peter Collingbourne) Date: Wed, 26 Jan 2011 18:07:07 -0000 Subject: [cfe-commits] r124298 - /cfe/trunk/include/clang/AST/Attr.h Message-ID: <20110126180707.47FDA2A6C12C@llvm.org> Author: pcc Date: Wed Jan 26 12:07:07 2011 New Revision: 124298 URL: http://llvm.org/viewvc/llvm-project?rev=124298&view=rev Log: Remove Attr::isMerged; it is not used any more and redundant with InheritableAttr Modified: cfe/trunk/include/clang/AST/Attr.h Modified: cfe/trunk/include/clang/AST/Attr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=124298&r1=124297&r2=124298&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Attr.h (original) +++ cfe/trunk/include/clang/AST/Attr.h Wed Jan 26 12:07:07 2011 @@ -89,10 +89,6 @@ public: - /// \brief Whether this attribute should be merged to new - /// declarations. - virtual bool isMerged() const { return true; } - attr::Kind getKind() const { return static_cast(AttrKind); } From peter at pcc.me.uk Wed Jan 26 10:07:13 2011 From: peter at pcc.me.uk (Peter Collingbourne) Date: Wed, 26 Jan 2011 18:07:13 -0000 Subject: [cfe-commits] r124299 - /cfe/trunk/include/clang/AST/Attr.h Message-ID: <20110126180713.9C1362A6C12D@llvm.org> Author: pcc Date: Wed Jan 26 12:07:13 2011 New Revision: 124299 URL: http://llvm.org/viewvc/llvm-project?rev=124299&view=rev Log: Move InheritableAttr::isInherited to Attr Modified: cfe/trunk/include/clang/AST/Attr.h Modified: cfe/trunk/include/clang/AST/Attr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=124299&r1=124298&r2=124299&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Attr.h (original) +++ cfe/trunk/include/clang/AST/Attr.h Wed Jan 26 12:07:13 2011 @@ -96,6 +96,8 @@ SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } + bool isInherited() const { return Inherited; } + // Clone this attribute. virtual Attr* clone(ASTContext &C) const = 0; @@ -109,7 +111,6 @@ : Attr(AK, L) {} public: - bool isInherited() const { return Inherited; } void setInherited(bool I) { Inherited = I; } // Implement isa/cast/dyncast/etc. From rjmccall at apple.com Wed Jan 26 11:15:40 2011 From: rjmccall at apple.com (John McCall) Date: Wed, 26 Jan 2011 19:15:40 -0000 Subject: [cfe-commits] r124309 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGTemporaries.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/exceptions.cpp test/CodeGenCXX/temporaries.cpp Message-ID: <20110126191540.29C8F2A6C12C@llvm.org> Author: rjmccall Date: Wed Jan 26 13:15:39 2011 New Revision: 124309 URL: http://llvm.org/viewvc/llvm-project?rev=124309&view=rev Log: Fix some obvious bugs in the conditional-cleanup code and then make the dtor cleanup use it. Modified: cfe/trunk/lib/CodeGen/CGException.cpp cfe/trunk/lib/CodeGen/CGTemporaries.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h cfe/trunk/test/CodeGenCXX/exceptions.cpp cfe/trunk/test/CodeGenCXX/temporaries.cpp Modified: cfe/trunk/lib/CodeGen/CGException.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124309&r1=124308&r2=124309&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGException.cpp (original) +++ cfe/trunk/lib/CodeGen/CGException.cpp Wed Jan 26 13:15:39 2011 @@ -179,8 +179,7 @@ // Initialize it to false at a site that's guaranteed to be run // before each evaluation. llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); - new llvm::StoreInst(Builder.getFalse(), run, - block->getFirstNonPHIOrDbg()); + new llvm::StoreInst(Builder.getFalse(), run, &block->back()); // Initialize it to true at the current location. Builder.CreateStore(Builder.getTrue(), run); Modified: cfe/trunk/lib/CodeGen/CGTemporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGTemporaries.cpp?rev=124309&r1=124308&r2=124309&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGTemporaries.cpp (original) +++ cfe/trunk/lib/CodeGen/CGTemporaries.cpp Wed Jan 26 13:15:39 2011 @@ -16,39 +16,11 @@ using namespace CodeGen; namespace { - struct DestroyTemporary : EHScopeStack::Cleanup { - const CXXTemporary *Temporary; - llvm::Value *Addr; - llvm::Value *CondPtr; - - DestroyTemporary(const CXXTemporary *Temporary, llvm::Value *Addr, - llvm::Value *CondPtr) - : Temporary(Temporary), Addr(Addr), CondPtr(CondPtr) {} - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - llvm::BasicBlock *CondEnd = 0; - - // If this is a conditional temporary, we need to check the condition - // boolean and only call the destructor if it's true. - if (CondPtr) { - llvm::BasicBlock *CondBlock = - CGF.createBasicBlock("temp.cond-dtor.call"); - CondEnd = CGF.createBasicBlock("temp.cond-dtor.cont"); - - llvm::Value *Cond = CGF.Builder.CreateLoad(CondPtr); - CGF.Builder.CreateCondBr(Cond, CondBlock, CondEnd); - CGF.EmitBlock(CondBlock); - } - - CGF.EmitCXXDestructorCall(Temporary->getDestructor(), - Dtor_Complete, /*ForVirtualBase=*/false, - Addr); - - if (CondPtr) { - // Reset the condition to false. - CGF.Builder.CreateStore(CGF.Builder.getFalse(), CondPtr); - CGF.EmitBlock(CondEnd); - } + struct DestroyTemporary { + static void Emit(CodeGenFunction &CGF, bool forEH, + const CXXDestructorDecl *dtor, llvm::Value *addr) { + CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false, + addr); } }; } @@ -56,23 +28,9 @@ /// Emits all the code to cause the given temporary to be cleaned up. void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr) { - llvm::AllocaInst *CondPtr = 0; - - // Check if temporaries need to be conditional. If so, we'll create a - // condition boolean, initialize it to 0 and - if (isInConditionalBranch()) { - CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); - - // Initialize it to false. This initialization takes place right after - // the alloca insert point. - InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); - - // Now set it to true. - Builder.CreateStore(Builder.getTrue(), CondPtr); - } - - EHStack.pushCleanup(NormalAndEHCleanup, - Temporary, Ptr, CondPtr); + pushFullExprCleanup(NormalAndEHCleanup, + Temporary->getDestructor(), + Ptr); } RValue Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124309&r1=124308&r2=124309&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Jan 26 13:15:39 2011 @@ -214,6 +214,7 @@ template class UnconditionalCleanup2 : public Cleanup { A0 a0; A1 a1; + public: UnconditionalCleanup2(A0 a0, A1 a1) : a0(a0), a1(a1) {} void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { T::Emit(CGF, IsForEHCleanup, a0, a1); @@ -226,17 +227,18 @@ class ConditionalCleanup2 : public ConditionalCleanup { typedef typename SavedValueInCond::saved_type A0_saved; typedef typename SavedValueInCond::saved_type A1_saved; - A0_saved a0; A1_saved a1; + A0_saved a0_saved; + A1_saved a1_saved; void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) { - A0 a0 = SavedValueInCond::restore(CGF, a0); - A1 a1 = SavedValueInCond::restore(CGF, a1); + A0 a0 = SavedValueInCond::restore(CGF, a0_saved); + A1 a1 = SavedValueInCond::restore(CGF, a1_saved); T::Emit(CGF, IsForEHCleanup, a0, a1); } public: ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1) - : ConditionalCleanup(cond), a0(a0), a1(a1) {} + : ConditionalCleanup(cond), a0_saved(a0), a1_saved(a1) {} }; private: Modified: cfe/trunk/test/CodeGenCXX/exceptions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/exceptions.cpp?rev=124309&r1=124308&r2=124309&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/exceptions.cpp (original) +++ cfe/trunk/test/CodeGenCXX/exceptions.cpp Wed Jan 26 13:15:39 2011 @@ -196,10 +196,10 @@ // CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1 // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 8 // CHECK: [[TMPACTIVE:%.*]] = alloca i1 - // CHECK-NEXT: store i1 false, i1* [[TMPACTIVE]] // CHECK-NEXT: store i1 false, i1* [[CLEANUPACTIVE]] // CHECK: [[COND:%.*]] = trunc i8 {{.*}} to i1 + // CHECK-NEXT: store i1 false, i1* [[TMPACTIVE]] // CHECK-NEXT: br i1 [[COND]] return (cond ? Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=124309&r1=124308&r2=124309&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original) +++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Wed Jan 26 13:15:39 2011 @@ -502,9 +502,9 @@ // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: [[LCONS:%.*]] = alloca i1 // CHECK-NEXT: [[RCONS:%.*]] = alloca i1 + // CHECK: store i1 false, i1* [[LCONS]] // CHECK-NEXT: store i1 false, i1* [[RCONS]] - // CHECK-NEXT: store i1 false, i1* [[LCONS]] - // CHECK: br i1 + // CHECK-NEXT: br i1 // CHECK: call void @_ZN6PR86231AC1Ei([[A]]* [[TMP]], i32 2) // CHECK-NEXT: store i1 true, i1* [[LCONS]] // CHECK-NEXT: br label @@ -514,12 +514,10 @@ // CHECK: load i1* [[RCONS]] // CHECK-NEXT: br i1 // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) - // CHECK-NEXT: store i1 false, i1* [[RCONS]] // CHECK-NEXT: br label // CHECK: load i1* [[LCONS]] // CHECK-NEXT: br i1 // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) - // CHECK-NEXT: store i1 false, i1* [[LCONS]] // CHECK-NEXT: br label // CHECK: ret void b ? A(2) : A(3); From rjmccall at apple.com Wed Jan 26 11:21:14 2011 From: rjmccall at apple.com (John McCall) Date: Wed, 26 Jan 2011 19:21:14 -0000 Subject: [cfe-commits] r124310 - /cfe/trunk/lib/CodeGen/CGExpr.cpp Message-ID: <20110126192114.1A16C2A6C12C@llvm.org> Author: rjmccall Date: Wed Jan 26 13:21:13 2011 New Revision: 124310 URL: http://llvm.org/viewvc/llvm-project?rev=124310&view=rev Log: Un-nest the meat of this function. Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=124310&r1=124309&r2=124310&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Jan 26 13:21:13 2011 @@ -1682,67 +1682,66 @@ LValue CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator *E) { - if (E->isGLValue()) { - if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) { - Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS(); - if (Live) - return EmitLValue(Live); - } - - llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); - llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); - llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); - - ConditionalEvaluation eval(*this); - - if (E->getLHS()) - EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - else { - Expr *save = E->getSAVE(); - assert(save && "VisitConditionalOperator - save is null"); - // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] - LValue SaveVal = EmitLValue(save); - ConditionalSaveLValueExprs[save] = SaveVal; - EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - } - - // Any temporaries created here are conditional. - EmitBlock(LHSBlock); - eval.begin(*this); - LValue LHS = EmitLValue(E->getTrueExpr()); - eval.end(*this); - - if (!LHS.isSimple()) - return EmitUnsupportedLValue(E, "conditional operator"); - - LHSBlock = Builder.GetInsertBlock(); - Builder.CreateBr(ContBlock); - - // Any temporaries created here are conditional. - EmitBlock(RHSBlock); - eval.begin(*this); - LValue RHS = EmitLValue(E->getRHS()); - eval.end(*this); - if (!RHS.isSimple()) - return EmitUnsupportedLValue(E, "conditional operator"); - RHSBlock = Builder.GetInsertBlock(); - - EmitBlock(ContBlock); - - llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(), - "cond-lvalue"); - phi->reserveOperandSpace(2); - phi->addIncoming(LHS.getAddress(), LHSBlock); - phi->addIncoming(RHS.getAddress(), RHSBlock); - return MakeAddrLValue(phi, E->getType()); + if (!E->isGLValue()) { + // ?: here should be an aggregate. + assert((hasAggregateLLVMType(E->getType()) && + !E->getType()->isAnyComplexType()) && + "Unexpected conditional operator!"); + return EmitAggExprToLValue(E); } - - // ?: here should be an aggregate. - assert((hasAggregateLLVMType(E->getType()) && - !E->getType()->isAnyComplexType()) && - "Unexpected conditional operator!"); - return EmitAggExprToLValue(E); + if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) { + Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS(); + if (Live) + return EmitLValue(Live); + } + + llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); + llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); + llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); + + ConditionalEvaluation eval(*this); + + if (E->getLHS()) + EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); + else { + Expr *save = E->getSAVE(); + assert(save && "VisitConditionalOperator - save is null"); + // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] + LValue SaveVal = EmitLValue(save); + ConditionalSaveLValueExprs[save] = SaveVal; + EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); + } + + // Any temporaries created here are conditional. + EmitBlock(LHSBlock); + eval.begin(*this); + LValue LHS = EmitLValue(E->getTrueExpr()); + eval.end(*this); + + if (!LHS.isSimple()) + return EmitUnsupportedLValue(E, "conditional operator"); + + LHSBlock = Builder.GetInsertBlock(); + Builder.CreateBr(ContBlock); + + // Any temporaries created here are conditional. + EmitBlock(RHSBlock); + eval.begin(*this); + LValue RHS = EmitLValue(E->getRHS()); + eval.end(*this); + if (!RHS.isSimple()) + return EmitUnsupportedLValue(E, "conditional operator"); + RHSBlock = Builder.GetInsertBlock(); + + EmitBlock(ContBlock); + + llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(), + "cond-lvalue"); + phi->reserveOperandSpace(2); + phi->addIncoming(LHS.getAddress(), LHSBlock); + phi->addIncoming(RHS.getAddress(), RHSBlock); + return MakeAddrLValue(phi, E->getType()); } /// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast. From dgregor at apple.com Wed Jan 26 11:30:29 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 19:30:29 -0000 Subject: [cfe-commits] r124311 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Sema/Overload.h include/clang/Sema/Sema.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Message-ID: <20110126193029.5F6C12A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 13:30:28 2011 New Revision: 124311 URL: http://llvm.org/viewvc/llvm-project?rev=124311&view=rev Log: Rvalue references for *this: implement the implicit conversion rules for the implicit object argument to a non-static member function with a ref-qualifier (C++0x [over.match.funcs]p4). Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp (with props) Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaOverload.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=124311&r1=124310&r2=124311&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Wed Jan 26 13:30:28 2011 @@ -268,6 +268,12 @@ bool isPRValue() const { return Kind >= CL_Function; } bool isRValue() const { return Kind >= CL_XValue; } bool isModifiable() const { return getModifiable() == CM_Modifiable; } + + /// \brief Create a simple, modifiably lvalue + static Classification makeSimpleLValue() { + return Classification(CL_LValue, CM_Modifiable); + } + }; /// \brief Classify - Classify this expression according to the C++0x /// expression taxonomy. Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124311&r1=124310&r2=124311&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 26 13:30:28 2011 @@ -294,7 +294,9 @@ no_conversion, unrelated_class, suppressed_user, - bad_qualifiers + bad_qualifiers, + lvalue_ref_to_rvalue, + rvalue_ref_to_lvalue }; // This can be null, e.g. for implicit object arguments. Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124311&r1=124310&r2=124311&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 26 13:30:28 2011 @@ -20,7 +20,7 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/DeclSpec.h" -#include "clang/AST/OperationKinds.h" +#include "clang/AST/Expr.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/TypeLoc.h" @@ -1080,12 +1080,14 @@ bool SuppressUserConversions = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -1094,6 +1096,7 @@ CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -1117,7 +1120,7 @@ DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - QualType ObjectTy, Expr **Args, unsigned NumArgs, + Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124311&r1=124310&r2=124311&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 13:30:28 2011 @@ -2345,9 +2345,10 @@ // and std::reference_wrapper when dealing with references to functions. // Proposed wording changes submitted to CWG for consideration. // - // FIXME: Rvalue references. We don't know if we're dealing with the - // implicit object parameter, or if the member function in this case has a - // ref qualifier. (Of course, we don't have ref qualifiers yet.) + // Note: neither of these conditions will evalute true for the implicit + // object parameter, because we don't set either BindsToRvalue or + // BindsToFunctionLvalue when computing the conversion sequence for the + // implicit object parameter. return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && SCS2.IsLvalueReference) || (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && @@ -3182,6 +3183,7 @@ /// expression @p From. static ImplicitConversionSequence TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, + Expr::Classification FromClassification, CXXMethodDecl *Method, CXXRecordDecl *ActingContext) { QualType ClassType = S.Context.getTypeDeclType(ActingContext); @@ -3197,22 +3199,35 @@ // We need to have an object of class type. QualType FromType = OrigFromType; - if (const PointerType *PT = FromType->getAs()) + if (const PointerType *PT = FromType->getAs()) { FromType = PT->getPointeeType(); + // When we had a pointer, it's implicitly dereferenced, so we + // better have an lvalue. + assert(FromClassification.isLValue()); + } + assert(FromType->isRecordType()); - // The implicit object parameter is has the type "reference to cv X", - // where X is the class of which the function is a member - // (C++ [over.match.funcs]p4). However, when finding an implicit - // conversion sequence for the argument, we are not allowed to - // create temporaries or perform user-defined conversions + // C++0x [over.match.funcs]p4: + // For non-static member functions, the type of the implicit object + // parameter is + // + // — "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // — "rvalue reference to cv X" for functions declared with the && + // ref-qualifier + // + // where X is the class of which the function is a member and cv is the + // cv-qualification on the member function declaration. + // + // However, when finding an implicit conversion sequence for the argument, we + // are not allowed to create temporaries or perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to // non-constant references. - // First check the qualifiers. We don't care about lvalue-vs-rvalue - // with the implicit object parameter (C++ [over.match.funcs]p5). + // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && @@ -3236,6 +3251,31 @@ return ICS; } + // Check the ref-qualifier. + switch (Method->getRefQualifier()) { + case RQ_None: + // Do nothing; we don't care about lvalueness or rvalueness. + break; + + case RQ_LValue: + if (!FromClassification.isLValue() && Quals != Qualifiers::Const) { + // non-const lvalue reference cannot bind to an rvalue + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + + case RQ_RValue: + if (!FromClassification.isRValue()) { + // rvalue reference cannot bind to an lvalue + ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + } + // Success. Mark this as a reference binding. ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); @@ -3244,10 +3284,10 @@ ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - - // FIXME: Rvalue references. - ICS.Standard.IsLvalueReference = true; + ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; ICS.Standard.BindsToFunctionLvalue = false; + + // Note: we intentionally don't set this; see isBetterReferenceBindingKind(). ICS.Standard.BindsToRvalue = false; return ICS; } @@ -3264,19 +3304,22 @@ QualType ImplicitParamRecordType = Method->getThisType(Context)->getAs()->getPointeeType(); + Expr::Classification FromClassification; if (const PointerType *PT = From->getType()->getAs()) { FromRecordType = PT->getPointeeType(); DestType = Method->getThisType(Context); + FromClassification = Expr::Classification::makeSimpleLValue(); } else { FromRecordType = From->getType(); DestType = ImplicitParamRecordType; + FromClassification = From->Classify(Context); } // Note that we always use the true parent context when performing // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(*this, From->getType(), Method, - Method->getParent()); + = TryObjectArgumentInitialization(*this, From->getType(), FromClassification, + Method, Method->getParent()); if (ICS.isBad()) { if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) { Qualifiers FromQs = FromRecordType.getQualifiers(); @@ -3549,7 +3592,7 @@ = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); assert(!Function->getDescribedFunctionTemplate() && - "Use AddTemplateOverloadCandidate for function templates"); + "Use AddTemp∫lateOverloadCandidate for function templates"); if (CXXMethodDecl *Method = dyn_cast(Function)) { if (!isa(Method)) { @@ -3561,7 +3604,8 @@ // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), - QualType(), Args, NumArgs, CandidateSet, + QualType(), Expr::Classification::makeSimpleLValue(), + Args, NumArgs, CandidateSet, SuppressUserConversions); return; } @@ -3662,7 +3706,8 @@ if (isa(FD) && !cast(FD)->isStatic()) AddMethodCandidate(cast(FD), F.getPair(), cast(FD)->getParent(), - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, @@ -3674,7 +3719,9 @@ AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), + Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else @@ -3690,6 +3737,7 @@ /// method) as a method candidate to the given overload set. void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3704,12 +3752,12 @@ "Expected a member function template"); AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ 0, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } else { AddMethodCandidate(cast(Decl), FoundDecl, ActingContext, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } } @@ -3724,6 +3772,7 @@ void Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3782,8 +3831,8 @@ // Determine the implicit conversion sequence for the object // parameter. Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, ObjectType, Method, - ActingContext); + = TryObjectArgumentInitialization(*this, ObjectType, ObjectClassification, + Method, ActingContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3827,6 +3876,7 @@ CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3867,8 +3917,8 @@ assert(isa(Specialization) && "Specialization is not a member function?"); AddMethodCandidate(cast(Specialization), FoundDecl, - ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions); + ActingContext, ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, SuppressUserConversions); } /// \brief Add a C++ function template specialization as a candidate @@ -3968,8 +4018,9 @@ = cast(ImplicitParamType->getAs()->getDecl()); Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, From->getType(), Conversion, - ConversionContext); + = TryObjectArgumentInitialization(*this, From->getType(), + From->Classify(Context), + Conversion, ConversionContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; @@ -4113,7 +4164,7 @@ DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - QualType ObjectType, + Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { if (!CandidateSet.isNewCandidate(Conversion)) @@ -4136,8 +4187,9 @@ // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(*this, ObjectType, Conversion, - ActingContext); + = TryObjectArgumentInitialization(*this, Object->getType(), + Object->Classify(Context), + Conversion, ActingContext); if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -4249,7 +4301,8 @@ Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args + 1, NumArgs - 1, CandidateSet, + Args[0]->Classify(Context), Args + 1, NumArgs - 1, + CandidateSet, /* SuppressUserConversions = */ false); } } @@ -4901,8 +4954,8 @@ // T& operator*(T*); // // C++ [over.built]p7: - // For every function type T, there exist candidate operator - // functions of the form + // For every function type T that does not have cv-qualifiers or a + // ref-qualifier, there exist candidate operator functions of the form // T& operator*(T*); void addUnaryStarPointerOverloads() { for (BuiltinCandidateTypeSet::iterator @@ -4914,6 +4967,10 @@ if (!PointeeTy->isObjectType() && !PointeeTy->isFunctionType()) continue; + if (const FunctionProtoType *Proto =PointeeTy->getAs()) + if (Proto->getTypeQuals() || Proto->getRefQualifier()) + continue; + S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), &ParamTy, Args, 1, CandidateSet); } @@ -7950,6 +8007,9 @@ Qualifier = UnresExpr->getQualifier(); QualType ObjectType = UnresExpr->getBaseType(); + Expr::Classification ObjectClassification + = UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue() + : UnresExpr->getBase()->Classify(Context); // Add overload candidates OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc()); @@ -7969,6 +8029,7 @@ if (isa(Func)) Func = cast(Func)->getTargetDecl(); + // Microsoft supports direct constructor calls. if (getLangOptions().Microsoft && isa(Func)) { AddOverloadCandidate(cast(Func), I.getPair(), Args, NumArgs, @@ -7980,13 +8041,14 @@ continue; AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, - Args, NumArgs, - CandidateSet, /*SuppressUserConversions=*/false); + ObjectClassification, + Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast(Func), I.getPair(), ActingDC, TemplateArgs, - ObjectType, Args, NumArgs, - CandidateSet, + ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } } @@ -8113,7 +8175,7 @@ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object->getType(), - Args, NumArgs, CandidateSet, + Object->Classify(Context), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -8158,8 +8220,7 @@ if (const FunctionProtoType *Proto = ConvType->getAs()) AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object->getType(), Args, NumArgs, - CandidateSet); + Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. @@ -8369,8 +8430,8 @@ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet, - /*SuppressUserConversions=*/false); + AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), + 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } // Perform overload resolution. Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp?rev=124311&view=auto ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp (added) +++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Wed Jan 26 13:30:28 2011 @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template T &lvalue(); +template T &&xvalue(); +template T prvalue(); + +struct X0 { + int &f() &; + float &f() &&; + + template int &ft(T) &; + template float &ft(T) &&; + + typedef int &(*func_int_ref)(); + typedef float &(*func_float_ref)(); + + operator func_int_ref() &; + operator func_float_ref() &&; + + void g(); + + int &operator+(const X0&) &; + float &operator+(const X0&) &&; + + template int &operator+(const T&) &; + template float &operator+(const T&) &&; + + int &h() const&; + float &h() &&; +}; + +void X0::g() { + int &ir1 = f(); + int &ir2 = X0::f(); +} + +void test_ref_qualifier_binding() { + int &ir1 = lvalue().f(); + float &fr1 = xvalue().f(); + float &fr2 = prvalue().f(); + int &ir2 = lvalue().ft(1); + float &fr3 = xvalue().ft(2); + float &fr4 = prvalue().ft(3); +} + +void test_ref_qualifier_binding_with_surrogates() { + int &ir1 = lvalue()(); + float &fr1 = xvalue()(); + float &fr2 = prvalue()(); +} + +void test_ref_qualifier_binding_operators() { + int &ir1 = lvalue() + prvalue(); + float &fr1 = xvalue() + prvalue(); + float &fr2 = prvalue() + prvalue(); + int &ir2 = lvalue() + 1; + float &fr3 = xvalue() + 2; + float &fr4 = prvalue() + 3; +} + +void test_ref_qualifier_overloading() { + int &ir1 = lvalue().h(); + float &fr1 = xvalue().h(); + float &fr2 = prvalue().h(); +} Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Wed Jan 26 11:41:18 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 19:41:18 -0000 Subject: [cfe-commits] r124313 - in /cfe/trunk: include/clang/Sema/Overload.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Message-ID: <20110126194118.55F472A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 13:41:18 2011 New Revision: 124313 URL: http://llvm.org/viewvc/llvm-project?rev=124313&view=rev Log: Rvalue references for *this: explicitly keep track of whether a reference binding is for the implicit object parameter of a member function with a ref-qualifier. My previous comment, that we didn't need to track this explicitly, was wrong: we do in fact get rvalue-references-prefer-rvalues overloading with ref-qualifiers. Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124313&r1=124312&r2=124313&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 26 13:41:18 2011 @@ -157,6 +157,10 @@ /// \brief Whether we're binding to an rvalue. unsigned BindsToRvalue : 1; + /// \brief Whether this binds an implicit object argument to a + /// non-static member function without a ref-qualifier. + unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124313&r1=124312&r2=124313&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 13:41:18 2011 @@ -173,6 +173,7 @@ IsLvalueReference = true; BindsToFunctionLvalue = false; BindsToRvalue = false; + BindsImplicitObjectArgumentWithoutRefQualifier = false; CopyConstructor = 0; } @@ -2344,11 +2345,10 @@ // time of this writing) break the standard definition of std::forward // and std::reference_wrapper when dealing with references to functions. // Proposed wording changes submitted to CWG for consideration. - // - // Note: neither of these conditions will evalute true for the implicit - // object parameter, because we don't set either BindsToRvalue or - // BindsToFunctionLvalue when computing the conversion sequence for the - // implicit object parameter. + if (SCS1.BindsImplicitObjectArgumentWithoutRefQualifier || + SCS2.BindsImplicitObjectArgumentWithoutRefQualifier) + return false; + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && SCS2.IsLvalueReference) || (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && @@ -2994,6 +2994,7 @@ ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = false; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3066,6 +3067,7 @@ ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = InitCategory.isRValue(); + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3146,11 +3148,13 @@ ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = true; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = true; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; } return ICS; @@ -3286,9 +3290,9 @@ ICS.Standard.DirectBinding = true; ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; ICS.Standard.BindsToFunctionLvalue = false; - - // Note: we intentionally don't set this; see isBetterReferenceBindingKind(). - ICS.Standard.BindsToRvalue = false; + ICS.Standard.BindsToRvalue = FromClassification.isRValue(); + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier + = (Method->getRefQualifier() == RQ_None); return ICS; } Modified: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp?rev=124313&r1=124312&r2=124313&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Wed Jan 26 13:41:18 2011 @@ -27,6 +27,8 @@ int &h() const&; float &h() &&; + int &h2() const&; + float &h2() const&&; }; void X0::g() { @@ -62,4 +64,7 @@ int &ir1 = lvalue().h(); float &fr1 = xvalue().h(); float &fr2 = prvalue().h(); + int &ir2 = lvalue().h2(); + float &fr3 = xvalue().h2(); + float &fr4 = prvalue().h2(); } From rjmccall at apple.com Wed Jan 26 12:05:40 2011 From: rjmccall at apple.com (John McCall) Date: Wed, 26 Jan 2011 20:05:40 -0000 Subject: [cfe-commits] r124315 - in /cfe/trunk: lib/AST/ItaniumMangle.cpp test/CodeGenCXX/mangle.cpp Message-ID: <20110126200540.49EFE2A6C12C@llvm.org> Author: rjmccall Date: Wed Jan 26 14:05:40 2011 New Revision: 124315 URL: http://llvm.org/viewvc/llvm-project?rev=124315&view=rev Log: When mangling a qualified array type, push the qualifiers down to the element type. Fixes rdar://problem/8913416. Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/test/CodeGenCXX/mangle.cpp Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=124315&r1=124314&r2=124315&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Jan 26 14:05:40 2011 @@ -1191,21 +1191,35 @@ Out << Buffer; } -void CXXNameMangler::mangleType(QualType T) { +void CXXNameMangler::mangleType(QualType nonCanon) { // Only operate on the canonical type! - T = Context.getASTContext().getCanonicalType(T); + QualType canon = nonCanon.getCanonicalType(); - bool IsSubstitutable = T.hasLocalQualifiers() || !isa(T); - if (IsSubstitutable && mangleSubstitution(T)) + SplitQualType split = canon.split(); + Qualifiers quals = split.second; + const Type *ty = split.first; + + bool isSubstitutable = quals || !isa(ty); + if (isSubstitutable && mangleSubstitution(canon)) return; - if (Qualifiers Quals = T.getLocalQualifiers()) { - mangleQualifiers(Quals); + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (quals && isa(ty)) { + ty = Context.getASTContext().getAsArrayType(canon); + quals = Qualifiers(); + + // Note that we don't update canon: we want to add the + // substitution at the canonical type. + } + + if (quals) { + mangleQualifiers(quals); // Recurse: even if the qualified type isn't yet substitutable, // the unqualified type might be. - mangleType(T.getLocalUnqualifiedType()); + mangleType(QualType(ty, 0)); } else { - switch (T->getTypeClass()) { + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -1213,15 +1227,15 @@ return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ - mangleType(static_cast(T.getTypePtr())); \ + mangleType(static_cast(ty)); \ break; #include "clang/AST/TypeNodes.def" } } // Add the substitution. - if (IsSubstitutable) - addSubstitution(T); + if (isSubstitutable) + addSubstitution(canon); } void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { Modified: cfe/trunk/test/CodeGenCXX/mangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle.cpp?rev=124315&r1=124314&r2=124315&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle.cpp Wed Jan 26 14:05:40 2011 @@ -635,3 +635,15 @@ // CHECK: define void @_ZN6test221fEDn( void f(decltype(nullptr)) { } } + +// rdar://problem/8913416 +namespace test23 { + typedef void * const vpc; + + // CHECK: define void @_ZN6test231fERA10_KPv( + void f(vpc (&)[10]) {} + + typedef vpc vpca5[5]; + void f(vpca5 volatile (&)[10]) {} + // CHECK: define void @_ZN6test231fERA10_A5_VKPv( +} From dgregor at apple.com Wed Jan 26 12:35:32 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 20:35:32 -0000 Subject: [cfe-commits] r124316 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td lib/Parse/ParseDecl.cpp test/Parser/cxx0x-in-cxx98.cpp Message-ID: <20110126203532.D3B272A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 14:35:32 2011 New Revision: 124316 URL: http://llvm.org/viewvc/llvm-project?rev=124316&view=rev Log: Improve the extension warning for the use of ref-qualifiers, to distinguish them from rvalue references. Using the rvalue-references warning was weird when the ref-qualifier was '&'. Added: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp (with props) Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/lib/Parse/ParseDecl.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=124316&r1=124315&r2=124316&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Jan 26 14:35:32 2011 @@ -160,6 +160,8 @@ "%0 declared as a reference to a reference">; def ext_rvalue_reference : ExtWarn< "rvalue references are a C++0x extension">, InGroup; +def ext_ref_qualifier : ExtWarn< + "reference qualifiers on functions are a C++0x extension">, InGroup; def ext_inline_namespace : ExtWarn< "inline namespaces are a C++0x feature">, InGroup; def err_argument_required_after_attribute : Error< Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124316&r1=124315&r2=124316&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Jan 26 14:35:32 2011 @@ -3102,7 +3102,7 @@ // Parse ref-qualifier[opt] if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_rvalue_reference); + Diag(Tok, diag::ext_ref_qualifier); RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); @@ -3353,7 +3353,7 @@ // Parse ref-qualifier[opt] if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_rvalue_reference); + Diag(Tok, diag::ext_ref_qualifier); RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); Added: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp?rev=124316&view=auto ============================================================================== --- cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp (added) +++ cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp Wed Jan 26 14:35:32 2011 @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s + +inline namespace N { // expected-warning{{inline namespaces are a C++0x feature}} +struct X { + template // expected-warning{{variadic templates are a C++0x extension}} + void f(Args &&...) &; // expected-warning{{rvalue references are a C++0x extension}} \ + // expected-warning{{reference qualifiers on functions are a C++0x extension}} +}; +} + Propchange: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Wed Jan 26 13:04:07 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 21:04:07 -0000 Subject: [cfe-commits] r124319 - in /cfe/trunk: lib/Sema/SemaCXXCast.cpp test/CXX/expr/expr.cast/p4-0x.cpp Message-ID: <20110126210407.27DB92A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 15:04:06 2011 New Revision: 124319 URL: http://llvm.org/viewvc/llvm-project?rev=124319&view=rev Log: Handle C-style casts to rvalue reference types that cast away constness. Added: cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp (with props) Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=124319&r1=124318&r2=124319&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original) +++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Jan 26 15:04:06 2011 @@ -78,7 +78,8 @@ // %1: Source Type // %2: Destination Type static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, - QualType DestType, CastKind &Kind, + QualType DestType, bool CStyle, + CastKind &Kind, CXXCastPath &BasePath, unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, @@ -583,7 +584,8 @@ // C++0x [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, Kind, BasePath, msg); + tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, CStyle, Kind, BasePath, + msg); if (tcr != TC_NotApplicable) return tcr; @@ -695,7 +697,8 @@ /// Tests whether a conversion according to N2844 is valid. TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, - CastKind &Kind, CXXCastPath &BasePath, unsigned &msg) { + bool CStyle, CastKind &Kind, CXXCastPath &BasePath, + unsigned &msg) { // C++0x [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". @@ -711,8 +714,15 @@ // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; bool ObjCConversion; + QualType FromType = SrcExpr->getType(); + QualType ToType = R->getPointeeType(); + if (CStyle) { + FromType = FromType.getUnqualifiedType(); + ToType = ToType.getUnqualifiedType(); + } + if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), - R->getPointeeType(), SrcExpr->getType(), + ToType, FromType, DerivedToBase, ObjCConversion) < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; Added: cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp?rev=124319&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp Wed Jan 26 15:04:06 2011 @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +struct X { }; +struct Y : X { }; + +void test_lvalue_to_rvalue_drop_cvquals(const X &x, const Y &y, const int &i) { + (void)(X&&)x; + (void)(int&&)i; + (void)(X&&)y; + (void)(Y&&)x; +} Propchange: cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/expr/expr.cast/p4-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Wed Jan 26 13:20:37 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 21:20:37 -0000 Subject: [cfe-commits] r124321 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaOverload.cpp test/CXX/over/over.load/p2-0x.cpp Message-ID: <20110126212037.C9FC12A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 15:20:37 2011 New Revision: 124321 URL: http://llvm.org/viewvc/llvm-project?rev=124321&view=rev Log: Implement the restriction that a function with a ref-qualifier cannot overload a function without a ref-qualifier (C++0x [over.load]p2). This, apparently, completes the implementation of rvalue references for *this. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/over/over.load/p2-0x.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124321&r1=124320&r2=124321&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jan 26 15:20:37 2011 @@ -2481,6 +2481,11 @@ "%select{static member|nonmember}0 function cannot have a ref-qualifier " "'%select{&&|&}1'">; +def err_ref_qualifier_overload : Error< + "cannot overload a member function %select{without a ref-qualifier|with " + "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" + "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; + def err_invalid_non_static_member_use : Error< "invalid use of nonstatic data member %0">; def err_invalid_incomplete_type_use : Error< Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124321&r1=124320&r2=124321&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 15:20:37 2011 @@ -694,8 +694,24 @@ if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic() && (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() || - OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) + OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) { + if (!UseUsingDeclRules && + OldMethod->getRefQualifier() != NewMethod->getRefQualifier() && + (OldMethod->getRefQualifier() == RQ_None || + NewMethod->getRefQualifier() == RQ_None)) { + // C++0x [over.load]p2: + // - Member function declarations with the same name and the same + // parameter-type-list as well as member function template + // declarations with the same name, the same parameter-type-list, and + // the same template parameter lists cannot be overloaded if any of + // them, but not all, have a ref-qualifier (8.3.5). + Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) + << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); + Diag(OldMethod->getLocation(), diag::note_previous_declaration); + } + return true; + } // The signatures match; this is not an overload. return false; Modified: cfe/trunk/test/CXX/over/over.load/p2-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.load/p2-0x.cpp?rev=124321&r1=124320&r2=124321&view=diff ============================================================================== --- cfe/trunk/test/CXX/over/over.load/p2-0x.cpp (original) +++ cfe/trunk/test/CXX/over/over.load/p2-0x.cpp Wed Jan 26 15:20:37 2011 @@ -10,12 +10,15 @@ void h() &; void h() const &; void h() &&; - void i() &; - void i() const; // FIXME: expected an error here! + void i() &; // expected-note{{previous declaration}} + void i() const; // expected-error{{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&'}} template void f(T*) &; template void f(T*) &&; - template void g(T*) &; - template void g(T*); // FIXME: expected an error here + template void g(T*) &; // expected-note{{previous declaration}} + template void g(T*); // expected-error{{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&'}} + + void k(); // expected-note{{previous declaration}} + void k() &&; // expected-error{{cannot overload a member function with ref-qualifier '&&' with a member function without a ref-qualifier}} }; From dgregor at apple.com Wed Jan 26 13:25:54 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 21:25:54 -0000 Subject: [cfe-commits] r124322 - in /cfe/trunk: docs/LanguageExtensions.html lib/Lex/PPMacroExpansion.cpp test/Lexer/has_feature_cxx0x.cpp Message-ID: <20110126212554.84ED52A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 15:25:54 2011 New Revision: 124322 URL: http://llvm.org/viewvc/llvm-project?rev=124322&view=rev Log: Add __has_feature(cxx_reference_qualified_functions); update tests and documentation. Modified: cfe/trunk/docs/LanguageExtensions.html cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Modified: cfe/trunk/docs/LanguageExtensions.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=124322&r1=124321&r2=124322&view=diff ============================================================================== --- cfe/trunk/docs/LanguageExtensions.html (original) +++ cfe/trunk/docs/LanguageExtensions.html Wed Jan 26 15:25:54 2011 @@ -39,6 +39,7 @@
    • C++0x lambdas
    • C++0x nullptr
    • C++0x rvalue references
    • +
    • C++0x reference-qualified functions
    • C++0x static_assert()
    • C++0x type inference
    • C++0x variadic templates
    • @@ -423,11 +424,13 @@ nullptr is enabled. clang does not yet fully implement this feature.

      +

      C++0x reference-qualified functions

      +

      Use __has_feature(cxx_reference_qualified_functions) to determine if support for reference-qualified functions (e.g., member functions with & or && applied to *this) is enabled.

      +

      C++0x rvalue references

      Use __has_feature(cxx_rvalue_references) to determine if support for -rvalue references is enabled. clang does not yet fully implement this -feature.

      +rvalue references is enabled.

      C++0x static_assert()

      @@ -438,7 +441,8 @@

      Use __has_feature(cxx_auto_type) to determine C++0x type inference is supported using the auto specifier. If this is disabled, -auto will instead be a storage class specifier, as in C or C++98.

      +auto will instead be a storage class specifier, as in C or C++98. +Clang does not currently implement this feature.

      C++0x variadic templates

      Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124322&r1=124321&r2=124322&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Jan 26 15:25:54 2011 @@ -556,6 +556,7 @@ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) //.Case("cxx_nullptr", false) + .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x) .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x) .Case("cxx_strong_enums", LangOpts.CPlusPlus0x) .Case("cxx_static_assert", LangOpts.CPlusPlus0x) Modified: cfe/trunk/test/Lexer/has_feature_cxx0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/has_feature_cxx0x.cpp?rev=124322&r1=124321&r2=124322&view=diff ============================================================================== --- cfe/trunk/test/Lexer/has_feature_cxx0x.cpp (original) +++ cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Wed Jan 26 15:25:54 2011 @@ -99,3 +99,13 @@ // CHECK-0X: has_inline_namespaces // CHECK-NO-0X: no_inline_namespaces + +#if __has_feature(cxx_reference_qualified_functions) +int has_reference_qualified_functions(); +#else +int no_reference_qualified_functions(); +#endif + +// CHECK-0X: has_reference_qualified_functions +// CHECK-NO-0X: no_reference_qualified_functions + From nicolasweber at gmx.de Wed Jan 26 13:28:52 2011 From: nicolasweber at gmx.de (Nico Weber) Date: Wed, 26 Jan 2011 21:28:52 -0000 Subject: [cfe-commits] r124325 - in /cfe/trunk/examples/PrintFunctionNames: Makefile README.txt Message-ID: <20110126212852.31FAB2A6C12C@llvm.org> Author: nico Date: Wed Jan 26 15:28:52 2011 New Revision: 124325 URL: http://llvm.org/viewvc/llvm-project?rev=124325&view=rev Log: make `make` work in examples/PrintFucntionNames on Mac. I checked that it still works on Linux. Modified: cfe/trunk/examples/PrintFunctionNames/Makefile cfe/trunk/examples/PrintFunctionNames/README.txt Modified: cfe/trunk/examples/PrintFunctionNames/Makefile URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/Makefile?rev=124325&r1=124324&r2=124325&view=diff ============================================================================== --- cfe/trunk/examples/PrintFunctionNames/Makefile (original) +++ cfe/trunk/examples/PrintFunctionNames/Makefile Wed Jan 26 15:28:52 2011 @@ -18,7 +18,11 @@ endif endif -LINK_LIBS_IN_SHARED = 1 +LINK_LIBS_IN_SHARED = 0 SHARED_LIBRARY = 1 include $(CLANG_LEVEL)/Makefile + +ifeq ($(OS),Darwin) + LDFLAGS=-Wl,-undefined,dynamic_lookup +endif Modified: cfe/trunk/examples/PrintFunctionNames/README.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?rev=124325&r1=124324&r2=124325&view=diff ============================================================================== --- cfe/trunk/examples/PrintFunctionNames/README.txt (original) +++ cfe/trunk/examples/PrintFunctionNames/README.txt Wed Jan 26 15:28:52 2011 @@ -1,10 +1,12 @@ This is a simple example demonstrating how to use clang's facility for providing AST consumers using a plugin. -You will probably need to build clang so that it exports all symbols (disable -TOOL_NO_EXPORT in the tools/clang Makefile). +Build the plugin by running `make` in this directory. Once the plugin is built, you can run it using: -- -$ clang -cc1 -load path/to/libPrintFunctionNames.so -plugin print-fns some-input-file.c --- +Linux: +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c + +Mac: +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c From dgregor at apple.com Wed Jan 26 13:35:14 2011 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 26 Jan 2011 21:35:14 -0000 Subject: [cfe-commits] r124326 - /cfe/trunk/www/cxx_status.html Message-ID: <20110126213515.16CCB2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 15:35:14 2011 New Revision: 124326 URL: http://llvm.org/viewvc/llvm-project?rev=124326&view=rev Log: Update C++0x status web page Modified: cfe/trunk/www/cxx_status.html Modified: cfe/trunk/www/cxx_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=124326&r1=124325&r2=124326&view=diff ============================================================================== --- cfe/trunk/www/cxx_status.html (original) +++ cfe/trunk/www/cxx_status.html Wed Jan 26 15:35:14 2011 @@ -195,12 +195,11 @@ rvalue references - - + + 8.3.2 N2118, - N2831 - N2027 + N2831 N2439 @@ -450,6 +449,7 @@ N2087 N2242 N2488 + N2555 @@ -475,12 +475,12 @@ extern templates - - - - + + + + 14.8.2 - N1448 + N1987 Local classes as template parameters From fjahanian at apple.com Wed Jan 26 15:08:27 2011 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 26 Jan 2011 23:08:27 -0000 Subject: [cfe-commits] r124332 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenObjC/block-6.m Message-ID: <20110126230827.556F32A6C12C@llvm.org> Author: fjahanian Date: Wed Jan 26 17:08:27 2011 New Revision: 124332 URL: http://llvm.org/viewvc/llvm-project?rev=124332&view=rev Log: Fixes an IRgen bug where __block variable is referenced in the block-literal initializer of that variable. // rdar://8893785 Added: cfe/trunk/test/CodeGenObjC/block-6.m Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=124332&r1=124331&r2=124332&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Jan 26 17:08:27 2011 @@ -305,6 +305,15 @@ return ByRefValueInfo.find(VD)->second.second; } +llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, + const VarDecl *V) { + llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding"); + Loc = Builder.CreateLoad(Loc); + Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V), + V->getNameAsString()); + return Loc; +} + /// BuildByRefType - This routine changes a __block variable declared as T x /// into: /// @@ -795,9 +804,6 @@ SpecialInit(*this, D, DeclPtr); } else if (Init) { llvm::Value *Loc = DeclPtr; - if (isByRef) - Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), - D.getNameAsString()); bool isVolatile = getContext().getCanonicalType(Ty).isVolatileQualified(); @@ -844,13 +850,31 @@ } } else if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, &D); + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Alignment, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); + if (isByRef) { + // When RHS has side-effect, must go through "forwarding' field + // to get to the address of the __block variable descriptor. + if (Init->HasSideEffects(getContext())) + Loc = BuildBlockByrefAddress(DeclPtr, &D); + else + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + } EmitStoreOfScalar(V, Loc, isVolatile, Alignment, Ty); } else if (Init->getType()->isAnyComplexType()) { + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false)); } } Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=124332&r1=124331&r2=124332&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Jan 26 17:08:27 2011 @@ -1164,12 +1164,9 @@ V = CGM.getStaticLocalDeclAddress(VD); assert(V && "DeclRefExpr not entered in LocalDeclMap?"); - if (VD->hasAttr()) { - V = Builder.CreateStructGEP(V, 1, "forwarding"); - V = Builder.CreateLoad(V); - V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), - VD->getNameAsString()); - } + if (VD->hasAttr()) + V = BuildBlockByrefAddress(V, VD); + if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124332&r1=124331&r2=124332&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Jan 26 17:08:27 2011 @@ -811,7 +811,11 @@ /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field /// number that holds the value. unsigned getByRefValueLLVMField(const ValueDecl *VD) const; - + + /// BuildBlockByrefAddress - Computes address location of the + /// variable which is declared as __block. + llvm::Value *BuildBlockByrefAddress(llvm::Value *BaseAddr, + const VarDecl *V); private: CGDebugInfo *DebugInfo; Added: cfe/trunk/test/CodeGenObjC/block-6.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/block-6.m?rev=124332&view=auto ============================================================================== --- cfe/trunk/test/CodeGenObjC/block-6.m (added) +++ cfe/trunk/test/CodeGenObjC/block-6.m Wed Jan 26 17:08:27 2011 @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s +// rdar://8893785 + +void MYFUNC() { +// CHECK: [[T1:%.*]] = bitcast i8* ()* +// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T:%.*]]* [[N:%.*]], i32 0, i32 1 +// CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]] +// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[N_T]]* [[T0]], i32 0, i32 6 +// CHECK-NEXT: store i8* [[T1]], i8** [[OBSERVER]] + __block id observer = ^{ return observer; }; +} + From dgregor at apple.com Wed Jan 26 16:58:17 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 00:58:17 -0000 Subject: [cfe-commits] r124340 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaCXXCast.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/CXX/expr/expr.cast/p4.cpp Message-ID: <20110127005817.BD28C2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 18:58:17 2011 New Revision: 124340 URL: http://llvm.org/viewvc/llvm-project?rev=124340&view=rev Log: Fix a horrible bug in our handling of C-style casting, where a C-style derived-to-base cast that also casts away constness (one of the cases for static_cast followed by const_cast) would be treated as a bit-cast rather than a derived-to-base class, causing miscompiles and heartburn. Fixes . Added: cfe/trunk/test/CXX/expr/expr.cast/p4.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaCXXCast.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 26 18:58:17 2011 @@ -999,7 +999,8 @@ Expr *From, bool SuppressUserConversions, bool AllowExplicit, - bool InOverloadResolution); + bool InOverloadResolution, + bool CStyle); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); @@ -1023,7 +1024,8 @@ CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); - bool IsQualificationConversion(QualType FromType, QualType ToType); + bool IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); @@ -4559,10 +4561,11 @@ bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, - bool IgnoreBaseAccess = false); + bool CStyle = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action,bool IgnoreBaseAccess); + AssignmentAction Action, + bool CStyle); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original) +++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Jan 26 18:58:17 2011 @@ -320,7 +320,7 @@ // Test if they're compatible. return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct); + !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false); } /// CheckDynamicCast - Check that a dynamic_cast\(SrcExpr) is valid. @@ -1035,8 +1035,7 @@ InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); InitializationKind InitKind - = InitializationKind::CreateCast(/*FIXME:*/OpRange, - CStyle); + = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle); InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); // At this point of CheckStaticCast, if the destination is a reference, Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 26 18:58:17 2011 @@ -1737,11 +1737,11 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, - IgnoreBaseAccess)) + CStyle)) return true; break; @@ -1772,7 +1772,7 @@ if (!ICS.UserDefined.EllipsisConversion) { if (PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, - IgnoreBaseAccess)) + CStyle)) return true; } @@ -1790,7 +1790,7 @@ From = CastArg.takeAs(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - AA_Converting, IgnoreBaseAccess); + AA_Converting, CStyle); } case ImplicitConversionSequence::AmbiguousConversion: @@ -1820,7 +1820,7 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, @@ -1982,7 +1982,7 @@ CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) + if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; @@ -1991,8 +1991,7 @@ case ICK_Pointer_Member: { CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, - IgnoreBaseAccess)) + if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; @@ -2022,7 +2021,7 @@ From->getLocStart(), From->getSourceRange(), &BasePath, - IgnoreBaseAccess)) + CStyle)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jan 26 18:58:17 2011 @@ -2519,7 +2519,9 @@ bool T1Function = T1->isFunctionType(); if (isLValueRef || T1Function) { if (InitCategory.isLValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + (Kind.isCStyleOrFunctionalCast() && + RefRelationship == Sema::Ref_Related))) { // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // @@ -2593,7 +2595,9 @@ // "cv1 T1" is reference-compatible with "cv2 T2" // Note: functions are handled below. if (!T1Function && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && + (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + (Kind.isCStyleOrFunctionalCast() && + RefRelationship == Sema::Ref_Related)) && (InitCategory.isXValue() || (InitCategory.isPRValue() && T2->isRecordType()) || (InitCategory.isPRValue() && T2->isArrayType()))) { @@ -2630,9 +2634,6 @@ // reference-related to T2, and can be implicitly converted to an // xvalue, class prvalue, or function lvalue of type "cv3 T3", // where "cv1 T1" is reference-compatible with "cv3 T3", - // - // FIXME: Need to handle xvalue, class prvalue, etc. cases in - // TryRefInitWithConversionFunction. if (T2->isRecordType()) { if (RefRelationship == Sema::Ref_Incompatible) { ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, @@ -2665,7 +2666,8 @@ if (S.TryImplicitConversion(Sequence, TempEntity, Initializer, /*SuppressUserConversions*/ false, AllowExplicit, - /*FIXME:InOverloadResolution=*/false)) { + /*FIXME:InOverloadResolution=*/false, + /*CStyle=*/Kind.isCStyleOrFunctionalCast())) { // FIXME: Use the conversion function set stored in ICS to turn // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some @@ -3184,7 +3186,8 @@ if (S.TryImplicitConversion(*this, Entity, Initializer, /*SuppressUserConversions*/ true, /*AllowExplicitConversions*/ false, - /*InOverloadResolution*/ false)) + /*InOverloadResolution*/ false, + /*CStyle=*/Kind.isCStyleOrFunctionalCast())) { if (Initializer->getType() == Context.OverloadTy) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); @@ -3844,11 +3847,9 @@ } case SK_ConversionSequence: { - bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, getAssignmentAction(Entity), - IgnoreBaseAccess)) + Kind.isCStyleOrFunctionalCast())) return ExprError(); CurInit.release(); Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 18:58:17 2011 @@ -46,7 +46,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, - StandardConversionSequence &SCS); + StandardConversionSequence &SCS, + bool CStyle); static OverloadingResult IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence& User, @@ -744,10 +745,11 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, - bool InOverloadResolution) { + bool InOverloadResolution, + bool CStyle) { ImplicitConversionSequence ICS; if (IsStandardConversion(S, From, ToType, InOverloadResolution, - ICS.Standard)) { + ICS.Standard, CStyle)) { ICS.setStandard(); return ICS; } @@ -858,12 +860,14 @@ Expr *Initializer, bool SuppressUserConversions, bool AllowExplicitConversions, - bool InOverloadResolution) { + bool InOverloadResolution, + bool CStyle) { ImplicitConversionSequence ICS = clang::TryImplicitConversion(*this, Initializer, Entity.getType(), SuppressUserConversions, AllowExplicitConversions, - InOverloadResolution); + InOverloadResolution, + CStyle); if (ICS.isBad()) return true; // Perform the actual conversion. @@ -891,7 +895,8 @@ ICS = clang::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -999,7 +1004,8 @@ /// routine will return false and the value of SCS is unspecified. static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, - StandardConversionSequence &SCS) { + StandardConversionSequence &SCS, + bool CStyle) { QualType FromType = From->getType(); // Standard conversions (C++ [conv]) @@ -1189,7 +1195,7 @@ QualType CanonFrom; QualType CanonTo; // The third conversion can be a qualification conversion (C++ 4p1). - if (S.IsQualificationConversion(FromType, ToType)) { + if (S.IsQualificationConversion(FromType, ToType, CStyle)) { SCS.Third = ICK_Qualification; FromType = ToType; CanonFrom = S.Context.getCanonicalType(FromType); @@ -1984,7 +1990,8 @@ /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). bool -Sema::IsQualificationConversion(QualType FromType, QualType ToType) { +Sema::IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); @@ -2009,12 +2016,12 @@ // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. - if (!ToType.isAtLeastAsQualifiedAs(FromType)) + if (!CStyle && !ToType.isAtLeastAsQualifiedAs(FromType)) return false; // -- if the cv 1,j and cv 2,j are different, then const is in // every cv for 0 < k < j. - if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers() + if (!CStyle && FromType.getCVRQualifiers() != ToType.getCVRQualifiers() && !PreviousToQualsIncludeConst) return false; @@ -3156,7 +3163,8 @@ // and does not constitute a conversion. ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, /*AllowExplicit=*/false, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); // Of course, that's still a reference binding. if (ICS.isStandard()) { @@ -3195,7 +3203,8 @@ return TryImplicitConversion(S, From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, - InOverloadResolution); + InOverloadResolution, + /*CStyle=*/false); } /// TryObjectArgumentInitialization - Try to initialize the object @@ -3379,7 +3388,8 @@ // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -3405,7 +3415,8 @@ // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToObjCId - Perform a contextual conversion Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124340&r1=124339&r2=124340&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 26 18:58:17 2011 @@ -3085,7 +3085,7 @@ if (ParamType->isPointerType() && !ParamType->getAs()->getPointeeType()->isFunctionType() && - S.IsQualificationConversion(ArgType, ParamType)) { + S.IsQualificationConversion(ArgType, ParamType, false)) { // For pointer-to-object types, qualification conversions are // permitted. } else { @@ -3429,7 +3429,8 @@ ParamType, Arg, Converted); - if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) { + if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), + false)) { ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { @@ -3492,7 +3493,7 @@ if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. - } else if (IsQualificationConversion(ArgType, ParamType)) { + } else if (IsQualificationConversion(ArgType, ParamType, false)) { ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); } else { // We can't perform this conversion. @@ -3597,7 +3598,7 @@ // the element type on the parameter could be more qualified than the // element type in the expression we constructed. if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType())) { + ParamType.getUnqualifiedType(), false)) { Expr *RefE = RefExpr.takeAs(); ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp); RefExpr = Owned(RefE); Added: cfe/trunk/test/CXX/expr/expr.cast/p4.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.cast/p4.cpp?rev=124340&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.cast/p4.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.cast/p4.cpp Wed Jan 26 18:58:17 2011 @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -ast-dump %s | FileCheck %s + +struct A { int x; }; +struct B { int y; }; +struct C : A, B { }; + +// CHECK: casting_away_constness +void casting_away_constness(const B &b, const C &c, const B *bp, const C *cp) { + // CHECK: DerivedToBase (B) + // CHECK: DeclRefExpr {{.*}} ParmVar='c' + (void)(B&)c; + // CHECK: BaseToDerived (B) + // CHECK: DeclRefExpr {{.*}} ParmVar='b' + (void)(C&)b; + // CHECK: DerivedToBase (B) + // CHECK: DeclRefExpr {{.*}} ParmVar='cp' + (void)(B*)cp; + // CHECK: BaseToDerived (B) + // CHECK: DeclRefExpr {{.*}} ParmVar='bp' + (void)(C*)bp; + // CHECK: ReturnStmt + return; +} From thakis at chromium.org Wed Jan 26 17:17:15 2011 From: thakis at chromium.org (Nico Weber) Date: Wed, 26 Jan 2011 17:17:15 -0800 Subject: [cfe-commits] r124279 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td test/Preprocessor/pragma_diagnostic_sections.cpp test/Sema/uninit-variables.c test/SemaCXX/uninit-variables.cpp In-Reply-To: <20110126044948.77A142A6C12D@llvm.org> References: <20110126044948.77A142A6C12D@llvm.org> Message-ID: Hi Ted, this adds 265 compile errors to the chrome build (we build with -Werror). I went through the first 40 or so, and they're all false positives. The two most common cases are http://llvm.org/bugs/show_bug.cgi?id=9063 http://llvm.org/bugs/show_bug.cgi?id=9064 (a real bug) I also filed http://llvm.org/bugs/show_bug.cgi?id=9061 http://llvm.org/bugs/show_bug.cgi?id=9062 At the moment, we will have to disable -Wuninitialized in chrome if we want to update clang (which we _always_ want to do :-) ). Nico On Tue, Jan 25, 2011 at 8:49 PM, Ted Kremenek wrote: > Author: kremenek > Date: Tue Jan 25 22:49:48 2011 > New Revision: 124279 > > URL: http://llvm.org/viewvc/llvm-project?rev=124279&view=rev > Log: > Merge -Wuninitialized-experimental into -Wuninitialized. > > Modified: >    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td >    cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp >    cfe/trunk/test/Sema/uninit-variables.c >    cfe/trunk/test/SemaCXX/uninit-variables.cpp > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124279&r1=124278&r2=124279&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 25 22:49:48 2011 > @@ -821,9 +821,9 @@ >  def note_uninit_reference_member : Note< >   "uninitialized reference member is here">; >  def warn_field_is_uninit : Warning<"field is uninitialized when used here">, > -  InGroup>; > +  InGroup; >  def warn_uninit_var : Warning<"use of uninitialized variable %0">, > -  InGroup>, DefaultIgnore; > +  InGroup, DefaultIgnore; >  def note_uninit_var : Note< >   "variable %0 is possibly uninitialized when used here">; >  def note_uninit_var_captured_by_block : Note< > > Modified: cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp?rev=124279&r1=124278&r2=124279&view=diff > ============================================================================== > --- cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp (original) > +++ cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp Tue Jan 25 22:49:48 2011 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -verify %s > +// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -Wno-uninitialized -verify %s > >  // rdar://8365684 >  struct S { > > Modified: cfe/trunk/test/Sema/uninit-variables.c > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124279&r1=124278&r2=124279&view=diff > ============================================================================== > --- cfe/trunk/test/Sema/uninit-variables.c (original) > +++ cfe/trunk/test/Sema/uninit-variables.c Tue Jan 25 22:49:48 2011 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify > +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fblocks %s -verify > >  int test1() { >   int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} > > Modified: cfe/trunk/test/SemaCXX/uninit-variables.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninit-variables.cpp?rev=124279&r1=124278&r2=124279&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/uninit-variables.cpp (original) > +++ cfe/trunk/test/SemaCXX/uninit-variables.cpp Tue Jan 25 22:49:48 2011 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only %s -verify > +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only %s -verify > >  int test1_aux(int &x); >  int test1() { > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > From dgregor at apple.com Wed Jan 26 17:30:16 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 01:30:16 -0000 Subject: [cfe-commits] r124344 - in /cfe/trunk: lib/Sema/SemaType.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Message-ID: <20110127013016.8E2CC2A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 19:30:16 2011 New Revision: 124344 URL: http://llvm.org/viewvc/llvm-project?rev=124344&view=rev Log: Cope with parenthesized function declarators when emitting a diagnostic about ref-qualifiers where they do not belong. Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124344&r1=124343&r2=124344&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Wed Jan 26 19:30:16 2011 @@ -1901,8 +1901,16 @@ if (FnTy->getRefQualifier()) { if (D.isFunctionDeclarator()) { - SourceLocation Loc - = D.getTypeObject(D.getNumTypeObjects()-1).Fun.getRefQualifierLoc(); + SourceLocation Loc = D.getIdentifierLoc(); + for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { + const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1); + if (Chunk.Kind == DeclaratorChunk::Function && + Chunk.Fun.hasRefQualifier()) { + Loc = Chunk.Fun.getRefQualifierLoc(); + break; + } + } + Diag(Loc, diag::err_invalid_ref_qualifier_function_type) << (FnTy->getRefQualifier() == RQ_LValue) << FixItHint::CreateRemoval(Loc); Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp?rev=124344&r1=124343&r2=124344&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (original) +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Wed Jan 26 19:30:16 2011 @@ -24,3 +24,5 @@ void (X::*mpf1)() & = &X::f0; void (X::*mpf2)() && = &X::f1; + +void (f() &&); // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}} From kremenek at apple.com Wed Jan 26 17:38:19 2011 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 26 Jan 2011 17:38:19 -0800 Subject: [cfe-commits] r124279 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td test/Preprocessor/pragma_diagnostic_sections.cpp test/Sema/uninit-variables.c test/SemaCXX/uninit-variables.cpp In-Reply-To: References: <20110126044948.77A142A6C12D@llvm.org> Message-ID: <97B2198C-6386-4DDE-B67B-EBB9BE6AE13F@apple.com> On Jan 26, 2011, at 5:17 PM, Nico Weber wrote: > Hi Ted, > > this adds 265 compile errors to the chrome build (we build with > -Werror). I went through the first 40 or so, and they're all false > positives. The two most common cases are Hi Nico, Thanks for filing these reports. I expected some fallout from enabling this warning, and I want to see these bugs. One thing I want to make clear is that the goal of -Wuninitialized in clang is twofold: 1) Provide consistent results despite the optimization level used for compilation (or even -O0) 2) Provide reasonable but conservative results. I suspect that GCC gives up in many cases. > > http://llvm.org/bugs/show_bug.cgi?id=9063 I think there are two cases here, and I've commented in the bug requesting more data. > http://llvm.org/bugs/show_bug.cgi?id=9064 (a real bug) Yes this is a glaring omission. Just need to handle fast enumeration. > > I also filed > http://llvm.org/bugs/show_bug.cgi?id=9061 I think this is reasonable to handle, but only for the case where loops have the format: for (int i = 0; i < constant ; ...) It's clear that the loop body is always entered. > http://llvm.org/bugs/show_bug.cgi?id=9062 I don't think this is reasonable to do. I suspect GCC just gets lucky because it's -Wuninitialized implementation in based on the optimizer or that it simply gives up. There is a control-dependency here that in the general case can only be handled using path-sensitive analysis. Going back to goals (1) and (2), I think this is one place where we want Clang to be more conservative than GCC. I suspect many will disagree. > At the moment, we will have to disable -Wuninitialized in chrome if we > want to update clang (which we _always_ want to do :-) ). I think 3/4 PRs are reasonable requests to fix. The only contentious one is 9062, and I don't know if that is a deal breaker for you. -------------- next part -------------- An HTML attachment was scrubbed... URL: From dgregor at apple.com Wed Jan 26 17:40:18 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 01:40:18 -0000 Subject: [cfe-commits] r124345 - in /cfe/trunk: lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.param/p1.cpp Message-ID: <20110127014018.2F9A32A6C12C@llvm.org> Author: dgregor Date: Wed Jan 26 19:40:17 2011 New Revision: 124345 URL: http://llvm.org/viewvc/llvm-project?rev=124345&view=rev Log: When we run into a template parameter that should have a default argument but doesn't (because previous template parameters had default arguments), clear out all of the default arguments so that we maintain the invariant that a template parameter has a default argument only if subsequence template parameters also have default arguments. Fixes a crash-on-invalid . Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/CXX/temp/temp.param/p1.cpp Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124345&r1=124344&r2=124345&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 26 19:40:17 2011 @@ -1149,6 +1149,7 @@ if (OldParams) OldParam = OldParams->begin(); + bool RemoveDefaultArguments = false; for (TemplateParameterList::iterator NewParam = NewParams->begin(), NewParamEnd = NewParams->end(); NewParam != NewParamEnd; ++NewParam) { @@ -1317,13 +1318,14 @@ } else if (MissingDefaultArg) { // C++ [temp.param]p11: // If a template-parameter of a class template has a default - // template-argument, each subsequent template- parameter shall either + // template-argument, each subsequent template-parameter shall either // have a default template-argument supplied or be a template parameter // pack. Diag((*NewParam)->getLocation(), diag::err_template_param_default_arg_missing); Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg); Invalid = true; + RemoveDefaultArguments = true; } // If we have an old template parameter list that we're merging @@ -1332,6 +1334,22 @@ ++OldParam; } + // We were missing some default arguments at the end of the list, so remove + // all of the default arguments. + if (RemoveDefaultArguments) { + for (TemplateParameterList::iterator NewParam = NewParams->begin(), + NewParamEnd = NewParams->end(); + NewParam != NewParamEnd; ++NewParam) { + if (TemplateTypeParmDecl *TTP = dyn_cast(*NewParam)) + TTP->removeDefaultArgument(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(*NewParam)) + NTTP->removeDefaultArgument(); + else + cast(*NewParam)->removeDefaultArgument(); + } + } + return Invalid; } Modified: cfe/trunk/test/CXX/temp/temp.param/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p1.cpp?rev=124345&r1=124344&r2=124345&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.param/p1.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.param/p1.cpp Wed Jan 26 19:40:17 2011 @@ -4,3 +4,9 @@ template class C> class D; // expected-error{{template template parameter must have its own template parameters}} +struct A {}; +template // expected-error{{template parameter missing a default argument}} +class X0 {}; // expected-note{{template is declared here}} +X0 x0; // expected-error{{too few template arguments for class template 'X0'}} From kremenek at apple.com Wed Jan 26 18:01:31 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 02:01:31 -0000 Subject: [cfe-commits] r124347 - in /cfe/trunk: lib/Analysis/UninitializedValuesV2.cpp test/SemaObjC/uninit-variables.m Message-ID: <20110127020131.F1DA92A6C12C@llvm.org> Author: kremenek Date: Wed Jan 26 20:01:31 2011 New Revision: 124347 URL: http://llvm.org/viewvc/llvm-project?rev=124347&view=rev Log: Teach -Wuninitialized about ObjC fast enumeration loops. Added: cfe/trunk/test/SemaObjC/uninit-variables.m Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp?rev=124347&r1=124346&r2=124347&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp (original) +++ cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Wed Jan 26 20:01:31 2011 @@ -311,6 +311,7 @@ void VisitBinaryOperator(BinaryOperator *bo); void VisitCastExpr(CastExpr *ce); void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se); + void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); }; } @@ -319,6 +320,43 @@ if (handler) handler->handleUseOfUninitVariable(ex, vd); } +static FindVarResult findBlockVarDecl(Expr* ex) { + if (DeclRefExpr* dr = dyn_cast(ex->IgnoreParenCasts())) + if (VarDecl *vd = dyn_cast(dr->getDecl())) + if (isTrackedVar(vd)) + return FindVarResult(vd, dr); + + return FindVarResult(0, 0); +} + +void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt( + ObjCForCollectionStmt *fs) { + + Visit(fs->getCollection()); + + // This represents an initialization of the 'element' value. + Stmt *element = fs->getElement(); + const VarDecl* vd = 0; + + if (DeclStmt* ds = dyn_cast(element)) { + vd = cast(ds->getSingleDecl()); + if (!isTrackedVar(vd)) + vd = 0; + } + else { + // Initialize the value of the reference variable. + const FindVarResult &res = findBlockVarDecl(cast(element)); + vd = res.getDecl(); + if (!vd) { + Visit(element); + return; + } + } + + if (vd) + vals[vd] = Initialized; +} + void TransferFunctions::VisitBlockExpr(BlockExpr *be) { if (!flagBlockUses || !handler) return; @@ -366,15 +404,6 @@ vals[vd] = Initialized; } -static FindVarResult findBlockVarDecl(Expr* ex) { - if (DeclRefExpr* dr = dyn_cast(ex->IgnoreParenCasts())) - if (VarDecl *vd = dyn_cast(dr->getDecl())) - if (isTrackedVar(vd)) - return FindVarResult(vd, dr); - - return FindVarResult(0, 0); -} - void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { if (bo->isAssignmentOp()) { const FindVarResult &res = findBlockVarDecl(bo->getLHS()); Added: cfe/trunk/test/SemaObjC/uninit-variables.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/uninit-variables.m?rev=124347&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/uninit-variables.m (added) +++ cfe/trunk/test/SemaObjC/uninit-variables.m Wed Jan 26 20:01:31 2011 @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fblocks %s -verify + +// Duplicated from uninit-variables.c. +// Test just to ensure the analysis is working. +int test1() { + int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} + return x; // expected-note{{variable 'x' is possibly uninitialized when used here}} +} + +// Test ObjC fast enumeration. +void test2() { + id collection = 0; + for (id obj in collection) { + if (0 == obj) // no-warning + break; + } +} + +void test3() { + id collection = 0; + id obj; + for (obj in collection) { // no-warning + if (0 == obj) // no-warning + break; + } +} + From thakis at chromium.org Wed Jan 26 18:14:25 2011 From: thakis at chromium.org (Nico Weber) Date: Wed, 26 Jan 2011 18:14:25 -0800 Subject: [cfe-commits] r124279 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td test/Preprocessor/pragma_diagnostic_sections.cpp test/Sema/uninit-variables.c test/SemaCXX/uninit-variables.cpp In-Reply-To: <97B2198C-6386-4DDE-B67B-EBB9BE6AE13F@apple.com> References: <20110126044948.77A142A6C12D@llvm.org> <97B2198C-6386-4DDE-B67B-EBB9BE6AE13F@apple.com> Message-ID: Thanks for the quick reply. On Wed, Jan 26, 2011 at 5:38 PM, Ted Kremenek wrote: > On Jan 26, 2011, at 5:17 PM, Nico Weber wrote: > > Hi Ted, > > this adds 265 compile errors to the chrome build (we build with > -Werror). I went through the first 40 or so, and they're all false > positives. The two most common cases are > > Hi Nico, > Thanks for filing these reports.  I expected some fallout from enabling this > warning, and I want to see these bugs. > One thing I want to make clear is that the goal of -Wuninitialized in clang > is twofold: > 1) Provide consistent results despite the optimization level used for > compilation (or even -O0) > 2) Provide reasonable but conservative results.  I suspect that GCC gives up > in many cases. > > http://llvm.org/bugs/show_bug.cgi?id=9063 > > I think there are two cases here, and I've commented in the bug requesting > more data. Replied on the bug. > > http://llvm.org/bugs/show_bug.cgi?id=9064 (a real bug) > > Yes this is a glaring omission.  Just need to handle fast enumeration. > > I also filed > http://llvm.org/bugs/show_bug.cgi?id=9061 > > I think this is reasonable to handle, but only for the case where loops have > the format: >   for (int i = 0; i < constant ; ...) > It's clear that the loop body is always entered. This would help, I've seen this pattern (for loop with a fixed upper bound) a few times already. > http://llvm.org/bugs/show_bug.cgi?id=9062 > > I don't think this is reasonable to do.  I suspect GCC just gets lucky > because it's -Wuninitialized implementation in based on the optimizer or > that it simply gives up.  There is a control-dependency here that in the > general case can only be handled using path-sensitive analysis.  Going back > to goals (1) and (2), I think this is one place where we want Clang to be > more conservative than GCC.  I suspect many will disagree. I've seen this problem only once so far, might not be a big deal. > > At the moment, we will have to disable -Wuninitialized in chrome if we > want to update clang (which we _always_ want to do :-) ). > > I think 3/4 PRs are reasonable requests to fix.  The only contentious one is > 9062, and I don't know if that is a deal breaker for you. I don't know yet, it depends on how the false positive rate looks after the new engine had some baking time. Thanks for being responsive :-) From kremenek at apple.com Wed Jan 26 18:29:34 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 02:29:34 -0000 Subject: [cfe-commits] r124348 - in /cfe/trunk: lib/Analysis/UninitializedValuesV2.cpp test/Sema/uninit-variables.c Message-ID: <20110127022934.DAB132A6C12C@llvm.org> Author: kremenek Date: Wed Jan 26 20:29:34 2011 New Revision: 124348 URL: http://llvm.org/viewvc/llvm-project?rev=124348&view=rev Log: Teach -Wuninitialized not to assert when analyzing blocks that reference captured variables. Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp cfe/trunk/test/Sema/uninit-variables.c Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp?rev=124348&r1=124347&r2=124348&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp (original) +++ cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Wed Jan 26 20:29:34 2011 @@ -25,9 +25,10 @@ using namespace clang; -static bool isTrackedVar(const VarDecl *vd) { +static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { return vd->isLocalVarDecl() && !vd->hasGlobalStorage() && - vd->getType()->isScalarType(); + vd->getType()->isScalarType() && + vd->getDeclContext() == dc; } //------------------------------------------------------------------------====// @@ -57,7 +58,7 @@ E(dc.decls_end()); for ( ; I != E; ++I) { const VarDecl *vd = *I; - if (isTrackedVar(vd)) + if (isTrackedVar(vd, &dc)) map[vd] = count++; } } @@ -312,6 +313,12 @@ void VisitCastExpr(CastExpr *ce); void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se); void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); + + bool isTrackedVar(const VarDecl *vd) { + return ::isTrackedVar(vd, cast(ac.getDecl())); + } + + FindVarResult findBlockVarDecl(Expr *ex); }; } @@ -320,12 +327,11 @@ if (handler) handler->handleUseOfUninitVariable(ex, vd); } -static FindVarResult findBlockVarDecl(Expr* ex) { +FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) { if (DeclRefExpr* dr = dyn_cast(ex->IgnoreParenCasts())) if (VarDecl *vd = dyn_cast(dr->getDecl())) if (isTrackedVar(vd)) - return FindVarResult(vd, dr); - + return FindVarResult(vd, dr); return FindVarResult(0, 0); } @@ -364,10 +370,11 @@ llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl()); for ( ; i != e; ++i) { const VarDecl *vd = *i; - if (vd->getAttr() || !vd->hasLocalStorage()) + if (vd->getAttr() || !vd->hasLocalStorage() || + !isTrackedVar(vd)) continue; if (vals[vd] == Uninitialized) - handler->handleUseOfUninitVariable(be, vd); + handler->handleUseOfUninitVariable(be, vd); } } Modified: cfe/trunk/test/Sema/uninit-variables.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124348&r1=124347&r2=124348&view=diff ============================================================================== --- cfe/trunk/test/Sema/uninit-variables.c (original) +++ cfe/trunk/test/Sema/uninit-variables.c Wed Jan 26 20:29:34 2011 @@ -223,3 +223,9 @@ return x; // expected-note{{variable 'x' is possibly uninitialized when used here}} } +// Test that this case doesn't crash. +void test35(int x) { + __block int y = 0; + ^{ y = (x == 0); }(); +} + From rjmccall at apple.com Wed Jan 26 18:37:01 2011 From: rjmccall at apple.com (John McCall) Date: Thu, 27 Jan 2011 02:37:01 -0000 Subject: [cfe-commits] r124349 - /cfe/trunk/lib/AST/ASTImporter.cpp Message-ID: <20110127023701.394302A6C12C@llvm.org> Author: rjmccall Date: Wed Jan 26 20:37:01 2011 New Revision: 124349 URL: http://llvm.org/viewvc/llvm-project?rev=124349&view=rev Log: Import three interesting bits that apply only to C++ methods. Modified: cfe/trunk/lib/AST/ASTImporter.cpp Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=124349&r1=124348&r2=124349&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Jan 26 20:37:01 2011 @@ -2396,6 +2396,9 @@ } ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); + ToFunction->setVirtualAsWritten(D->isVirtualAsWritten()); + ToFunction->setTrivial(D->isTrivial()); + ToFunction->setPure(D->isPure()); Importer.Imported(D, ToFunction); // Set the parameters. From rjmccall at apple.com Wed Jan 26 18:46:02 2011 From: rjmccall at apple.com (John McCall) Date: Thu, 27 Jan 2011 02:46:02 -0000 Subject: [cfe-commits] r124351 - /cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Message-ID: <20110127024602.DA4F22A6C12C@llvm.org> Author: rjmccall Date: Wed Jan 26 20:46:02 2011 New Revision: 124351 URL: http://llvm.org/viewvc/llvm-project?rev=124351&view=rev Log: Notes on dynamic array cookies in MSVC. My thanks to chapuni for his help in investigating this. Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=124351&r1=124350&r2=124351&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Jan 26 20:46:02 2011 @@ -55,6 +55,29 @@ EmitThisParam(CGF); // TODO: 'for base' flag } + + // ==== Notes on array cookies ========= + // + // MSVC seems to only use cookies when the class has a destructor; a + // two-argument usual array deallocation function isn't sufficient. + // + // For example, this code prints "100" and "1": + // struct A { + // char x; + // void *operator new[](size_t sz) { + // printf("%u\n", sz); + // return malloc(sz); + // } + // void operator delete[](void *p, size_t sz) { + // printf("%u\n", sz); + // free(p); + // } + // }; + // int main() { + // A *p = new A[100]; + // delete[] p; + // } + // Whereas it prints "104" and "104" if you give A a destructor. }; } From kremenek at apple.com Wed Jan 26 18:57:57 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 02:57:57 -0000 Subject: [cfe-commits] r124352 - /cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Message-ID: <20110127025757.3186C2A6C12C@llvm.org> Author: kremenek Date: Wed Jan 26 20:57:57 2011 New Revision: 124352 URL: http://llvm.org/viewvc/llvm-project?rev=124352&view=rev Log: Teach -Wuninitialized to suggest "= false" for initializing bool variables. Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124352&r1=124351&r2=124352&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Wed Jan 26 20:57:57 2011 @@ -433,6 +433,9 @@ else if (vdTy->isRealFloatingType()) { initialization = " = 0.0"; } + else if (vdTy->isBooleanType()) { + initialization = " = false"; + } else if (vdTy->isScalarType()) { initialization = " = 0"; } From clattner at apple.com Wed Jan 26 19:59:23 2011 From: clattner at apple.com (Chris Lattner) Date: Wed, 26 Jan 2011 19:59:23 -0800 Subject: [cfe-commits] r124352 - /cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp In-Reply-To: <20110127025757.3186C2A6C12C@llvm.org> References: <20110127025757.3186C2A6C12C@llvm.org> Message-ID: <804BB7F9-51D0-4B29-9028-DE518CB090FD@apple.com> On Jan 26, 2011, at 6:57 PM, Ted Kremenek wrote: > Author: kremenek > Date: Wed Jan 26 20:57:57 2011 > New Revision: 124352 > > URL: http://llvm.org/viewvc/llvm-project?rev=124352&view=rev > Log: > Teach -Wuninitialized to suggest "= false" for initializing bool variables. In C99 mode, it should suggest 0 for _Bool, not false. Does this work? -Chris > > Modified: > cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > > Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124352&r1=124351&r2=124352&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) > +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Wed Jan 26 20:57:57 2011 > @@ -433,6 +433,9 @@ > else if (vdTy->isRealFloatingType()) { > initialization = " = 0.0"; > } > + else if (vdTy->isBooleanType()) { > + initialization = " = false"; > + } > else if (vdTy->isScalarType()) { > initialization = " = 0"; > } > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From kremenek at apple.com Wed Jan 26 21:18:52 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 05:18:52 -0000 Subject: [cfe-commits] r124356 - /cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Message-ID: <20110127051852.EA8E02A6C12C@llvm.org> Author: kremenek Date: Wed Jan 26 23:18:52 2011 New Revision: 124356 URL: http://llvm.org/viewvc/llvm-project?rev=124356&view=rev Log: Tweak -Wuninitialized fixit for '_Bool' types to be initialized to 0, and C++ 'bool' types to false. Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=124356&r1=124355&r2=124356&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Wed Jan 26 23:18:52 2011 @@ -433,7 +433,7 @@ else if (vdTy->isRealFloatingType()) { initialization = " = 0.0"; } - else if (vdTy->isBooleanType()) { + else if (vdTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) { initialization = " = false"; } else if (vdTy->isScalarType()) { From kremenek at apple.com Wed Jan 26 21:22:21 2011 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 26 Jan 2011 21:22:21 -0800 Subject: [cfe-commits] r124352 - /cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp In-Reply-To: <804BB7F9-51D0-4B29-9028-DE518CB090FD@apple.com> References: <20110127025757.3186C2A6C12C@llvm.org> <804BB7F9-51D0-4B29-9028-DE518CB090FD@apple.com> Message-ID: On Jan 26, 2011, at 7:59 PM, Chris Lattner wrote: > > On Jan 26, 2011, at 6:57 PM, Ted Kremenek wrote: > >> Author: kremenek >> Date: Wed Jan 26 20:57:57 2011 >> New Revision: 124352 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=124352&view=rev >> Log: >> Teach -Wuninitialized to suggest "= false" for initializing bool variables. > > In C99 mode, it should suggest 0 for _Bool, not false. Does this work? > > -Chris > > WFM. r124356 -------------- next part -------------- An HTML attachment was scrubbed... URL: From geek4civic at gmail.com Wed Jan 26 21:47:56 2011 From: geek4civic at gmail.com (NAKAMURA Takumi) Date: Thu, 27 Jan 2011 14:47:56 +0900 Subject: [cfe-commits] [PATCH] 7bit-ize Message-ID: Hello. Some source files contain utf8 characters. I would like to apply this if we should better get rid of utf8, thank you. ...Takumi -------------- next part -------------- From d602455c60ec48e0baad5b9fa2a8bfdee80c7c6f Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 6 Jan 2011 15:43:06 +0900 Subject: [PATCH 1/2] 7bit-ize. --- lib/Analysis/PrintfFormatString.cpp | 2 +- lib/Sema/SemaExprCXX.cpp | 18 +++++++++--------- lib/Sema/SemaInit.cpp | 6 +++--- lib/Sema/SemaLookup.cpp | 4 ++-- lib/Sema/SemaOverload.cpp | 8 ++++---- lib/Sema/SemaStmt.cpp | 2 +- lib/Sema/SemaTemplate.cpp | 12 ++++++------ lib/Sema/SemaTemplateDeduction.cpp | 16 ++++++++-------- lib/StaticAnalyzer/BasicStore.cpp | 4 ++-- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 82ab14d..4eea2bc 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -454,7 +454,7 @@ bool PrintfSpecifier::fixType(QualType QT) { void PrintfSpecifier::toString(llvm::raw_ostream &os) const { // Whilst some features have no defined order, we are using the order - // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1) + // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) os << "%"; // Positional args diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index acdc15f..7e0cb8a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -78,13 +78,13 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. In a qualified-id of the form: - // - // ::[opt] nested-name-specifier ? class-name + // + // ::[opt] nested-name-specifier ~ class-name // // where the nested-name-specifier designates a namespace scope, and in // a qualified-id of the form: // - // ::opt nested-name-specifier class-name :: ? class-name + // ::opt nested-name-specifier class-name :: ~ class-name // // the class-names are looked up as types in the scope designated by // the nested-name-specifier. @@ -1017,10 +1017,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation - // function?s name is operator new and the deallocation function?s + // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array - // type, the allocation function?s name is operator new[] and the - // deallocation function?s name is operator delete[]. + // type, the allocation function's name is operator new[] and the + // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( @@ -1061,12 +1061,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the - // deallocation function?s name is looked up in the global + // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an - // array thereof, the deallocation function?s name is looked up in + // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the - // deallocation function?s name is looked up in the global scope. + // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index b34fe2f..a2a087a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2651,8 +2651,8 @@ static void TryReferenceInitialization(Sema &S, Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } - - // - Otherwise, a temporary of type ?cv1 T1? is created and initialized + + // - Otherwise, a temporary of type "cv1 T1" is created and initialized // from the initializer expression using the rules for a non-reference // copy initialization (8.5). The reference is then bound to the // temporary. [...] @@ -2850,7 +2850,7 @@ static void TryValueInitialization(Sema &S, // -- if T is a (possibly cv-qualified) non-union class type // without a user-provided constructor, then the object is - // zero-initialized and, if T?s implicitly-declared default + // zero-initialized and, if T's implicitly-declared default // constructor is non-trivial, that constructor is called. if ((ClassDecl->getTagKind() == TTK_Class || ClassDecl->getTagKind() == TTK_Struct)) { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 161908e..3b7fa0a 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1759,7 +1759,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member - // templates, the member template?s class; the namespaces and classes + // templates, the member template's class; the namespaces and classes // associated with the types of the template arguments provided for // template type parameters (excluding template template parameters); the // namespaces in which any template template arguments are defined; and @@ -1886,7 +1886,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class - // member, its associated class is the member?s class; else + // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast(T)->getDecl(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f33f42d..1e8f315 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3242,9 +3242,9 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, // For non-static member functions, the type of the implicit object // parameter is // - // ? "lvalue reference to cv X" for functions declared without a - // ref-qualifier or with the & ref-qualifier - // ? "rvalue reference to cv X" for functions declared with the && + // - "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // - "rvalue reference to cv X" for functions declared with the && // ref-qualifier // // where X is the class of which the function is a member and cv is the @@ -3623,7 +3623,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); assert(!Function->getDescribedFunctionTemplate() && - "Use AddTemp?lateOverloadCandidate for function templates"); + "Use AddTemplateOverloadCandidate for function templates"); if (CXXMethodDecl *Method = dyn_cast(Function)) { if (!isa(Method)) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 72d28e6..f4fe647 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1168,7 +1168,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // [...] If overload resolution fails, or if the type of the first // parameter of the selected constructor is not an rvalue reference - // to the object?s type (possibly cv-qualified), overload resolution + // to the object's type (possibly cv-qualified), overload resolution // is performed again, considering the object as an lvalue. if (Seq.getKind() != InitializationSequence::FailedSequence) { for (InitializationSequence::step_iterator Step = Seq.step_begin(), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1d2de0f..133b29b 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3868,9 +3868,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // C++0x [temp.arg.template]p3: // A template-argument matches a template template-parameter (call it P) - // when each of the template parameters in the template-parameter-list of - // the template-argument?s corresponding class template or template alias - // (call it A) matches the corresponding template parameter in the + // when each of the template parameters in the template-parameter-list of + // the template-argument's corresponding class template or template alias + // (call it A) matches the corresponding template parameter in the // template-parameter-list of P. [...] TemplateParameterList::iterator NewParm = New->begin(); TemplateParameterList::iterator NewParmEnd = New->end(); @@ -3896,9 +3896,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } // C++0x [temp.arg.template]p3: - // [...] When P?s template- parameter-list contains a template parameter - // pack (14.5.3), the template parameter pack will match zero or more - // template parameters or template parameter packs in the + // [...] When P's template- parameter-list contains a template parameter + // pack (14.5.3), the template parameter pack will match zero or more + // template parameters or template parameter packs in the // template-parameter-list of A with the same type and form as the // template parameter pack in P (ignoring whether those template // parameters are template parameter packs). diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index fd12ccf..1cad333 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -913,7 +913,7 @@ DeduceTemplateArguments(Sema &S, // which case the type of Pi is changed to be the template parameter // type (i.e., T&& is changed to simply T). [ Note: As a result, when // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be - // deduced as X&. ? end note ] + // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; if (const RValueReferenceType *ParamRef @@ -2439,7 +2439,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, Expr *Arg, unsigned &TDF) { // C++0x [temp.deduct.call]p3: - // If P is a cv-qualified type, the top level cv-qualifiers of P?s type + // If P is a cv-qualified type, the top level cv-qualifiers of P's type // are ignored for type deduction. if (ParamType.getCVRQualifiers()) ParamType = ParamType.getLocalUnqualifiedType(); @@ -2495,7 +2495,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, else if (ArgType->isFunctionType()) ArgType = S.Context.getPointerType(ArgType); else { - // - If A is a cv-qualified type, the top level cv-qualifiers of A?s + // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. if (ArgType.getCVRQualifiers()) ArgType = ArgType.getUnqualifiedType(); @@ -2858,12 +2858,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, else if (P->isFunctionType()) P = Context.getPointerType(P); // - If P is a cv-qualified type, the top level cv-qualifiers of - // P?s type are ignored for type deduction. + // P's type are ignored for type deduction. else P = P.getUnqualifiedType(); // C++0x [temp.deduct.conv]p3: - // If A is a cv-qualified type, the top level cv-qualifiers of A?s + // If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. A = A.getUnqualifiedType(); } @@ -2893,7 +2893,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (ToType->isReferenceType()) TDF |= TDF_ParamWithReferenceType; // - The deduced A can be another pointer or pointer to member - // type that can be converted to A via a quali?cation + // type that can be converted to A via a qualification // conversion. // // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when @@ -2963,7 +2963,7 @@ static void MaybeAddImplicitObjectParameterType(ASTContext &Context, // // For non-static member functions, the type of the implicit // object parameter is - // ? "lvalue reference to cv X" for functions declared without a + // - "lvalue reference to cv X" for functions declared without a // ref-qualifier or with the & ref-qualifier // - "rvalue reference to cv X" for functions declared with the // && ref-qualifier @@ -3067,7 +3067,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, break; case TPOC_Other: - // - In other contexts (14.6.6.2) the function template?s function type + // - In other contexts (14.6.6.2) the function template's function type // is used. // FIXME: Don't we actually want to perform the adjustments on the parameter // types? diff --git a/lib/StaticAnalyzer/BasicStore.cpp b/lib/StaticAnalyzer/BasicStore.cpp index 0254ba7..64de19d 100644 --- a/lib/StaticAnalyzer/BasicStore.cpp +++ b/lib/StaticAnalyzer/BasicStore.cpp @@ -459,8 +459,8 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, // C99: 6.7.8 Initialization // If an object that has static storage duration is not initialized // explicitly, then: - // ?if it has pointer type, it is initialized to a null pointer; - // ?if it has arithmetic type, it is initialized to (positive or + // -if it has pointer type, it is initialized to a null pointer; + // -if it has arithmetic type, it is initialized to (positive or // unsigned) zero; if (!InitVal) { QualType T = VD->getType(); -- 1.7.1.GIT -------------- next part -------------- A non-text attachment was scrubbed... Name: 0002-Fix-whitespace.patch.txt.gz Type: application/x-gzip Size: 112489 bytes Desc: not available URL: From clattner at apple.com Wed Jan 26 21:57:10 2011 From: clattner at apple.com (Chris Lattner) Date: Wed, 26 Jan 2011 21:57:10 -0800 Subject: [cfe-commits] [PATCH] 7bit-ize In-Reply-To: References: Message-ID: On Jan 26, 2011, at 9:47 PM, NAKAMURA Takumi wrote: > Hello. > > Some source files contain utf8 characters. I would like to apply this > if we should better get rid of utf8, thank you. Sounds great, please commit! -Chris From kremenek at apple.com Wed Jan 26 22:54:14 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 06:54:14 -0000 Subject: [cfe-commits] r124360 - in /cfe/trunk: lib/Lex/PPMacroExpansion.cpp lib/StaticAnalyzer/CFRefCount.cpp test/Analysis/retain-release.m www/analyzer/annotations.html Message-ID: <20110127065414.B71042A6C12C@llvm.org> Author: kremenek Date: Thu Jan 27 00:54:14 2011 New Revision: 124360 URL: http://llvm.org/viewvc/llvm-project?rev=124360&view=rev Log: Hook up attribute ns_consumes_self in the ObjC retain/release checker in the static analyzer. Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp cfe/trunk/test/Analysis/retain-release.m cfe/trunk/www/analyzer/annotations.html Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124360&r1=124359&r2=124360&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Thu Jan 27 00:54:14 2011 @@ -536,6 +536,7 @@ .Case("attribute_ext_vector_type", true) .Case("attribute_ns_returns_not_retained", true) .Case("attribute_ns_returns_retained", true) + .Case("attribute_ns_consumes_self", true) .Case("attribute_objc_ivar_unused", true) .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124360&r1=124359&r2=124360&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Thu Jan 27 00:54:14 2011 @@ -467,6 +467,10 @@ /// terminate the path. bool isEndPath() const { return EndPath; } + + /// Sets the effect on the receiver of the message. + void setReceiverEffect(ArgEffect e) { Receiver = e; } + /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } @@ -1219,6 +1223,11 @@ bool isTrackedLoc = false; + // Effects on the receiver. + if (MD->getAttr()) { + Summ.setReceiverEffect(DecRefMsg); + } + // Determine if there is a special return effect for this method. if (cocoa::isCocoaObjectRef(MD->getResultType())) { if (MD->getAttr()) { Modified: cfe/trunk/test/Analysis/retain-release.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=124360&r1=124359&r2=124360&view=diff ============================================================================== --- cfe/trunk/test/Analysis/retain-release.m (original) +++ cfe/trunk/test/Analysis/retain-release.m Thu Jan 27 00:54:14 2011 @@ -13,6 +13,9 @@ #if __has_feature(attribute_cf_returns_not_retained) #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) #endif +#if __has_feature(attribute_ns_consumes_self) +#define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) +#endif //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from Mac OS X headers: @@ -1211,6 +1214,7 @@ - (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning - (NSString*) newStringNoAttr; - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} +- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED; @end static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} @@ -1228,6 +1232,19 @@ NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}} } +void testattr2_a() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // expected-warning{{leak}} +} + +void testattr2_b() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // expected-warning{{leak}} +} + +void testattr2_c() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // no-warning + [x release]; +} + @interface MyClassTestCFAttr : NSObject {} - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED; - (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED; @@ -1401,7 +1418,7 @@ while (error_to_dump != ((void*)0)) { CFDictionaryRef info; - info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1404 and stored into 'info'}} + info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1421 and stored into 'info'}} if (info != ((void*)0)) { } Modified: cfe/trunk/www/analyzer/annotations.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124360&r1=124359&r2=124360&view=diff ============================================================================== --- cfe/trunk/www/analyzer/annotations.html (original) +++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 00:54:14 2011 @@ -56,6 +56,7 @@
    • Attribute 'ns_returns_not_retained'
    • Attribute 'cf_returns_retained'
    • Attribute 'cf_returns_not_retained'
    • +
    • Attribute 'ns_consumes_self'
    @@ -350,6 +351,38 @@ #endif +

    Attribute 'ns_consumes_self' +(Clang-specific)

    + +

    The 'ns_consumes_self' attribute can be placed only on an Objective-C method declaration. + It indicates that the receiver of the message is "consumed" (a single reference count decremented) + after the message is sent. This matches the semantics of all "init" methods. +

    + +

    One use of this attribute is declare your own init-like methods that do not follow the + standard Cocoa naming conventions. For example:

    + +
    +#ifndef __has_feature
    +#define __has_Feature(x) 0 // Compatibility with non-clang compilers.
    +#endif
    +
    +#ifndef NS_CONSUMES_SELF
    +#if __has_feature((attribute_ns_consumes_self))
    +#else
    +#define NS_CONSUMES_SELF
    +#endif
    +#endif
    +
    + at interface MyClass : NSObject
    +- initWith:(MyClass *)x;
    +- nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
    + at end
    +
    + +

    In this example, nonstandardInitWith: has the same ownership semantics as the init method initWith:. + The static analyzer will observe that the method consumes the receiver, and then returns an object with a +1 retain count.

    +

    Custom Assertion Handlers

    From kremenek at apple.com Wed Jan 26 22:59:29 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 06:59:29 -0000 Subject: [cfe-commits] r124361 - /cfe/trunk/www/analyzer/annotations.html Message-ID: <20110127065929.8416C2A6C12C@llvm.org> Author: kremenek Date: Thu Jan 27 00:59:29 2011 New Revision: 124361 URL: http://llvm.org/viewvc/llvm-project?rev=124361&view=rev Log: Fix a few typos in HTML documentation. Modified: cfe/trunk/www/analyzer/annotations.html Modified: cfe/trunk/www/analyzer/annotations.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124361&r1=124360&r2=124361&view=diff ============================================================================== --- cfe/trunk/www/analyzer/annotations.html (original) +++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 00:59:29 2011 @@ -364,11 +364,11 @@
     #ifndef __has_feature
    -#define __has_Feature(x) 0 // Compatibility with non-clang compilers.
    +#define __has_feature(x) 0 // Compatibility with non-clang compilers.
     #endif
     
     #ifndef NS_CONSUMES_SELF
    -#if __has_feature((attribute_ns_consumes_self))
    +#if __has_feature((attribute_ns_consumes_self))
     #else
     #define NS_CONSUMES_SELF
     #endif
    @@ -376,7 +376,7 @@
     
     @interface MyClass : NSObject
     - initWith:(MyClass *)x;
    -- nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
    +- nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
     @end
     
    From kremenek at apple.com Wed Jan 26 23:02:03 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 07:02:03 -0000 Subject: [cfe-commits] r124362 - /cfe/trunk/www/analyzer/annotations.html Message-ID: <20110127070203.7AE1B2A6C12C@llvm.org> Author: kremenek Date: Thu Jan 27 01:02:03 2011 New Revision: 124362 URL: http://llvm.org/viewvc/llvm-project?rev=124362&view=rev Log: Fix HTML highlighting and add missing line. Modified: cfe/trunk/www/analyzer/annotations.html Modified: cfe/trunk/www/analyzer/annotations.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124362&r1=124361&r2=124362&view=diff ============================================================================== --- cfe/trunk/www/analyzer/annotations.html (original) +++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 01:02:03 2011 @@ -368,7 +368,8 @@ #endif #ifndef NS_CONSUMES_SELF -#if __has_feature((attribute_ns_consumes_self)) +#if __has_feature((attribute_ns_consumes_self)) +#define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) #else #define NS_CONSUMES_SELF #endif From geek4civic at gmail.com Wed Jan 26 23:09:50 2011 From: geek4civic at gmail.com (NAKAMURA Takumi) Date: Thu, 27 Jan 2011 07:09:50 -0000 Subject: [cfe-commits] r124363 - in /cfe/trunk/lib: Analysis/PrintfFormatString.cpp Sema/SemaExprCXX.cpp Sema/SemaInit.cpp Sema/SemaLookup.cpp Sema/SemaOverload.cpp Sema/SemaStmt.cpp Sema/SemaTemplate.cpp Sema/SemaTemplateDeduction.cpp StaticAnalyzer/BasicStore.cpp Message-ID: <20110127070950.60B252A6C12C@llvm.org> Author: chapuni Date: Thu Jan 27 01:09:49 2011 New Revision: 124363 URL: http://llvm.org/viewvc/llvm-project?rev=124363&view=rev Log: 7bit-ize. Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/lib/Sema/SemaLookup.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Thu Jan 27 01:09:49 2011 @@ -454,7 +454,7 @@ void PrintfSpecifier::toString(llvm::raw_ostream &os) const { // Whilst some features have no defined order, we are using the order - // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1) + // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) os << "%"; // Positional args Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 01:09:49 2011 @@ -78,13 +78,13 @@ // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. In a qualified-id of the form: - // - // ::[opt] nested-name-specifier ̃ class-name + // + // ::[opt] nested-name-specifier ~ class-name // // where the nested-name-specifier designates a namespace scope, and in // a qualified-id of the form: // - // ::opt nested-name-specifier class-name :: ̃ class-name + // ::opt nested-name-specifier class-name :: ~ class-name // // the class-names are looked up as types in the scope designated by // the nested-name-specifier. @@ -1017,10 +1017,10 @@ // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation - // function’s name is operator new and the deallocation function’s + // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array - // type, the allocation function’s name is operator new[] and the - // deallocation function’s name is operator delete[]. + // type, the allocation function's name is operator new[] and the + // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( @@ -1061,12 +1061,12 @@ // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the - // deallocation function’s name is looked up in the global + // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an - // array thereof, the deallocation function’s name is looked up in + // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the - // deallocation function’s name is looked up in the global scope. + // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jan 27 01:09:49 2011 @@ -2651,8 +2651,8 @@ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } - - // - Otherwise, a temporary of type “cv1 T1” is created and initialized + + // - Otherwise, a temporary of type "cv1 T1" is created and initialized // from the initializer expression using the rules for a non-reference // copy initialization (8.5). The reference is then bound to the // temporary. [...] @@ -2850,7 +2850,7 @@ // -- if T is a (possibly cv-qualified) non-union class type // without a user-provided constructor, then the object is - // zero-initialized and, if T’s implicitly-declared default + // zero-initialized and, if T's implicitly-declared default // constructor is non-trivial, that constructor is called. if ((ClassDecl->getTagKind() == TTK_Class || ClassDecl->getTagKind() == TTK_Struct)) { Modified: cfe/trunk/lib/Sema/SemaLookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) +++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Jan 27 01:09:49 2011 @@ -1759,7 +1759,7 @@ // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member - // templates, the member template’s class; the namespaces and classes + // templates, the member template's class; the namespaces and classes // associated with the types of the template arguments provided for // template type parameters (excluding template template parameters); the // namespaces in which any template template arguments are defined; and @@ -1886,7 +1886,7 @@ // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class - // member, its associated class is the member’s class; else + // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast(T)->getDecl(); Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jan 27 01:09:49 2011 @@ -3242,9 +3242,9 @@ // For non-static member functions, the type of the implicit object // parameter is // - // — "lvalue reference to cv X" for functions declared without a - // ref-qualifier or with the & ref-qualifier - // — "rvalue reference to cv X" for functions declared with the && + // - "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // - "rvalue reference to cv X" for functions declared with the && // ref-qualifier // // where X is the class of which the function is a member and cv is the @@ -3623,7 +3623,7 @@ = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); assert(!Function->getDescribedFunctionTemplate() && - "Use AddTemp∫lateOverloadCandidate for function templates"); + "Use AddTemplateOverloadCandidate for function templates"); if (CXXMethodDecl *Method = dyn_cast(Function)) { if (!isa(Method)) { Modified: cfe/trunk/lib/Sema/SemaStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp (original) +++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jan 27 01:09:49 2011 @@ -1168,7 +1168,7 @@ // [...] If overload resolution fails, or if the type of the first // parameter of the selected constructor is not an rvalue reference - // to the object’s type (possibly cv-qualified), overload resolution + // to the object's type (possibly cv-qualified), overload resolution // is performed again, considering the object as an lvalue. if (Seq.getKind() != InitializationSequence::FailedSequence) { for (InitializationSequence::step_iterator Step = Seq.step_begin(), Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 27 01:09:49 2011 @@ -3868,9 +3868,9 @@ // C++0x [temp.arg.template]p3: // A template-argument matches a template template-parameter (call it P) - // when each of the template parameters in the template-parameter-list of - // the template-argument’s corresponding class template or template alias - // (call it A) matches the corresponding template parameter in the + // when each of the template parameters in the template-parameter-list of + // the template-argument's corresponding class template or template alias + // (call it A) matches the corresponding template parameter in the // template-parameter-list of P. [...] TemplateParameterList::iterator NewParm = New->begin(); TemplateParameterList::iterator NewParmEnd = New->end(); @@ -3896,9 +3896,9 @@ } // C++0x [temp.arg.template]p3: - // [...] When P’s template- parameter-list contains a template parameter - // pack (14.5.3), the template parameter pack will match zero or more - // template parameters or template parameter packs in the + // [...] When P's template- parameter-list contains a template parameter + // pack (14.5.3), the template parameter pack will match zero or more + // template parameters or template parameter packs in the // template-parameter-list of A with the same type and form as the // template parameter pack in P (ignoring whether those template // parameters are template parameter packs). Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jan 27 01:09:49 2011 @@ -913,7 +913,7 @@ // which case the type of Pi is changed to be the template parameter // type (i.e., T&& is changed to simply T). [ Note: As a result, when // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be - // deduced as X&. — end note ] + // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; if (const RValueReferenceType *ParamRef @@ -2439,7 +2439,7 @@ Expr *Arg, unsigned &TDF) { // C++0x [temp.deduct.call]p3: - // If P is a cv-qualified type, the top level cv-qualifiers of P’s type + // If P is a cv-qualified type, the top level cv-qualifiers of P's type // are ignored for type deduction. if (ParamType.getCVRQualifiers()) ParamType = ParamType.getLocalUnqualifiedType(); @@ -2495,7 +2495,7 @@ else if (ArgType->isFunctionType()) ArgType = S.Context.getPointerType(ArgType); else { - // - If A is a cv-qualified type, the top level cv-qualifiers of A’s + // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. if (ArgType.getCVRQualifiers()) ArgType = ArgType.getUnqualifiedType(); @@ -2858,12 +2858,12 @@ else if (P->isFunctionType()) P = Context.getPointerType(P); // - If P is a cv-qualified type, the top level cv-qualifiers of - // P’s type are ignored for type deduction. + // P's type are ignored for type deduction. else P = P.getUnqualifiedType(); // C++0x [temp.deduct.conv]p3: - // If A is a cv-qualified type, the top level cv-qualifiers of A’s + // If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. A = A.getUnqualifiedType(); } @@ -2893,7 +2893,7 @@ if (ToType->isReferenceType()) TDF |= TDF_ParamWithReferenceType; // - The deduced A can be another pointer or pointer to member - // type that can be converted to A via a qualification + // type that can be converted to A via a qualification // conversion. // // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when @@ -2963,7 +2963,7 @@ // // For non-static member functions, the type of the implicit // object parameter is - // — "lvalue reference to cv X" for functions declared without a + // - "lvalue reference to cv X" for functions declared without a // ref-qualifier or with the & ref-qualifier // - "rvalue reference to cv X" for functions declared with the // && ref-qualifier @@ -3067,7 +3067,7 @@ break; case TPOC_Other: - // - In other contexts (14.6.6.2) the function template’s function type + // - In other contexts (14.6.6.2) the function template's function type // is used. // FIXME: Don't we actually want to perform the adjustments on the parameter // types? Modified: cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp?rev=124363&r1=124362&r2=124363&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp Thu Jan 27 01:09:49 2011 @@ -459,8 +459,8 @@ // C99: 6.7.8 Initialization // If an object that has static storage duration is not initialized // explicitly, then: - // —if it has pointer type, it is initialized to a null pointer; - // —if it has arithmetic type, it is initialized to (positive or + // -if it has pointer type, it is initialized to a null pointer; + // -if it has arithmetic type, it is initialized to (positive or // unsigned) zero; if (!InitVal) { QualType T = VD->getType(); From geek4civic at gmail.com Wed Jan 26 23:10:08 2011 From: geek4civic at gmail.com (NAKAMURA Takumi) Date: Thu, 27 Jan 2011 07:10:08 -0000 Subject: [cfe-commits] r124364 - in /cfe/trunk/lib: Analysis/PrintfFormatString.cpp Sema/SemaExprCXX.cpp Sema/SemaInit.cpp Sema/SemaLookup.cpp Sema/SemaOverload.cpp Sema/SemaStmt.cpp Sema/SemaTemplate.cpp Sema/SemaTemplateDeduction.cpp StaticAnalyzer/BasicStore.cpp Message-ID: <20110127071009.6F85D2A6C12C@llvm.org> Author: chapuni Date: Thu Jan 27 01:10:08 2011 New Revision: 124364 URL: http://llvm.org/viewvc/llvm-project?rev=124364&view=rev Log: Fix whitespace. Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/lib/Sema/SemaLookup.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Thu Jan 27 01:10:08 2011 @@ -100,7 +100,7 @@ for ( ; I != E; ++I) { switch (*I) { default: hasMore = false; break; - case '\'': + case '\'': // FIXME: POSIX specific. Always accept? FS.setHasThousandsGrouping(I); break; @@ -281,7 +281,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { const PrintfConversionSpecifier &CS = getConversionSpecifier(); - + if (!CS.consumesDataArgument()) return ArgTypeResult::Invalid(); @@ -292,7 +292,7 @@ default: return ArgTypeResult::Invalid(); } - + if (CS.isIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: @@ -593,7 +593,7 @@ bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { if (!HasThousandsGrouping) return true; - + switch (CS.getKind()) { case ConversionSpecifier::dArg: case ConversionSpecifier::iArg: Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 01:10:08 2011 @@ -31,7 +31,7 @@ using namespace sema; ParsedType Sema::getDestructorName(SourceLocation TildeLoc, - IdentifierInfo &II, + IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, @@ -71,11 +71,11 @@ if (SS.isSet()) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); - + bool AlreadySearched = false; bool LookAtPrefix = true; // C++ [basic.lookup.qual]p6: - // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, + // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. In a qualified-id of the form: // @@ -86,11 +86,11 @@ // // ::opt nested-name-specifier class-name :: ~ class-name // - // the class-names are looked up as types in the scope designated by + // the class-names are looked up as types in the scope designated by // the nested-name-specifier. // // Here, we check the first case (completely) and determine whether the - // code below is permitted to look at the prefix of the + // code below is permitted to look at the prefix of the // nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { @@ -99,7 +99,7 @@ isDependent = false; } else if (DC && isa(DC)) LookAtPrefix = false; - + // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = 0; if (AlreadySearched) { @@ -116,7 +116,7 @@ LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } - + LookInScope = false; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: @@ -128,7 +128,7 @@ // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); - assert((isDependent || !SearchType->isIncompleteType()) && + assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; @@ -170,7 +170,7 @@ // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core - // issue 399, for which there isn't even an obvious direction. + // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle()) { QualType MemberOfType; if (SS.isSet()) { @@ -182,7 +182,7 @@ } if (MemberOfType.isNull()) MemberOfType = SearchType; - + if (MemberOfType.isNull()) continue; @@ -199,7 +199,7 @@ continue; } - + // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't @@ -220,7 +220,7 @@ // The class template we found has the same name as the // (dependent) template name being specialized. - if (DependentTemplateName *DepTemplate + if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) @@ -253,7 +253,7 @@ if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << &II; + << &II; else Diag(NameLoc, diag::err_destructor_class_name); @@ -266,9 +266,9 @@ TypeSourceInfo *Operand, SourceLocation RParenLoc) { // C++ [expr.typeid]p4: - // The top-level cv-qualifiers of the lvalue expression or the type-id + // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. - // If the type of the type-id is a class type or a reference to a class + // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T @@ -277,7 +277,7 @@ if (T->getAs() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc))); @@ -298,7 +298,7 @@ // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated @@ -310,11 +310,11 @@ MarkVTableUsed(TypeidLoc, RecordD); } } - + // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly - // cv-qualified type, the result of the typeid expression refers to a - // std::type_info object representing the cv-unqualified referenced + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); @@ -323,16 +323,16 @@ ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)); } } - + // If this is an unevaluated operand, clear out the set of // declaration references we have been computing and eliminate any // temporaries introduced in its computation. if (isUnevaluatedOperand) ExprEvalContexts.back().Context = Unevaluated; - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, - SourceRange(TypeidLoc, RParenLoc))); + SourceRange(TypeidLoc, RParenLoc))); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); @@ -351,9 +351,9 @@ if (!CXXTypeInfoDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); } - + QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); - + if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = 0; @@ -361,14 +361,14 @@ &TInfo); if (T.isNull()) return ExprError(); - + if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } - // The operand is an expression. + // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } @@ -400,7 +400,7 @@ if (!GetUuidAttrOfType(Operand->getType())) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); } - + // FIXME: add __uuidof semantic analysis for type operand. return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, @@ -413,21 +413,21 @@ Expr *E, SourceLocation RParenLoc) { if (!E->getType()->isDependentType()) { - if (!GetUuidAttrOfType(E->getType()) && + if (!GetUuidAttrOfType(E->getType()) && !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); } // FIXME: add __uuidof semantic analysis for type operand. return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, - SourceRange(TypeidLoc, RParenLoc))); + SourceRange(TypeidLoc, RParenLoc))); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - // If MSVCGuidDecl has not been cached, do the lookup. + // If MSVCGuidDecl has not been cached, do the lookup. if (!MSVCGuidDecl) { IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); @@ -435,10 +435,10 @@ MSVCGuidDecl = R.getAsSingle(); if (!MSVCGuidDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); - } - + } + QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); - + if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = 0; @@ -446,14 +446,14 @@ &TInfo); if (T.isNull()) return ExprError(); - + if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); } - // The operand is an expression. + // The operand is an expression. return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } @@ -486,12 +486,12 @@ // A throw-expression initializes a temporary object, called the exception // object, the type of which is determined by removing any top-level // cv-qualifiers from the static type of the operand of throw and adjusting - // the type from "array of T" or "function returning T" to "pointer to T" + // the type from "array of T" or "function returning T" to "pointer to T" // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, CastCategory(E)); - + DefaultFunctionArrayConversion(E); // If the type of the exception would be an incomplete type or a pointer @@ -523,7 +523,7 @@ InitializedEntity Entity = InitializedEntity::InitializeException(ThrowLoc, E->getType(), /*NRVO=*/false); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, QualType(), E); if (Res.isInvalid()) return true; @@ -547,7 +547,7 @@ if (RD->hasTrivialDestructor()) return false; - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = const_cast(LookupDestructor(RD)); if (!Destructor) return false; @@ -580,7 +580,7 @@ SourceLocation RParenLoc) { if (!TypeRep) return ExprError(); - + TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) @@ -622,7 +622,7 @@ PDiag(diag::err_invalid_incomplete_type_use) << FullRange)) return ExprError(); - + if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); @@ -637,7 +637,7 @@ CastKind Kind = CK_Invalid; ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], + if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], Kind, VK, BasePath, /*FunctionalStyle=*/true)) return ExprError(); @@ -655,7 +655,7 @@ InitializationKind Kind = NumExprs ? InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, + : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); @@ -673,7 +673,7 @@ ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, SourceRange TypeIdParens, + SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { @@ -715,10 +715,10 @@ QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); - + if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(AllocType); - + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, move(PlacementArgs), @@ -766,9 +766,9 @@ // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { - + QualType SizeType = ArraySize->getType(); - + ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, PDiag(diag::err_array_size_not_integral), @@ -778,16 +778,16 @@ PDiag(diag::note_array_size_conversion), PDiag(diag::err_array_size_ambiguous_conversion), PDiag(diag::note_array_size_conversion), - PDiag(getLangOptions().CPlusPlus0x? 0 + PDiag(getLangOptions().CPlusPlus0x? 0 : diag::ext_array_size_conversion)); if (ConvertedSize.isInvalid()) return ExprError(); - + ArraySize = ConvertedSize.take(); SizeType = ArraySize->getType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); - + // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. @@ -795,17 +795,17 @@ llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( - llvm::APInt::getNullValue(Value.getBitWidth()), + llvm::APInt::getNullValue(Value.getBitWidth()), Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); - + if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { - Diag(ArraySize->getSourceRange().getBegin(), + Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_too_large) << Value.toString(10) << ArraySize->getSourceRange(); @@ -818,11 +818,11 @@ << ArraySize->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); - + TypeIdParens = SourceRange(); } } - + ImpCastExprToType(ArraySize, Context.getSizeType(), CK_IntegralCast); } @@ -831,7 +831,7 @@ FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); - + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -842,21 +842,21 @@ llvm::SmallVector AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. - const FunctionProtoType *Proto = + const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; - + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, - Proto, 1, PlaceArgs, NumPlaceArgs, + Proto, 1, PlaceArgs, NumPlaceArgs, AllPlaceArgs, CallType)) return ExprError(); - + NumPlaceArgs = AllPlaceArgs.size(); if (NumPlaceArgs > 0) PlaceArgs = &AllPlaceArgs[0]; } - + bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- CXXConstructorDecl *Constructor = 0; @@ -868,7 +868,7 @@ if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { SourceRange InitRange(ConsArgs[0]->getLocStart(), ConsArgs[NumConsArgs - 1]->getLocEnd()); - + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } @@ -883,21 +883,21 @@ // initialized (8.5); if no initialization is performed, // the object has indeterminate value = !Init? InitializationKind::CreateDefault(TypeRange.getBegin()) - // - Otherwise, the new-initializer is interpreted according to the + // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. : InitializationKind::CreateDirect(TypeRange.getBegin(), - ConstructorLParen, + ConstructorLParen, ConstructorRParen); - + InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); - ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, + ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, move(ConstructorArgs)); if (FullInit.isInvalid()) return ExprError(); - - // FullInit is our initializer; walk through it to determine if it's a + + // FullInit is our initializer; walk through it to determine if it's a // constructor call, which CXXNewExpr handles directly. if (Expr *FullInitExpr = (Expr *)FullInit.get()) { if (CXXBindTemporaryExpr *Binder @@ -917,12 +917,12 @@ } else { // No initialization required. } - + // Take the converted arguments and use them for the new expression. NumConsArgs = ConvertedConstructorArgs.size(); ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } - + // Mark the new and delete operators as referenced. if (OperatorNew) MarkDeclarationReferenced(StartLoc, OperatorNew); @@ -930,10 +930,10 @@ MarkDeclarationReferenced(StartLoc, OperatorDelete); // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) - + PlacementArgs.release(); ConstructorArgs.release(); - + return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, @@ -969,7 +969,7 @@ else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - + return false; } @@ -1099,7 +1099,7 @@ // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] - // + // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. @@ -1111,7 +1111,7 @@ = OperatorNew->getType()->getAs(); llvm::SmallVector ArgTypes; - ArgTypes.push_back(Context.VoidPtrTy); + ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) ArgTypes.push_back(Proto->getArgType(I)); @@ -1123,11 +1123,11 @@ ArgTypes.size(), EPI); } - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = 0; - if (FunctionTemplateDecl *FnTmpl + if (FunctionTemplateDecl *FnTmpl = dyn_cast((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. @@ -1144,7 +1144,7 @@ // C++ [expr.new]p20: // [...] Any non-placement deallocation function matches a // non-placement allocation function. [...] - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast((*D)->getUnderlyingDecl())) @@ -1169,7 +1169,7 @@ if (NumPlaceArgs && getLangOptions().CPlusPlus0x && isNonPlacementDeallocationFunction(OperatorDelete)) { Diag(StartLoc, diag::err_placement_new_non_placement_delete) - << SourceRange(PlaceArgs[0]->getLocStart(), + << SourceRange(PlaceArgs[0]->getLocStart(), PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; @@ -1203,7 +1203,7 @@ R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc); - for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. @@ -1242,7 +1242,7 @@ Owned(Args[i])); if (Result.isInvalid()) return true; - + Args[i] = Result.takeAs(); } Operator = FnDecl; @@ -1287,18 +1287,18 @@ void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; - + // C++ [basic.std.dynamic]p2: - // [...] The following allocation and deallocation functions (18.4) are - // implicitly declared in global scope in each translation unit of a + // [...] The following allocation and deallocation functions (18.4) are + // implicitly declared in global scope in each translation unit of a // program - // + // // void* operator new(std::size_t) throw(std::bad_alloc); - // void* operator new[](std::size_t) throw(std::bad_alloc); - // void operator delete(void*) throw(); + // void* operator new[](std::size_t) throw(std::bad_alloc); + // void operator delete(void*) throw(); // void operator delete[](void*) throw(); // - // These implicit declarations introduce only the function names operator + // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. // // Here, we need to refer to std::bad_alloc, so we will implicitly declare @@ -1308,14 +1308,14 @@ if (!StdBadAlloc) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. - StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, - getOrCreateStdNamespace(), - SourceLocation(), - &PP.getIdentifierTable().get("bad_alloc"), + StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, + getOrCreateStdNamespace(), + SourceLocation(), + &PP.getIdentifierTable().get("bad_alloc"), SourceLocation(), 0); getStdBadAlloc()->setImplicit(true); } - + GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); @@ -1365,7 +1365,7 @@ } QualType BadAllocType; - bool HasBadAllocExceptionSpec + bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { @@ -1379,17 +1379,17 @@ EPI.NumExceptions = 1; EPI.Exceptions = &BadAllocType; } - + QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, SC_None, SC_None, false, true); Alloc->setImplicit(); - + if (AddMallocAttr) Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); - + ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, SC_None, @@ -1408,7 +1408,7 @@ LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); - + if (Found.isAmbiguous()) return true; @@ -1452,7 +1452,7 @@ if (!Found.empty()) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; - + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), @@ -1464,7 +1464,7 @@ // Look for a global declaration. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); - + CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation()); Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; @@ -1497,14 +1497,14 @@ QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs()) { - if (RequireCompleteType(StartLoc, Type, + if (RequireCompleteType(StartLoc, Type, PDiag(diag::err_delete_incomplete_class_type))) return ExprError(); - + llvm::SmallVector ObjectPtrConversions; CXXRecordDecl *RD = cast(Record->getDecl()); - const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = I.getDecl(); @@ -1514,9 +1514,9 @@ // Skip over templated conversion functions; they aren't considered. if (isa(D)) continue; - + CXXConversionDecl *Conv = cast(D); - + QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) @@ -1547,7 +1547,7 @@ QualType Pointee = Type->getAs()->getPointeeType(); if (Pointee->isVoidType() && !isSFINAEContext()) { - // The C++ standard bans deleting a pointer to a non-object type, which + // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) @@ -1562,11 +1562,11 @@ return ExprError(); // C++ [expr.delete]p2: - // [Note: a pointer to a const type can be the operand of a - // delete-expression; it is not necessary to cast away the constness - // (5.2.11) of the pointer expression before it is used as the operand + // [Note: a pointer to a const type can be the operand of a + // delete-expression; it is not necessary to cast away the constness + // (5.2.11) of the pointer expression before it is used as the operand // of the delete-expression. ] - ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), + ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), CK_NoOp); if (Pointee->isArrayType() && !ArrayForm) { @@ -1583,10 +1583,10 @@ if (const RecordType *RT = PointeeElem->getAs()) { CXXRecordDecl *RD = cast(RT->getDecl()); - if (!UseGlobal && + if (!UseGlobal && FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) return ExprError(); - + if (!RD->hasTrivialDestructor()) if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { MarkDeclarationReferenced(StartLoc, @@ -1594,7 +1594,7 @@ DiagnoseUseOfDecl(Dtor, StartLoc); } } - + if (!OperatorDelete) { // Look for a global declaration. DeclareGlobalNewDelete(); @@ -1621,25 +1621,25 @@ SourceLocation StmtLoc, bool ConvertToBoolean) { QualType T = ConditionVar->getType(); - + // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, - ConditionVar->getLocation(), + ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType(), VK_LValue); if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) return ExprError(); - + return Owned(Condition); } @@ -1687,7 +1687,7 @@ return false; } -static ExprResult BuildCXXCastArgument(Sema &S, +static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, @@ -1698,35 +1698,35 @@ default: assert(0 && "Unhandled cast kind!"); case CK_ConstructorConversion: { ASTOwningVector ConstructorArgs(S); - + if (S.CompleteConstructorCall(cast(Method), MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - - ExprResult Result = - S.BuildCXXConstructExpr(CastLoc, Ty, cast(Method), + + ExprResult Result = + S.BuildCXXConstructExpr(CastLoc, Ty, cast(Method), move_arg(ConstructorArgs), /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); - + return S.MaybeBindToTemporary(Result.takeAs()); } - + case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - + // Create an implicit call expr that calls it. ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method); if (Result.isInvalid()) return ExprError(); - + return S.MaybeBindToTemporary(Result.get()); } } -} +} /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit @@ -1746,13 +1746,13 @@ break; case ImplicitConversionSequence::UserDefinedConversion: { - + FunctionDecl *FD = ICS.UserDefined.ConversionFunction; CastKind CastKind; QualType BeforeToType; if (const CXXConversionDecl *Conv = dyn_cast(FD)) { CastKind = CK_UserDefinedConversion; - + // If the user-defined conversion is specified by a conversion function, // the initial standard conversion sequence converts the source type to // the implicit object parameter of the conversion function. @@ -1762,21 +1762,21 @@ CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { - // If the user-defined conversion is specified by a constructor, the + // If the user-defined conversion is specified by a constructor, the // initial standard conversion sequence converts the source type to the // type required by the argument of the constructor BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); } - } + } // Watch out for elipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { - if (PerformImplicitConversion(From, BeforeToType, + if (PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, CStyle)) return true; } - - ExprResult CastArg + + ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), @@ -1798,7 +1798,7 @@ PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return true; - + case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); return false; @@ -1834,7 +1834,7 @@ ASTOwningVector ConstructorArgs(*this); if (CompleteConstructorCall(cast(SCS.CopyConstructor), MultiExprArg(*this, &From, 1), - /*FIXME:ConstructLoc*/SourceLocation(), + /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return true; ExprResult FromResult = @@ -1874,7 +1874,7 @@ if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - + From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); } @@ -1926,11 +1926,11 @@ // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) - return true; - + return true; + ImpCastExprToType(From, ToType, CK_NoOp); break; - + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CK_IntegralCast); @@ -1979,7 +1979,7 @@ << From->getType() << ToType << Action << From->getSourceRange(); } - + CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) @@ -1987,7 +1987,7 @@ ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; } - + case ICK_Pointer_Member: { CastKind Kind = CK_Invalid; CXXCastPath BasePath; @@ -2009,17 +2009,17 @@ case Type::STK_IntegralComplex: Kind = CK_IntegralComplexToBoolean; break; case Type::STK_FloatingComplex: Kind = CK_FloatingComplexToBoolean; break; } - + ImpCastExprToType(From, Context.BoolTy, Kind); break; } case ICK_Derived_To_Base: { CXXCastPath BasePath; - if (CheckDerivedToBaseConversion(From->getType(), + if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), + From->getSourceRange(), &BasePath, CStyle)) return true; @@ -2037,7 +2037,7 @@ case ICK_Vector_Splat: ImpCastExprToType(From, ToType, CK_VectorSplat); break; - + case ICK_Complex_Real: // Case 1. x -> _Complex y if (const ComplexType *ToComplex = ToType->getAs()) { @@ -2086,7 +2086,7 @@ } } break; - + case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: @@ -2357,7 +2357,7 @@ TypeSourceInfo *TSInfo, SourceLocation RParen) { QualType T = TSInfo->getType(); - + // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // all traits except __is_class, __is_enum and __is_union require a the type // to be complete, an array of unknown bound, or void. @@ -2409,7 +2409,7 @@ // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. - if (Self.IsDerivedFrom(RhsT, LhsT) || + if (Self.IsDerivedFrom(RhsT, LhsT) || (!LhsT->isUnionType() && !RhsT->isUnionType() && LhsT->getAsCXXRecordDecl() == RhsT->getAsCXXRecordDecl())) return true; @@ -2429,7 +2429,7 @@ SourceLocation RParen) { QualType LhsT = LhsTSInfo->getType(); QualType RhsT = RhsTSInfo->getType(); - + if (BTT == BTT_IsBaseOf) { // C++0x [meta.rel]p2 // If Base and Derived are class types and are different types @@ -2558,9 +2558,9 @@ // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is - // ill-formed if the second operand is a pointer to member function with - // ref-qualifier &. In a ->* expression or in a .* expression whose object - // expression is an lvalue, the program is ill-formed if the second operand + // ill-formed if the second operand is a pointer to member function with + // ref-qualifier &. In a ->* expression or in a .* expression whose object + // expression is an lvalue, the program is ill-formed if the second operand // is a pointer to member function with ref-qualifier &&. if (const FunctionProtoType *Proto = Result->getAs()) { switch (Proto->getRefQualifier()) { @@ -2573,7 +2573,7 @@ Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RType << 1 << lex->getSourceRange(); break; - + case RQ_RValue: if (isIndirect || !lex->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) @@ -2581,7 +2581,7 @@ break; } } - + // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its @@ -2612,8 +2612,8 @@ QualType &ToType) { HaveConversion = false; ToType = To->getType(); - - InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), + + InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); // C++0x 5.16p3 // The process for determining whether an operand expression E1 of type T1 @@ -2627,14 +2627,14 @@ // conversion the reference must bind directly to E1. QualType T = Self.Context.getLValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); } @@ -2646,9 +2646,9 @@ QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs(); const RecordType *TRec = TTy->getAs(); - bool FDerivedFromT = FRec && TRec && FRec != TRec && + bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(FTy, TTy); - if (FRec && TRec && + if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and @@ -2661,28 +2661,28 @@ HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); - } + } } - + return false; } - + // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have - // if E2 were converted to an rvalue (or the type it has, if E2 is + // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. if (!TTy->getAs()) TTy = TTy.getUnqualifiedType(); - + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); @@ -2743,7 +2743,7 @@ ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1)); if (Result.isInvalid()) return true; - + E = Result.takeAs(); return false; } @@ -2822,7 +2822,7 @@ // Otherwise, if the second and third operand have different types, and // either has (cv) class type, and attempt is made to convert each of those // operands to the other. - if (!Context.hasSameType(LTy, RTy) && + if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; // These return true if a single direction is already ambiguous. @@ -2832,7 +2832,7 @@ return QualType(); if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) return QualType(); - + // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -2905,18 +2905,18 @@ if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); - ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), + ExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), Owned(LHS)); if (LHSCopy.isInvalid()) return QualType(); - - ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), + + ExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), Owned(RHS)); if (RHSCopy.isInvalid()) return QualType(); - + LHS = LHSCopy.takeAs(); RHS = RHSCopy.takeAs(); } @@ -2925,7 +2925,7 @@ } // Extension: conditional operator involving vector types. - if (LTy->isVectorType() || RTy->isVectorType()) + if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(QuestionLoc, LHS, RHS); // -- The second and third operands have arithmetic or enumeration type; @@ -2951,14 +2951,14 @@ isSFINAEContext()? 0 : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) - Diag(QuestionLoc, + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands_nonstandard) << LTy << RTy << Composite << LHS->getSourceRange() << RHS->getSourceRange(); - + return Composite; } - + // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) @@ -2984,12 +2984,12 @@ /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. -QualType Sema::FindCompositePointerType(SourceLocation Loc, +QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; - + assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); @@ -3040,20 +3040,20 @@ ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); - unsigned NeedConstBefore = 0; + unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); @@ -3065,13 +3065,13 @@ (MemPtr2 = Composite2->getAs())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), @@ -3087,7 +3087,7 @@ if (NeedConstBefore && NonStandardCompositeType) { // Extension: Add 'const' to qualifiers that come before the first qualifier - // mismatch, so that our (non-standard!) composite type meets the + // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. for (unsigned I = 0; I != NeedConstBefore; ++I) { if ((QualifierUnion[I] & Qualifiers::Const) == 0) { @@ -3096,7 +3096,7 @@ } } } - + // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); @@ -3159,7 +3159,7 @@ if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs(); - + return Composite1; } @@ -3170,28 +3170,28 @@ InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); if (!E1ToC2 || !E2ToC2) return QualType(); - + // Convert E1 to Composite2 ExprResult E1Result = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1)); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs(); - + // Convert E2 to Composite2 ExprResult E2Result = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1)); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs(); - + return Composite2; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!E) return ExprError(); - + if (!Context.getLangOptions().CPlusPlus) return Owned(E); @@ -3209,7 +3209,7 @@ } else if (ObjCMessageExpr *ME = dyn_cast(E)) { if (const ObjCMethodDecl *MD = ME->getMethodDecl()) { if (MD->getResultType()->isReferenceType()) - return Owned(E); + return Owned(E); } } @@ -3251,11 +3251,11 @@ return E; } -ExprResult +ExprResult Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); - + return Owned(MaybeCreateExprWithCleanups(SubExpr.take())); } @@ -3297,7 +3297,7 @@ if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); - + ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Owned(Base); @@ -3311,7 +3311,7 @@ llvm::SmallPtrSet CTypes; llvm::SmallVector Locations; CTypes.insert(Context.getCanonicalType(BaseType)); - + while (BaseType->isRecordType()) { Result = BuildOverloadedArrowExpr(S, Base, OpLoc); if (Result.isInvalid()) @@ -3351,10 +3351,10 @@ // The object type must be complete (or dependent). if (!BaseType->isDependentType() && - RequireCompleteType(OpLoc, BaseType, + RequireCompleteType(OpLoc, BaseType, PDiag(diag::err_incomplete_member_access))) return ExprError(); - + // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an // unqualified-id, and the type of the object expression is of a class @@ -3370,7 +3370,7 @@ Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call) << isa(MemExpr) << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(/*Scope*/ 0, MemExpr, /*LPLoc*/ ExpectedLParenLoc, @@ -3388,11 +3388,11 @@ PseudoDestructorTypeStorage Destructed, bool HasTrailingLParen) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); - + // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { @@ -3404,11 +3404,11 @@ << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } - + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); @@ -3416,7 +3416,7 @@ } // C++ [expr.pseudo]p2: - // [...] The cv-unqualified versions of the object type and of the type + // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); @@ -3427,7 +3427,7 @@ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - + // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, @@ -3435,29 +3435,29 @@ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } - + // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // - // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { - + Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); - + ScopeType = QualType(); ScopeTypeInfo = 0; } } - + Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, @@ -3466,10 +3466,10 @@ CCLoc, TildeLoc, Destructed); - + if (HasTrailingLParen) return Owned(Result); - + return DiagnoseDtorReference(Destructed.getLocation(), Result); } @@ -3490,9 +3490,9 @@ "Invalid second type name in pseudo-destructor"); // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { @@ -3504,7 +3504,7 @@ << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } @@ -3518,32 +3518,32 @@ else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } - - // Convert the name of the type being destructed (following the ~) into a + + // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = 0; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*SecondTypeName.Identifier, + ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, S, &SS, true, ObjectTypePtrForLookup); - if (!T && + if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { - // The name of the type being destroyed is a dependent name, and we + // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { - Diag(SecondTypeName.StartLocation, + Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); - + // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else @@ -3565,8 +3565,8 @@ } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } - - // If we've performed some kind of recovery, (re-)build the type source + + // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) @@ -3574,24 +3574,24 @@ SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } - + // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = 0; QualType ScopeType; - if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*FirstTypeName.Identifier, + ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, S, &SS, false, ObjectTypePtrForLookup); if (!T) { - Diag(FirstTypeName.StartLocation, + Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; - + if (isSFINAEContext()) return ExprError(); - + // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else @@ -3611,15 +3611,15 @@ // Recover by dropping this type. ScopeType = QualType(); } else - ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); + ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } - + if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); - + return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed, HasTrailingLParen); @@ -3631,7 +3631,7 @@ FoundDecl, Method)) return true; - MemberExpr *ME = + MemberExpr *ME = new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, SourceLocation(), Method->getType(), VK_RValue, OK_Ordinary); @@ -3692,7 +3692,7 @@ } ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { - if (!FullExpr) + if (!FullExpr) return ExprError(); if (DiagnoseUnexpandedParameterPack(FullExpr)) Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jan 27 01:10:08 2011 @@ -229,11 +229,11 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, - InitListExpr *ILE, + InitListExpr *ILE, bool &RequiresSecondPass) { SourceLocation Loc = ILE->getSourceRange().getBegin(); unsigned NumInits = ILE->getNumInits(); - InitializedEntity MemberEntity + InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { // FIXME: We probably don't need to handle references @@ -252,7 +252,7 @@ hadError = true; return; } - + InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); @@ -261,14 +261,14 @@ hadError = true; return; } - + ExprResult MemberInit = InitSeq.Perform(SemaRef, MemberEntity, Kind, MultiExprArg()); if (MemberInit.isInvalid()) { hadError = true; return; } - + if (hadError) { // Do nothing } else if (Init < NumInits) { @@ -284,14 +284,14 @@ } } else if (InitListExpr *InnerILE = dyn_cast(ILE->getInit(Init))) - FillInValueInitializations(MemberEntity, InnerILE, - RequiresSecondPass); + FillInValueInitializations(MemberEntity, InnerILE, + RequiresSecondPass); } /// Recursively replaces NULL values within the given initializer list /// with expressions that perform value-initialization of the /// appropriate type. -void +void InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass) { @@ -342,17 +342,17 @@ ElementType = AType->getElementType(); if (const ConstantArrayType *CAType = dyn_cast(AType)) NumElements = CAType->getSize().getZExtValue(); - ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); } else if (const VectorType *VType = ILE->getType()->getAs()) { ElementType = VType->getElementType(); NumElements = VType->getNumElements(); - ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); } else ElementType = ILE->getType(); - + for (unsigned Init = 0; Init != NumElements; ++Init) { if (hadError) return; @@ -407,7 +407,7 @@ unsigned newStructuredIndex = 0; FullyStructuredList = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); - CheckExplicitInitList(Entity, IL, T, newIndex, + CheckExplicitInitList(Entity, IL, T, newIndex, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); @@ -415,7 +415,7 @@ bool RequiresSecondPass = false; FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); if (RequiresSecondPass && !hadError) - FillInValueInitializations(Entity, FullyStructuredList, + FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); } } @@ -480,7 +480,7 @@ // Check the element types and build the structural subobject. unsigned StartIndex = Index; - CheckListElementTypes(Entity, ParentIList, T, + CheckListElementTypes(Entity, ParentIList, T, /*SubobjectIsDesignatorContext=*/false, Index, StructuredSubobjectInitList, StructuredSubobjectInitIndex, @@ -495,16 +495,16 @@ = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); StructuredSubobjectInitList->setRBraceLoc(EndLoc); } - + // Warn about missing braces. if (T->isArrayType() || T->isRecordType()) { SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() - << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), + << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), "{") << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( - StructuredSubobjectInitList->getLocEnd()), + StructuredSubobjectInitList->getLocEnd()), "}"); } } @@ -518,7 +518,7 @@ assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); - CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, + CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); IList->setType(ExprTy); @@ -583,7 +583,7 @@ CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { - CheckVectorType(Entity, IList, DeclType, Index, + CheckVectorType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isAggregateType()) { if (DeclType->isRecordType()) { @@ -596,7 +596,7 @@ llvm::APSInt Zero( SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), false); - CheckArrayType(Entity, IList, DeclType, Zero, + CheckArrayType(Entity, IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); } else @@ -656,7 +656,7 @@ UpdateStructuredListElement(StructuredList, StructuredIndex, Str); ++Index; } else if (ElemType->isScalarType()) { - CheckScalarType(Entity, IList, ElemType, Index, + CheckScalarType(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); } else if (ElemType->isReferenceType()) { CheckReferenceType(Entity, IList, ElemType, Index, @@ -670,17 +670,17 @@ // member, the member is initialized. [...] // FIXME: Better EqualLoc? - InitializationKind Kind = + InitializationKind Kind = InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); - + if (Seq) { - ExprResult Result = + ExprResult Result = Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); if (Result.isInvalid()) hadError = true; - - UpdateStructuredListElement(StructuredList, StructuredIndex, + + UpdateStructuredListElement(StructuredList, StructuredIndex, Result.takeAs()); ++Index; return; @@ -720,7 +720,7 @@ } else { // We cannot initialize this element, so let // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(Entity, SourceLocation(), + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), SemaRef.Owned(expr)); hadError = true; ++Index; @@ -772,7 +772,7 @@ hadError = true; // types weren't compatible. else { ResultExpr = Result.takeAs(); - + if (ResultExpr != expr) { // The type was promoted, update initializer list. IList->setInit(Index, ResultExpr); @@ -859,7 +859,7 @@ hadError = true; // types weren't compatible. else { ResultExpr = Result.takeAs(); - + if (ResultExpr != Init) { // The type was promoted, update initializer list. IList->setInit(Index, ResultExpr); @@ -875,12 +875,12 @@ InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); - + for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - + ElementEntity.setElementIndex(Index); CheckSubElementType(ElementEntity, IList, elementType, Index, StructuredList, StructuredIndex); @@ -890,13 +890,13 @@ InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); - + // OpenCL initializers allows vectors to be constructed from vectors. for (unsigned i = 0; i < maxElements; ++i) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - + ElementEntity.setElementIndex(Index); QualType IType = IList->getInit(Index)->getType(); @@ -908,7 +908,7 @@ QualType VecType; const VectorType *IVT = IType->getAs(); unsigned numIElts = IVT->getNumElements(); - + if (IType->isExtVectorType()) VecType = SemaRef.Context.getExtVectorType(elementType, numIElts); else @@ -1018,7 +1018,7 @@ break; InitializedEntity ElementEntity = - InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, + InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, Entity); // Check this element. CheckSubElementType(ElementEntity, IList, elementType, Index, @@ -1145,7 +1145,7 @@ } // Emit warnings for missing struct field initializers. - if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && + if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { // It is possible we have one or more unnamed bitfields remaining. // Find first (if any) named field and emit warning. @@ -1185,12 +1185,12 @@ InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); - + if (isa(IList->getInit(Index))) - CheckSubElementType(MemberEntity, IList, Field->getType(), Index, + CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); else - CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, + CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); } @@ -1226,7 +1226,7 @@ &Replacements[0] + Replacements.size()); } -/// \brief Given an implicit anonymous field, search the IndirectField that +/// \brief Given an implicit anonymous field, search the IndirectField that /// corresponds to FieldName. static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, IdentifierInfo *FieldName) { @@ -1357,7 +1357,7 @@ for (; Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; - + // If we find a field representing an anonymous field, look in the // IndirectFieldDecl that follow for the designated initializer. if (!KnownField && Field->isAnonymousStructOrUnion()) { @@ -1387,19 +1387,19 @@ if (Lookup.first == Lookup.second) { // Name lookup didn't find anything. Determine whether this // was a typo for another field name. - LookupResult R(SemaRef, FieldName, D->getFieldLoc(), + LookupResult R(SemaRef, FieldName, D->getFieldLoc(), Sema::LookupMemberName); if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, - Sema::CTC_NoKeywords) && + Sema::CTC_NoKeywords) && (ReplacementField = R.getAsSingle()) && ReplacementField->getDeclContext()->getRedeclContext() ->Equals(RT->getDecl())) { - SemaRef.Diag(D->getFieldLoc(), + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) << FieldName << CurrentObjectType << R.getLookupName() << FixItHint::CreateReplacement(D->getFieldLoc(), R.getLookupName().getAsString()); - SemaRef.Diag(ReplacementField->getLocation(), + SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << ReplacementField->getDeclName(); } else { @@ -1409,7 +1409,7 @@ return true; } } - + if (!ReplacementField) { // Name lookup found something, but it wasn't a field. SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) @@ -1429,7 +1429,7 @@ if (Field->isUnnamedBitfield()) continue; - if (ReplacementField == *Field || + if (ReplacementField == *Field || Field->getIdentifier() == ReplacementField->getIdentifier()) break; @@ -1521,11 +1521,11 @@ // Recurse to check later designated subobjects. QualType FieldType = (*Field)->getType(); unsigned newStructuredIndex = FieldIndex; - + InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); - if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, - FieldType, 0, 0, Index, + if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, + FieldType, 0, 0, Index, StructuredList, newStructuredIndex, true, false)) return true; @@ -1554,7 +1554,7 @@ // Check the remaining fields within this class/struct/union subobject. bool prevHadError = hadError; - + CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index, StructuredList, FieldIndex); return hadError && !prevHadError; @@ -1644,7 +1644,7 @@ // Move to the next designator unsigned ElementIndex = DesignatedStartIndex.getZExtValue(); unsigned OldIndex = Index; - + InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); @@ -1652,10 +1652,10 @@ // Recurse to check later designated subobjects. QualType ElementType = AT->getElementType(); Index = OldIndex; - + ElementEntity.setElementIndex(ElementIndex); - if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, - ElementType, 0, 0, Index, + if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, + ElementType, 0, 0, Index, StructuredList, ElementIndex, (DesignatedStartIndex == DesignatedEndIndex), false)) @@ -1680,7 +1680,7 @@ // Check the remaining elements within this array subobject. bool prevHadError = hadError; - CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, + CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, /*SubobjectIsDesignatorContext=*/false, Index, StructuredList, ElementIndex); return hadError && !prevHadError; @@ -1913,11 +1913,11 @@ Designators.data(), Designators.size(), InitExpressions.data(), InitExpressions.size(), Loc, GNUSyntax, Init.takeAs()); - + if (getLangOptions().CPlusPlus) Diag(DIE->getLocStart(), diag::ext_designated_init) << DIE->getSourceRange(); - + return Owned(DIE); } @@ -1934,9 +1934,9 @@ // Initialization entity //===----------------------------------------------------------------------===// -InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, +InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) - : Parent(&Parent), Index(Index) + : Parent(&Parent), Index(Index) { if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { Kind = EK_ArrayElement; @@ -1947,7 +1947,7 @@ } } -InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base, bool IsInheritedVirtualBase) { @@ -1956,7 +1956,7 @@ Result.Base = reinterpret_cast(Base); if (IsInheritedVirtualBase) Result.Base |= 0x01; - + Result.Type = Base->getType(); return Result; } @@ -1982,7 +1982,7 @@ case EK_BlockElement: return DeclarationName(); } - + // Silence GCC warning return DeclarationName(); } @@ -2004,7 +2004,7 @@ case EK_BlockElement: return 0; } - + // Silence GCC warning return 0; } @@ -2014,7 +2014,7 @@ case EK_Result: case EK_Exception: return LocAndNRVO.NRVO; - + case EK_Variable: case EK_Parameter: case EK_Member: @@ -2054,7 +2054,7 @@ case SK_StringInit: case SK_ObjCObjectConversion: break; - + case SK_ConversionSequence: delete ICS; } @@ -2067,7 +2067,7 @@ bool InitializationSequence::isAmbiguous() const { if (getKind() != FailedSequence) return false; - + switch (getFailureKind()) { case FK_TooManyInitsForReference: case FK_ArrayNeedsInitList: @@ -2085,13 +2085,13 @@ case FK_DefaultInitOfConst: case FK_Incomplete: return false; - + case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: case FK_ConstructorOverloadFailed: return FailedOverloadResult == OR_Ambiguous; } - + return false; } @@ -2110,7 +2110,7 @@ Steps.push_back(S); } -void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, ExprValueKind VK) { Step S; switch (VK) { @@ -2123,7 +2123,7 @@ Steps.push_back(S); } -void InitializationSequence::AddReferenceBindingStep(QualType T, +void InitializationSequence::AddReferenceBindingStep(QualType T, bool BindingTemporary) { Step S; S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; @@ -2185,7 +2185,7 @@ Steps.push_back(S); } -void +void InitializationSequence::AddConstructorInitializationStep( CXXConstructorDecl *Constructor, AccessSpecifier Access, @@ -2226,7 +2226,7 @@ Steps.push_back(S); } -void InitializationSequence::SetOverloadFailure(FailureKind Failure, +void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; this->Failure = Failure; @@ -2237,8 +2237,8 @@ // Attempt initialization //===----------------------------------------------------------------------===// -/// \brief Attempt list initialization (C++0x [dcl.init.list]) -static void TryListInitialization(Sema &S, +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, @@ -2254,7 +2254,7 @@ QualType DestType = Entity.getType(); // C++ [dcl.init]p13: - // If T is a scalar type, then a declaration of the form + // If T is a scalar type, then a declaration of the form // // T x = { a }; // @@ -2301,7 +2301,7 @@ bool DerivedToBase; bool ObjCConversion; - assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), T1, T2, DerivedToBase, ObjCConversion) && "Must have incompatible references when binding via conversion"); @@ -2316,7 +2316,7 @@ // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; - + const RecordType *T1RecordType = 0; if (AllowRValues && (T1RecordType = T1->getAs()) && !S.RequireCompleteType(Kind.getLocation(), T1, 0)) { @@ -2338,7 +2338,7 @@ ConstructorTmpl->getTemplatedDecl()); else Constructor = cast(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) @@ -2351,11 +2351,11 @@ &Initializer, 1, CandidateSet, /*SuppressUserConversions=*/true); } - } + } } if (T1RecordType && T1RecordType->getDecl()->isInvalidDecl()) return OR_No_Viable_Function; - + const RecordType *T2RecordType = 0; if ((T2RecordType = T2->getAs()) && !S.RequireCompleteType(Kind.getLocation(), T2, 0)) { @@ -2371,19 +2371,19 @@ CXXRecordDecl *ActingDC = cast(D->getDeclContext()); if (isa(D)) D = cast(D)->getTargetDecl(); - + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else Conv = cast(D); - + // If the conversion function doesn't return a reference type, // it can't be considered for this conversion unless we're allowed to // consider rvalues. - // FIXME: Do we need to make sure that we only consider conversion - // candidates with reference-compatible results? That might be needed to + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to // break recursion. if ((AllowExplicit || !Conv->isExplicit()) && (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ @@ -2399,12 +2399,12 @@ } if (T2RecordType && T2RecordType->getDecl()->isInvalidDecl()) return OR_No_Viable_Function; - + SourceLocation DeclLoc = Initializer->getLocStart(); - // Perform overload resolution. If it fails, return the failed result. + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) return Result; @@ -2420,7 +2420,7 @@ Sequence.AddUserConversionStep(Function, Best->FoundDecl, T2.getNonLValueExprType(S.Context)); - // Determine whether we need to perform derived-to-base or + // Determine whether we need to perform derived-to-base or // cv-qualification adjustments. ExprValueKind VK = VK_RValue; if (T2->isLValueReferenceType()) @@ -2431,7 +2431,7 @@ bool NewDerivedToBase = false; bool NewObjCConversion = false; Sema::ReferenceCompareResult NewRefRelationship - = S.CompareReferenceRelationship(DeclLoc, T1, + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonLValueExprType(S.Context), NewDerivedToBase, NewObjCConversion); if (NewRefRelationship == Sema::Ref_Incompatible) { @@ -2447,7 +2447,7 @@ } else if (NewDerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, - T2.getNonReferenceType().getQualifiers()), + T2.getNonReferenceType().getQualifiers()), VK); else if (NewObjCConversion) Sequence.AddObjCObjectConversionStep( @@ -2456,13 +2456,13 @@ if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) Sequence.AddQualificationConversionStep(cv1T1, VK); - + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); return OR_Success; } - -/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) -static void TryReferenceInitialization(Sema &S, + +/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) +static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, @@ -2483,7 +2483,7 @@ // type of the resulting function. if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { DeclAccessPair Found; - if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, T1, false, Found)) { @@ -2507,10 +2507,10 @@ ObjCConversion); // C++0x [dcl.init.ref]p5: - // A reference to type "cv1 T1" is initialized by an expression of type + // A reference to type "cv1 T1" is initialized by an expression of type // "cv2 T2" as follows: // - // - If the reference is an lvalue reference and the initializer + // - If the reference is an lvalue reference and the initializer // expression // Note the analogous bullet points for rvlaue refs to functions. Because // there are no function rvalues in C++, rvalue refs to functions are treated @@ -2518,21 +2518,21 @@ OverloadingResult ConvOvlResult = OR_Success; bool T1Function = T1->isFunctionType(); if (isLValueRef || T1Function) { - if (InitCategory.isLValue() && + if (InitCategory.isLValue() && (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || - (Kind.isCStyleOrFunctionalCast() && + (Kind.isCStyleOrFunctionalCast() && RefRelationship == Sema::Ref_Related))) { - // - is an lvalue (but is not a bit-field), and "cv1 T1" is + // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // - // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a + // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a // bit-field when we're determining whether the reference initialization // can occur. However, we do pay attention to whether it is a bit-field // to decide whether we're actually binding to a temporary created from // the bit-field. if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, T2Quals), + S.Context.getQualifiedType(T1, T2Quals), VK_LValue); else if (ObjCConversion) Sequence.AddObjCObjectConversionStep( @@ -2545,18 +2545,18 @@ Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); return; } - - // - has a class type (i.e., T2 is a class type), where T1 is not - // reference-related to T2, and can be implicitly converted to an - // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible - // with "cv3 T3" (this conversion is selected by enumerating the + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (this conversion is selected by enumerating the // applicable conversion functions (13.3.1.6) and choosing the best // one through overload resolution (13.3)), // If we have an rvalue ref to function type here, the rhs must be // an rvalue. if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && (isLValueRef || InitCategory.isRValue())) { - ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, Initializer, /*AllowRValues=*/isRValueRef, Sequence); @@ -2570,7 +2570,7 @@ } } - // - Otherwise, the reference shall be an lvalue reference to a + // - Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile())) { @@ -2596,7 +2596,7 @@ // Note: functions are handled below. if (!T1Function && (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || - (Kind.isCStyleOrFunctionalCast() && + (Kind.isCStyleOrFunctionalCast() && RefRelationship == Sema::Ref_Related)) && (InitCategory.isXValue() || (InitCategory.isPRValue() && T2->isRecordType()) || @@ -2615,23 +2615,23 @@ if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft) Sequence.AddExtraneousCopyToTemporary(cv2T2); } - + if (DerivedToBase) Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals), ValueKind); else if (ObjCConversion) Sequence.AddObjCObjectConversionStep( S.Context.getQualifiedType(T1, T2Quals)); - + if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, ValueKind); - Sequence.AddReferenceBindingStep(cv1T1, + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/(InitCategory.isPRValue() && !T2->isArrayType())); - return; + return; } - - // - has a class type (i.e., T2 is a class type), where T1 is not - // reference-related to T2, and can be implicitly converted to an + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an // xvalue, class prvalue, or function lvalue of type "cv3 T3", // where "cv1 T1" is reference-compatible with "cv3 T3", if (T2->isRecordType()) { @@ -2644,17 +2644,17 @@ Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); - + return; } - + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } // - Otherwise, a temporary of type "cv1 T1" is created and initialized // from the initializer expression using the rules for a non-reference - // copy initialization (8.5). The reference is then bound to the + // copy initialization (8.5). The reference is then bound to the // temporary. [...] // Determine whether we are allowed to call explicit constructors or @@ -2688,28 +2688,28 @@ // than, cv2; otherwise, the program is ill-formed. unsigned T1CVRQuals = T1Quals.getCVRQualifiers(); unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); - if (RefRelationship == Sema::Ref_Related && + if (RefRelationship == Sema::Ref_Related && (T1CVRQuals | T2CVRQuals) != T1CVRQuals) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } - // [...] If T1 is reference-related to T2 and the reference is an rvalue + // [...] If T1 is reference-related to T2 and the reference is an rvalue // reference, the initializer expression shall not be an lvalue. - if (RefRelationship >= Sema::Ref_Related && !isLValueRef && + if (RefRelationship >= Sema::Ref_Related && !isLValueRef && InitCategory.isLValue()) { Sequence.SetFailed( InitializationSequence::FK_RValueReferenceBindingToLValue); return; } - + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); return; } /// \brief Attempt character array initialization from a string literal -/// (C++ [dcl.init.string], C99 6.7.8). -static void TryStringLiteralInitialization(Sema &S, +/// (C++ [dcl.init.string], C99 6.7.8). +static void TryStringLiteralInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, @@ -2721,19 +2721,19 @@ /// \brief Attempt initialization by constructor (C++ [dcl.init]), which /// enumerates the constructors of the initialized entity and performs overload /// resolution to select the best. -static void TryConstructorInitialization(Sema &S, +static void TryConstructorInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); - + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); CandidateSet.clear(); - + // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || @@ -2745,21 +2745,21 @@ Sequence.SetFailed(InitializationSequence::FK_Incomplete); return; } - + // The type we're converting to is a class type. Enumerate its constructors // to see if one is suitable. const RecordType *DestRecordType = DestType->getAs(); - assert(DestRecordType && "Constructor initialization requires record type"); + assert(DestRecordType && "Constructor initialization requires record type"); CXXRecordDecl *DestRecordDecl = cast(DestRecordType->getDecl()); - + DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); bool SuppressUserConversions = false; - + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl = dyn_cast(D); @@ -2769,14 +2769,14 @@ else { Constructor = cast(D); - // If we're performing copy initialization using a copy constructor, we + // If we're performing copy initialization using a copy constructor, we // suppress user-defined conversions on the arguments. // FIXME: Move constructors? if (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isCopyConstructor()) SuppressUserConversions = true; } - + if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) @@ -2789,16 +2789,16 @@ Args, NumArgs, CandidateSet, SuppressUserConversions); } - } - + } + SourceLocation DeclLoc = Kind.getLocation(); - - // Perform overload resolution. If it fails, return the failed result. + + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( - InitializationSequence::FK_ConstructorOverloadFailed, + InitializationSequence::FK_ConstructorOverloadFailed, Result); return; } @@ -2817,13 +2817,13 @@ // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. Sequence.AddConstructorInitializationStep( - cast(Best->Function), + cast(Best->Function), Best->FoundDecl.getAccess(), DestType); } /// \brief Attempt value initialization (C++ [dcl.init]p7). -static void TryValueInitialization(Sema &S, +static void TryValueInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitializationSequence &Sequence) { @@ -2831,11 +2831,11 @@ // // To value-initialize an object of type T means: QualType T = Entity.getType(); - + // -- if T is an array type, then each element is value-initialized; while (const ArrayType *AT = S.Context.getAsArrayType(T)) T = AT->getElementType(); - + if (const RecordType *RT = T->getAs()) { if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { // -- if T is a class type (clause 9) with a user-declared @@ -2847,7 +2847,7 @@ // but Entity doesn't have a way to capture that (yet). if (ClassDecl->hasUserDeclaredConstructor()) return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); - + // -- if T is a (possibly cv-qualified) non-union class type // without a user-provided constructor, then the object is // zero-initialized and, if T's implicitly-declared default @@ -2855,7 +2855,7 @@ if ((ClassDecl->getTagKind() == TTK_Class || ClassDecl->getTagKind() == TTK_Struct)) { Sequence.AddZeroInitializationStep(Entity.getType()); - return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); } } } @@ -2870,14 +2870,14 @@ const InitializationKind &Kind, InitializationSequence &Sequence) { assert(Kind.getKind() == InitializationKind::IK_Default); - + // C++ [dcl.init]p6: // To default-initialize an object of type T means: // - if T is an array type, each element is default-initialized; QualType DestType = Entity.getType(); while (const ArrayType *Array = S.Context.getAsArrayType(DestType)) DestType = Array->getElementType(); - + // - if T is a (possibly cv-qualified) class type (Clause 9), the default // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); @@ -2885,12 +2885,12 @@ TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); return; } - + // - otherwise, no initialization is performed. Sequence.setSequenceKind(InitializationSequence::NoInitialization); - + // If a program calls for the default initialization of an object of - // a const-qualified type T, T shall be a class type with a user-provided + // a const-qualified type T, T shall be a class type with a user-provided // default constructor. if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); @@ -2899,42 +2899,42 @@ /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), /// which enumerates all conversion functions and performs overload resolution /// to select the best. -static void TryUserDefinedConversion(Sema &S, +static void TryUserDefinedConversion(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); - + QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); assert((DestType->isRecordType() || SourceType->isRecordType()) && "Must have a class type to perform a user-defined conversion"); - + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); CandidateSet.clear(); - + // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; - + if (const RecordType *DestRecordType = DestType->getAs()) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. CXXRecordDecl *DestRecordDecl = cast(DestRecordType->getDecl()); - + // Try to complete the type we're converting to. - if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl @@ -2944,7 +2944,7 @@ ConstructorTmpl->getTemplatedDecl()); else Constructor = cast(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) @@ -2957,7 +2957,7 @@ &Initializer, 1, CandidateSet, /*SuppressUserConversions=*/true); } - } + } } } @@ -2972,24 +2972,24 @@ if (!S.RequireCompleteType(DeclLoc, SourceType, 0)) { CXXRecordDecl *SourceRecordDecl = cast(SourceRecordType->getDecl()); - + const UnresolvedSetImpl *Conversions = SourceRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), - E = Conversions->end(); + E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast(D->getDeclContext()); if (isa(D)) D = cast(D)->getTargetDecl(); - + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else Conv = cast(D); - + if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), @@ -3002,19 +3002,19 @@ } } } - - // Perform overload resolution. If it fails, return the failed result. + + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { Sequence.SetOverloadFailure( - InitializationSequence::FK_UserConversionOverloadFailed, + InitializationSequence::FK_UserConversionOverloadFailed, Result); return; } FunctionDecl *Function = Best->Function; - + if (isa(Function)) { // Add the user-defined conversion step. Any cv-qualification conversion is // subsumed by the initialization. @@ -3036,7 +3036,7 @@ } Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); - + // If the conversion following the call to the conversion function // is interesting, add it as a separate step. if (Best->FinalConversion.First || Best->FinalConversion.Second || @@ -3055,12 +3055,12 @@ unsigned NumArgs) : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; - + // C++0x [dcl.init]p16: - // The semantics of initializers are as follows. The destination type is - // the type of the object or reference being initialized and the source + // The semantics of initializers are as follows. The destination type is + // the type of the object or reference being initialized and the source // type is the type of the initializer expression. The source type is not - // defined when the initializer is a braced-init-list or when it is a + // defined when the initializer is a braced-init-list or when it is a // parenthesized list of expressions. QualType DestType = Entity.getType(); @@ -3081,14 +3081,14 @@ if (!isa(Initializer)) SourceType = Initializer->getType(); } - - // - If the initializer is a braced-init-list, the object is + + // - If the initializer is a braced-init-list, the object is // list-initialized (8.5.4). if (InitListExpr *InitList = dyn_cast_or_null(Initializer)) { TryListInitialization(S, Entity, Kind, InitList, *this); return; } - + // - If the destination type is a reference type, see 8.5.3. if (DestType->isReferenceType()) { // C++0x [dcl.init.ref]p1: @@ -3102,36 +3102,36 @@ TryReferenceInitialization(S, Entity, Kind, Args[0], *this); return; } - - // - If the destination type is an array of characters, an array of - // char16_t, an array of char32_t, or an array of wchar_t, and the + + // - If the destination type is an array of characters, an array of + // char16_t, an array of char32_t, or an array of wchar_t, and the // initializer is a string literal, see 8.5.2. if (Initializer && IsStringInit(Initializer, DestType, Context)) { TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); return; } - + // - If the initializer is (), the object is value-initialized. if (Kind.getKind() == InitializationKind::IK_Value || (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { TryValueInitialization(S, Entity, Kind, *this); return; } - + // Handle default initialization. if (Kind.getKind() == InitializationKind::IK_Default) { TryDefaultInitialization(S, Entity, Kind, *this); return; } - // - Otherwise, if the destination type is an array, the program is + // - Otherwise, if the destination type is an array, the program is // ill-formed. if (const ArrayType *AT = Context.getAsArrayType(DestType)) { if (AT->getElementType()->isAnyCharacterType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); else SetFailed(FK_ArrayNeedsInitList); - + return; } @@ -3141,22 +3141,22 @@ AddCAssignmentStep(DestType); return; } - + // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { - // - If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the + // - If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the // class of the destination, constructors are considered. [...] if (Kind.getKind() == InitializationKind::IK_Direct || (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) - TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, Entity.getType(), *this); - // - Otherwise (i.e., for the remaining copy-initialization cases), + // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source - // type to the destination type or (when a conversion function is + // type to the destination type or (when a conversion function is // used) to a derived class thereof are enumerated as described in // 13.3.1.4, and the best one is chosen through overload resolution // (13.3). @@ -3164,24 +3164,24 @@ TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } - + if (NumArgs > 1) { SetFailed(FK_TooManyInitsForScalar); return; } assert(NumArgs == 1 && "Zero-argument case handled above"); - - // - Otherwise, if the source type is a (possibly cv-qualified) class + + // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } - + // - Otherwise, the initial value of the object being initialized is the // (possibly converted) value of the initializer expression. Standard // conversions (Clause 4) will be used, if necessary, to convert the - // initializer expression to the cv-unqualified version of the + // initializer expression to the cv-unqualified version of the // destination type; no user-defined conversions are considered. if (S.TryImplicitConversion(*this, Entity, Initializer, /*SuppressUserConversions*/ true, @@ -3208,7 +3208,7 @@ //===----------------------------------------------------------------------===// // Perform initialization //===----------------------------------------------------------------------===// -static Sema::AssignmentAction +static Sema::AssignmentAction getAssignmentAction(const InitializedEntity &Entity) { switch(Entity.getKind()) { case InitializedEntity::EK_Variable: @@ -3218,7 +3218,7 @@ return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: - if (Entity.getDecl() && + if (Entity.getDecl() && isa(Entity.getDecl()->getDeclContext())) return Sema::AA_Sending; @@ -3230,7 +3230,7 @@ case InitializedEntity::EK_Temporary: // FIXME: Can we tell apart casting vs. converting? return Sema::AA_Casting; - + case InitializedEntity::EK_Member: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: @@ -3255,12 +3255,12 @@ case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: return false; - + case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: return true; } - + llvm_unreachable("missed an InitializedEntity kind?"); } @@ -3275,7 +3275,7 @@ case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: return false; - + case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: @@ -3283,8 +3283,8 @@ case InitializedEntity::EK_Exception: return true; } - - llvm_unreachable("missed an InitializedEntity kind?"); + + llvm_unreachable("missed an InitializedEntity kind?"); } /// \brief Make a (potentially elidable) temporary copy of the object @@ -3314,7 +3314,7 @@ bool IsExtraneousCopy) { // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); - CXXRecordDecl *Class = 0; + CXXRecordDecl *Class = 0; if (const RecordType *Record = T->getAs()) Class = cast(Record->getDecl()); if (!Class) @@ -3330,10 +3330,10 @@ // with the same cv-unqualified type, the copy/move operation // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move - // + // // Note that the other three bullets are handled elsewhere. Copy // elision for return statements and throw expressions are handled as part - // of constructor initialization, while copy elision for exception handlers + // of constructor initialization, while copy elision for exception handlers // is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject(S.Context, Class); SourceLocation Loc; @@ -3341,11 +3341,11 @@ case InitializedEntity::EK_Result: Loc = Entity.getReturnLoc(); break; - + case InitializedEntity::EK_Exception: Loc = Entity.getThrowLoc(); break; - + case InitializedEntity::EK_Variable: Loc = Entity.getDecl()->getLocation(); break; @@ -3362,7 +3362,7 @@ break; } - // Make sure that the type we are copying is complete. + // Make sure that the type we are copying is complete. if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete))) return move(CurInit); @@ -3388,7 +3388,7 @@ S.AddOverloadCandidate(Constructor, FoundDecl, &CurInitExpr, 1, CandidateSet); continue; - } + } // Handle constructor templates. FunctionTemplateDecl *ConstructorTmpl = cast(*Con); @@ -3407,12 +3407,12 @@ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0, &CurInitExpr, 1, CandidateSet, true); } - + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, Loc, Best)) { case OR_Success: break; - + case OR_No_Viable_Function: S.Diag(Loc, IsExtraneousCopy && !S.isSFINAEContext() ? diag::ext_rvalue_to_reference_temp_copy_no_viable @@ -3423,14 +3423,14 @@ if (!IsExtraneousCopy || S.isSFINAEContext()) return ExprError(); return move(CurInit); - + case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); CandidateSet.NoteCandidates(S, OCD_ViableCandidates, &CurInitExpr, 1); return ExprError(); - + case OR_Deleted: S.Diag(Loc, diag::err_temp_copy_deleted) << (int)Entity.getKind() << CurInitExpr->getType() @@ -3472,7 +3472,7 @@ return S.Owned(CurInitExpr); } - + // Determine the arguments required to actually perform the // constructor call (we might have derived-to-base conversions, or // the copy constructor may have default arguments). @@ -3486,7 +3486,7 @@ /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); - + // If we're supposed to bind temporaries, do so. if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); @@ -3507,7 +3507,7 @@ } } -ExprResult +ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -3518,7 +3518,7 @@ Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); return ExprError(); } - + if (SequenceKind == DependentSequence) { // If the declaration is a non-dependent, incomplete array type // that has an initializer, then its type will be completed once @@ -3568,14 +3568,14 @@ unsigned NumArgs = Args.size(); return S.Owned(new (S.Context) ParenListExpr(S.Context, SourceLocation(), - (Expr **)Args.release(), + (Expr **)Args.release(), NumArgs, SourceLocation())); } if (SequenceKind == NoInitialization) return S.Owned((Expr *)0); - + QualType DestType = Entity.getType().getNonReferenceType(); // FIXME: Ugly hack around the fact that Entity.getType() is not // the same as Entity.getDecl()->getType() in cases involving type merging, @@ -3585,10 +3585,10 @@ Entity.getType(); ExprResult CurInit = S.Owned((Expr *)0); - + assert(!Steps.empty() && "Cannot have an empty initialization sequence"); - - // For initialization steps that start with a single initializer, + + // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" // initializer. switch (Steps.front().Kind) { @@ -3619,26 +3619,26 @@ CurInit = ExprResult(CurInitExpr); break; } - + case SK_ConstructorInitialization: case SK_ZeroInitialization: break; } - - // Walk through the computed steps for the initialization sequence, + + // Walk through the computed steps for the initialization sequence, // performing the specified conversions along the way. bool ConstructorInitRequiresZeroInit = false; for (step_iterator Step = step_begin(), StepEnd = step_end(); Step != StepEnd; ++Step) { if (CurInit.isInvalid()) return ExprError(); - + Expr *CurInitExpr = CurInit.get(); QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); - + switch (Step->Kind) { case SK_ResolveAddressOfOverloadedFunction: - // Overload resolution determined which function invoke; update the + // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); @@ -3646,29 +3646,29 @@ Step->Function.FoundDecl, Step->Function.Function); break; - + case SK_CastDerivedToBaseRValue: case SK_CastDerivedToBaseXValue: case SK_CastDerivedToBaseLValue: { // We have a derived-to-base cast that produces either an rvalue or an // lvalue. Perform that cast. - + CXXCastPath BasePath; // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, CurInitExpr->getLocStart(), - CurInitExpr->getSourceRange(), + CurInitExpr->getSourceRange(), &BasePath, IgnoreBaseAccess)) return ExprError(); - + if (S.BasePathInvolvesVirtualBase(BasePath)) { QualType T = SourceType; if (const PointerType *Pointer = T->getAs()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs()) - S.MarkVTableUsed(CurInitExpr->getLocStart(), + S.MarkVTableUsed(CurInitExpr->getLocStart(), cast(RecordTy->getDecl())); } @@ -3685,7 +3685,7 @@ &BasePath, VK)); break; } - + case SK_BindReference: if (FieldDecl *BitField = CurInitExpr->getBitField()) { // References cannot bind to bit fields (C++ [dcl.init.ref]p5). @@ -3705,7 +3705,7 @@ PrintInitLocationNote(S, Entity); return ExprError(); } - + // Reference binding does not have any corresponding ASTs. // Check exception specifications @@ -3722,9 +3722,9 @@ return ExprError(); break; - + case SK_ExtraneousCopyToTemporary: - CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), /*IsExtraneousCopy=*/true); break; @@ -3749,9 +3749,9 @@ MultiExprArg(&CurInitExpr, 1), Loc, ConstructorArgs)) return ExprError(); - + // Build the an expression that constructs a temporary. - CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, move_arg(ConstructorArgs), /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, @@ -3762,13 +3762,13 @@ S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); - + CastKind = CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) IsCopy = true; - + CreatedObject = true; } else { // Build a call to the conversion function. @@ -3777,8 +3777,8 @@ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); - - // FIXME: Should we move this initialization into a separate + + // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, @@ -3788,18 +3788,18 @@ // Do a little dance to make sure that CurInit has the proper // pointer. CurInit.release(); - + // Build the actual call to the conversion function. CurInit = S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, Conversion); if (CurInit.isInvalid() || !CurInit.get()) return ExprError(); - + CastKind = CK_UserDefinedConversion; - + CreatedObject = Conversion->getResultType()->isRecordType(); } - - bool RequiresCopy = !IsCopy && + + bool RequiresCopy = !IsCopy && getKind() != InitializationSequence::ReferenceBinding; if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); @@ -3807,22 +3807,22 @@ CurInitExpr = static_cast(CurInit.get()); QualType T = CurInitExpr->getType(); if (const RecordType *Record = T->getAs()) { - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = S.LookupDestructor(cast(Record->getDecl())); - S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart()); } } - + CurInitExpr = CurInit.takeAs(); // FIXME: xvalues CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, CurInitExpr->getType(), CastKind, CurInitExpr, 0, IsLvalue ? VK_LValue : VK_RValue)); - + if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, move(CurInit), /*IsExtraneousCopy=*/false); @@ -3851,12 +3851,12 @@ getAssignmentAction(Entity), Kind.isCStyleOrFunctionalCast())) return ExprError(); - + CurInit.release(); CurInit = S.Owned(CurInitExpr); break; } - + case SK_ListInitialization: { InitListExpr *InitList = cast(CurInitExpr); QualType Ty = Step->Type; @@ -3872,7 +3872,7 @@ unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast(Step->Function.Function); - + // Build a call to the selected constructor. ASTOwningVector ConstructorArgs(S); SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) @@ -3892,11 +3892,11 @@ // Determine the arguments required to actually perform the constructor // call. - if (S.CompleteConstructorCall(Constructor, move(Args), + if (S.CompleteConstructorCall(Constructor, move(Args), Loc, ConstructorArgs)) return ExprError(); - - + + if (Entity.getKind() == InitializedEntity::EK_Temporary && NumArgs != 1 && // FIXME: Hack to work around cast weirdness (Kind.getKind() == InitializationKind::IK_Direct || @@ -3906,28 +3906,28 @@ Expr **Exprs = (Expr **)ConstructorArgs.take(); S.MarkDeclarationReferenced(Loc, Constructor); S.DiagnoseUseOfDecl(Constructor, Loc); - + TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); - + CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor, TSInfo, - Exprs, + Exprs, NumExprs, Kind.getParenRange(), ConstructorInitRequiresZeroInit)); } else { CXXConstructExpr::ConstructionKind ConstructKind = CXXConstructExpr::CK_Complete; - + if (Entity.getKind() == InitializedEntity::EK_Base) { ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? - CXXConstructExpr::CK_VirtualBase : + CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; - } - + } + // Only get the parenthesis range if it is a direct construction. SourceRange parenRange = Kind.getKind() == InitializationKind::IK_Direct ? @@ -3944,7 +3944,7 @@ parenRange); else CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, + Constructor, move_arg(ConstructorArgs), ConstructorInitRequiresZeroInit, ConstructKind, @@ -3957,17 +3957,17 @@ S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc); - + if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); - + break; } - + case SK_ZeroInitialization: { step_iterator NextStep = Step; ++NextStep; - if (NextStep != StepEnd && + if (NextStep != StepEnd && NextStep->Kind == SK_ConstructorInitialization) { // The need for zero-initialization is recorded directly into // the call to the object's constructor within the next step. @@ -3977,7 +3977,7 @@ !Kind.isImplicitValueInit()) { TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) - TSInfo = S.Context.getTrivialTypeSourceInfo(Step->Type, + TSInfo = S.Context.getTrivialTypeSourceInfo(Step->Type, Kind.getRange().getBegin()); CurInit = S.Owned(new (S.Context) CXXScalarValueInitExpr( @@ -4005,7 +4005,7 @@ bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInitExpr, + CurInitExpr, getAssignmentAction(Entity), &Complained)) { PrintInitLocationNote(S, Entity); @@ -4025,7 +4025,7 @@ } case SK_ObjCObjectConversion: - S.ImpCastExprToType(CurInitExpr, Step->Type, + S.ImpCastExprToType(CurInitExpr, Step->Type, CK_ObjCObjectLValueCast, S.CastCategory(CurInitExpr)); CurInit.release(); @@ -4040,20 +4040,20 @@ S.CheckBitFieldInitialization(Kind.getLocation(), cast(Entity.getDecl()), CurInit.get()); - + return move(CurInit); } //===----------------------------------------------------------------------===// // Diagnose initialization failures //===----------------------------------------------------------------------===// -bool InitializationSequence::Diagnose(Sema &S, +bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs) { if (SequenceKind != FailedSequence) return false; - + QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: @@ -4065,22 +4065,22 @@ S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); break; - + case FK_ArrayNeedsInitList: case FK_ArrayNeedsInitListOrStringLiteral: S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << (Failure == FK_ArrayNeedsInitListOrStringLiteral); break; - + case FK_AddressOfOverloadFailed: { DeclAccessPair Found; - S.ResolveAddressOfOverloadedFunction(Args[0], + S.ResolveAddressOfOverloadedFunction(Args[0], DestType.getNonReferenceType(), true, Found); break; } - + case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { @@ -4096,14 +4096,14 @@ FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs); break; - + case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; - + case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) << Args[0]->getType() << DestType.getNonReferenceType() @@ -4120,16 +4120,16 @@ } break; } - + case OR_Success: llvm_unreachable("Conversion did not fail!"); break; } break; - + case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToUnrelated: - S.Diag(Kind.getLocation(), + S.Diag(Kind.getLocation(), Failure == FK_NonConstLValueReferenceBindingToTemporary ? diag::err_lvalue_reference_bind_to_temporary : diag::err_lvalue_reference_bind_to_unrelated) @@ -4138,20 +4138,20 @@ << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_ReferenceInitDropsQualifiers: S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_ReferenceInitFailed: S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) << DestType.getNonReferenceType() @@ -4159,7 +4159,7 @@ << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_ConversionFailed: S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) << (int)Entity.getKind() @@ -4175,7 +4175,7 @@ if (InitListExpr *InitList = dyn_cast(Args[0])) R = SourceRange(InitList->getInit(0)->getLocEnd(), InitList->getLocEnd()); - else + else R = SourceRange(Args[0]->getLocEnd(), Args[NumArgs - 1]->getLocEnd()); R.setBegin(S.PP.getLocForEndOfToken(R.getBegin())); @@ -4197,13 +4197,13 @@ S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); break; - + case FK_ConstructorOverloadFailed: { SourceRange ArgsRange; if (NumArgs) - ArgsRange = SourceRange(Args[0]->getLocStart(), + ArgsRange = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); - + // FIXME: Using "DestType" for the entity we're printing is probably // bad. switch (FailedOverloadResult) { @@ -4213,7 +4213,7 @@ FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs); break; - + case OR_No_Viable_Function: if (Kind.getKind() == InitializationKind::IK_Default && (Entity.getKind() == InitializedEntity::EK_Base || @@ -4247,7 +4247,7 @@ if (const RecordType *Record = Entity.getType()->getAs()) - S.Diag(Record->getDecl()->getLocation(), + S.Diag(Record->getDecl()->getLocation(), diag::note_previous_decl) << S.Context.getTagDeclType(Record->getDecl()); } @@ -4258,7 +4258,7 @@ << DestType << ArgsRange; FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; - + case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) << true << DestType << ArgsRange; @@ -4273,14 +4273,14 @@ } break; } - + case OR_Success: llvm_unreachable("Conversion did not fail!"); break; } break; } - + case FK_DefaultInitOfConst: if (Entity.getKind() == InitializedEntity::EK_Member && isa(S.CurContext)) { @@ -4300,13 +4300,13 @@ << DestType << (bool)DestType->getAs(); } break; - + case FK_Incomplete: - S.RequireCompleteType(Kind.getLocation(), DestType, + S.RequireCompleteType(Kind.getLocation(), DestType, diag::err_init_incomplete_type); - break; + break; } - + PrintInitLocationNote(S, Entity); return true; } @@ -4319,95 +4319,95 @@ case FK_TooManyInitsForReference: OS << "too many initializers for reference"; break; - + case FK_ArrayNeedsInitList: OS << "array requires initializer list"; break; - + case FK_ArrayNeedsInitListOrStringLiteral: OS << "array requires initializer list or string literal"; break; - + case FK_AddressOfOverloadFailed: OS << "address of overloaded function failed"; break; - + case FK_ReferenceInitOverloadFailed: OS << "overload resolution for reference initialization failed"; break; - + case FK_NonConstLValueReferenceBindingToTemporary: OS << "non-const lvalue reference bound to temporary"; break; - + case FK_NonConstLValueReferenceBindingToUnrelated: OS << "non-const lvalue reference bound to unrelated type"; break; - + case FK_RValueReferenceBindingToLValue: OS << "rvalue reference bound to an lvalue"; break; - + case FK_ReferenceInitDropsQualifiers: OS << "reference initialization drops qualifiers"; break; - + case FK_ReferenceInitFailed: OS << "reference initialization failed"; break; - + case FK_ConversionFailed: OS << "conversion failed"; break; - + case FK_TooManyInitsForScalar: OS << "too many initializers for scalar"; break; - + case FK_ReferenceBindingToInitList: OS << "referencing binding to initializer list"; break; - + case FK_InitListBadDestinationType: OS << "initializer list for non-aggregate, non-scalar type"; break; - + case FK_UserConversionOverloadFailed: OS << "overloading failed for user-defined conversion"; break; - + case FK_ConstructorOverloadFailed: OS << "constructor overloading failed"; break; - + case FK_DefaultInitOfConst: OS << "default initialization of a const variable"; break; - + case FK_Incomplete: OS << "initialization of incomplete type"; break; - } + } OS << '\n'; return; } - + case DependentSequence: OS << "Dependent sequence: "; return; - + case UserDefinedConversion: OS << "User-defined conversion sequence: "; break; - + case ConstructorInitialization: OS << "Constructor initialization sequence: "; break; - + case ReferenceBinding: OS << "Reference binding: "; break; - + case ListInitialization: OS << "List initialization: "; break; @@ -4415,54 +4415,54 @@ case ZeroInitialization: OS << "Zero initialization\n"; return; - + case NoInitialization: OS << "No initialization\n"; return; - + case StandardConversion: OS << "Standard conversion: "; break; - + case CAssignment: OS << "C assignment: "; break; - + case StringInit: OS << "String initialization: "; break; } - + for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { if (S != step_begin()) { OS << " -> "; } - + switch (S->Kind) { case SK_ResolveAddressOfOverloadedFunction: OS << "resolve address of overloaded function"; break; - + case SK_CastDerivedToBaseRValue: OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")"; break; - + case SK_CastDerivedToBaseXValue: OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")"; break; - + case SK_CastDerivedToBaseLValue: OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")"; break; - + case SK_BindReference: OS << "bind reference to lvalue"; break; - + case SK_BindReferenceToTemporary: OS << "bind reference to a temporary"; break; - + case SK_ExtraneousCopyToTemporary: OS << "extraneous C++03 copy to temporary"; break; @@ -4480,29 +4480,29 @@ case SK_QualificationConversionLValue: OS << "qualification conversion (lvalue)"; break; - + case SK_ConversionSequence: OS << "implicit conversion sequence ("; S->ICS->DebugPrint(); // FIXME: use OS OS << ")"; break; - + case SK_ListInitialization: OS << "list initialization"; break; - + case SK_ConstructorInitialization: OS << "constructor initialization"; break; - + case SK_ZeroInitialization: OS << "zero initialization"; break; - + case SK_CAssignment: OS << "C assignment"; break; - + case SK_StringInit: OS << "string initialization"; break; @@ -4521,7 +4521,7 @@ //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// -ExprResult +ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init) { Modified: cfe/trunk/lib/Sema/SemaLookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) +++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Jan 27 01:10:08 2011 @@ -91,7 +91,7 @@ UnqualUsingDirectiveSet() {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { - // C++ [namespace.udir]p1: + // C++ [namespace.udir]p1: // During unqualified name lookup, the names appear as if they // were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. @@ -106,7 +106,7 @@ } else { Scope::udir_iterator I = S->using_directives_begin(), End = S->using_directives_end(); - + for (; I != End; ++I) visit(*I, InnermostFileDC); } @@ -177,7 +177,7 @@ while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); Common = Common->getPrimaryContext(); - + list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } @@ -186,7 +186,7 @@ } typedef ListTy::const_iterator const_iterator; - + const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } @@ -259,9 +259,9 @@ case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; - + case Sema::LookupAnyName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol | Decl::IDNS_Type; break; @@ -315,7 +315,7 @@ /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); @@ -338,13 +338,13 @@ llvm::SmallPtrSet Unique; llvm::SmallPtrSet UniqueTypes; - + bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; - + unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); @@ -365,14 +365,14 @@ } } } - + if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; continue; - } - + } + // Otherwise, do some decl type analysis and then continue. if (isa(D)) { @@ -456,7 +456,7 @@ Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; - + for (iterator I = begin(), E = end(); I != E; ++I) { Out << "\n"; (*I)->print(Out, 2); @@ -482,9 +482,9 @@ if (S.getLangOptions().CPlusPlus && S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; - - if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, - BuiltinID, S.TUScope, + + if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, + BuiltinID, S.TUScope, R.isForRedeclaration(), R.getNameLoc())) { R.addDecl(D); @@ -512,16 +512,16 @@ // Don't do it if the class is invalid. if (Class->isInvalidDecl()) return false; - + // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; - + // We can't be in the middle of defining the class. if (const RecordType *RecordTy = Context.getTypeDeclType(Class)->getAs()) return !RecordTy->isBeingDefined(); - + return false; } @@ -532,46 +532,46 @@ // If the default constructor has not yet been declared, do so now. if (!Class->hasDeclaredDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); - + // If the copy constructor has not yet been declared, do so now. if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); - + // If the copy assignment operator has not yet been declared, do so now. if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); + DeclareImplicitDestructor(Class); } -/// \brief Determine whether this is the name of an implicitly-declared +/// \brief Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; - + case DeclarationName::CXXOperatorName: return Name.getCXXOverloadedOperator() == OO_Equal; - + default: - break; + break; } - + return false; } /// \brief If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. -static void DeclareImplicitMemberFunctionsWithName(Sema &S, +static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, const DeclContext *DC) { if (!DC) return; - + switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) @@ -584,26 +584,26 @@ S.DeclareImplicitCopyConstructor(const_cast(Record)); } break; - + case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && !Record->hasDeclaredDestructor() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitDestructor(const_cast(Record)); break; - + case DeclarationName::CXXOperatorName: if (Name.getCXXOverloadedOperator() != OO_Equal) break; - + if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitCopyAssignment(const_cast(Record)); break; - + default: - break; + break; } } @@ -615,7 +615,7 @@ // Lazily declare C++ special member functions. if (S.getLangOptions().CPlusPlus) DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC); - + // Perform lookup into this declaration context. DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { @@ -636,7 +636,7 @@ return Found; // C++ [temp.mem]p6: - // A specialization of a conversion function template is not found by + // A specialization of a conversion function template is not found by // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast(DC); @@ -644,36 +644,36 @@ return Found; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast(*U); if (!ConvTemplate) continue; - + // When we're performing lookup for the purposes of redeclaration, just - // add the conversion function template. When we deduce template - // arguments for specializations, we'll end up unifying the return + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return // type of the new declaration with the type of the function template. if (R.isForRedeclaration()) { R.addDecl(ConvTemplate); Found = true; continue; } - + // C++ [temp.mem]p6: - // [...] For each such operator, if argument deduction succeeds - // (14.9.2.3), the resulting specialization is used as if found by + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by // name lookup. // // When referencing a conversion function for any purpose other than // a redeclaration (such that we'll be building an expression with the - // result), perform template argument deduction and place the + // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); FunctionDecl *Specialization = 0; - - const FunctionProtoType *ConvProto + + const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs(); assert(ConvProto && "Nonsensical conversion function template type"); @@ -688,7 +688,7 @@ QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), 0, 0, EPI); - + // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, @@ -704,7 +704,7 @@ // Performs C++ unqualified lookup into the given file context. static bool -CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, +CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); @@ -742,7 +742,7 @@ static std::pair findOuterContext(Scope *S) { DeclContext *DC = static_cast(S->getEntity()); DeclContext *Lexical = 0; - for (Scope *OuterS = S->getParent(); OuterS; + for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = static_cast(OuterS->getEntity()); @@ -758,12 +758,12 @@ // // Example: // - // namespace N { - // class C { }; + // namespace N { + // class C { }; // // template class B { // void f(T); - // }; + // }; // } // // template void N::B::f(C) { @@ -772,24 +772,24 @@ // // In this example, the lexical context we return is the // TranslationUnit, while the semantic context is the namespace N. - if (!Lexical || !DC || !S->getParent() || + if (!Lexical || !DC || !S->getParent() || !S->getParent()->isTemplateParamScope()) return std::make_pair(Lexical, false); - // Find the outermost template parameter scope. + // Find the outermost template parameter scope. // For the example, this is the scope for the template parameters of // template. Scope *OutermostTemplateScope = S->getParent(); while (OutermostTemplateScope->getParent() && OutermostTemplateScope->getParent()->isTemplateParamScope()) OutermostTemplateScope = OutermostTemplateScope->getParent(); - + // Find the namespace context in which the original scope occurs. In // the example, this is namespace N. DeclContext *Semantic = DC; while (!Semantic->isFileContext()) Semantic = Semantic->getParent(); - + // Find the declaration context just outside of the template // parameter scope. This is the context in which the template is // being lexically declaration (a namespace context). In the @@ -813,7 +813,7 @@ if (DeclContext *DC = static_cast(PreS->getEntity())) DeclareImplicitMemberFunctionsWithName(*this, Name, DC); } - + // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. @@ -896,7 +896,7 @@ if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( - Name.getAsIdentifierInfo(), + Name.getAsIdentifierInfo(), ClassDeclared)) { if (R.isAcceptableDecl(Ivar)) { R.addDecl(Ivar); @@ -975,7 +975,7 @@ Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = 0; } - + if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; @@ -989,24 +989,24 @@ // non-transparent context. if (Ctx->isTransparentContext()) continue; - + // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. if (!(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); - + // Look into context considering using-directives. if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) Found = true; } - + if (Found) { R.resolveKind(); return true; } - + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } @@ -1245,41 +1245,41 @@ } /// \brief Callback that looks for any member of a class with the given name. -static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, +static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); - + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); Path.Decls = BaseRecord->lookup(N); return Path.Decls.first != Path.Decls.second; } -/// \brief Determine whether the given set of member declarations contains only +/// \brief Determine whether the given set of member declarations contains only /// static members, nested types, and enumerators. template static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { Decl *D = (*First)->getUnderlyingDecl(); if (isa(D) || isa(D) || isa(D)) return true; - + if (isa(D)) { // Determine whether all of the methods are static. bool AllMethodsAreStatic = true; for(; First != Last; ++First) { D = (*First)->getUnderlyingDecl(); - + if (!isa(D)) { assert(isa(D) && "Non-function must be a tag decl"); break; } - + if (!cast(D)->isStatic()) { AllMethodsAreStatic = false; break; } } - + if (AllMethodsAreStatic) return true; } @@ -1305,7 +1305,7 @@ /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// -/// \param InUnqualifiedLookup true if this is qualified name lookup that +/// \param InUnqualifiedLookup true if this is qualified name lookup that /// occurs as part of unqualified name lookup. /// /// \returns true if lookup succeeded, false if it failed. @@ -1356,7 +1356,7 @@ // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any - // dependent base classes, then we either have to delay lookup until + // dependent base classes, then we either have to delay lookup until // template instantiation time (at which point all bases will be available) // or we have to fail. if (!InUnqualifiedLookup && LookupRec->isDependentContext() && @@ -1364,7 +1364,7 @@ R.setNotFoundInCurrentInstantiation(); return false; } - + // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(LookupRec); @@ -1377,7 +1377,7 @@ case LookupRedeclarationWithLinkage: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; - + case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; @@ -1385,21 +1385,21 @@ case LookupAnyName: BaseCallback = &LookupAnyMember; break; - + case LookupUsingDeclName: // This lookup is for redeclarations only. - + case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: // These lookups will never find a member in a C++ class (or base class). return false; - + case LookupNestedNameSpecifierName: BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; break; } - + if (!LookupRec->lookupInBases(BaseCallback, R.getLookupName().getAsOpaquePtr(), Paths)) return false; @@ -1415,7 +1415,7 @@ QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; - + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); @@ -1423,15 +1423,15 @@ // Pick the best (i.e. most permissive i.e. numerically lowest) access // across all paths. SubobjectAccess = std::min(SubobjectAccess, Path->Access); - + // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; continue; - } - + } + if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of @@ -1441,26 +1441,26 @@ CXXBasePaths::paths_iterator FirstPath = Paths.begin(); DeclContext::lookup_iterator FirstD = FirstPath->Decls.first; DeclContext::lookup_iterator CurrentD = Path->Decls.first; - + while (FirstD != FirstPath->Decls.second && CurrentD != Path->Decls.second) { if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) break; - + ++FirstD; ++CurrentD; } - + if (FirstD == FirstPath->Decls.second && CurrentD == Path->Decls.second) continue; } - + R.setAmbiguousBaseSubobjectTypes(Paths); return true; - } - + } + if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. @@ -1470,7 +1470,7 @@ // has more than one base class subobject of type T. if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) continue; - + // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); @@ -1570,21 +1570,21 @@ Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) << LookupRange; - + DeclContext::lookup_iterator Found = Paths->front().Decls.first; while (isa(*Found) && cast(*Found)->isStatic()) ++Found; - + Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); - + return true; } case LookupResult::AmbiguousBaseSubobjectTypes: { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) << Name << LookupRange; - + CXXBasePaths *Paths = Result.getBasePaths(); std::set DeclsPrinted; for (CXXBasePaths::paths_iterator Path = Paths->begin(), @@ -1627,7 +1627,7 @@ case LookupResult::AmbiguousReference: { Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; - + LookupResult::iterator DI = Result.begin(), DE = Result.end(); for (; DI != DE; ++DI) Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; @@ -1693,7 +1693,7 @@ addAssociatedClassesAndNamespaces(Result, Arg.getAsType()); break; - case TemplateArgument::Template: + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as @@ -1709,7 +1709,7 @@ } break; } - + case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: @@ -2078,7 +2078,7 @@ } /// \brief Find the protocol with the given name, if any. -ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc) { Decl *D = LookupSingleName(TUScope, II, IdLoc, LookupObjCProtocolName); @@ -2135,7 +2135,7 @@ if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); } - + CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name); @@ -2143,7 +2143,7 @@ /// \brief Look for the destructor of the given class. /// -/// During semantic analysis, this routine should be used in lieu of +/// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). /// /// \returns The destructor for this class. @@ -2279,7 +2279,7 @@ /// of declarations. class ShadowMapEntry { typedef llvm::SmallVector DeclVector; - + /// \brief Contains either the solitary NamedDecl * or a vector /// of declarations. llvm::PointerUnion DeclOrVector; @@ -2361,7 +2361,7 @@ DeclOrVector = ND; return; } - + if (NamedDecl *PrevND = DeclOrVector.dyn_cast()) { // 1 -> 2 elements: create the vector of results and push in the // existing declaration. @@ -2381,7 +2381,7 @@ } } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::begin() { if (DeclOrVector.isNull()) return 0; @@ -2392,7 +2392,7 @@ return DeclOrVector.get()->begin(); } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::end() { if (DeclOrVector.isNull()) return 0; @@ -2406,7 +2406,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); - + unsigned IDNS = ND->getIdentifierNamespace(); std::list::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list::reverse_iterator SMEnd = ShadowMaps.rend(); @@ -2415,12 +2415,12 @@ if (Pos == SM->end()) continue; - for (ShadowMapEntry::iterator I = Pos->second.begin(), + for (ShadowMapEntry::iterator I = Pos->second.begin(), IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if ((*I)->hasTagIdentifierNamespace() && - (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -2437,7 +2437,7 @@ ND->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; - + // We've found a declaration that hides this one. return *I; } @@ -2457,14 +2457,14 @@ // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; - + if (CXXRecordDecl *Class = dyn_cast(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; + for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), + for (DeclContext::decl_iterator D = CurCtx->decls_begin(), DEnd = CurCtx->decls_end(); D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast(*D)) { @@ -2499,7 +2499,7 @@ ShadowContextRAII Shadow(Visited); DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { - LookupVisibleDecls((*I)->getNominatedNamespace(), Result, + LookupVisibleDecls((*I)->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -2513,16 +2513,16 @@ BEnd = Record->bases_end(); B != BEnd; ++B) { QualType BaseType = B->getType(); - + // Don't look into dependent bases, because name lookup can't look // there anyway. if (BaseType->isDependentType()) continue; - + const RecordType *Record = BaseType->getAs(); if (!Record) continue; - + // FIXME: It would be nice to be able to determine whether referencing // a particular member would be ambiguous. For example, given // @@ -2541,21 +2541,21 @@ // or // // c->A::member - + // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, true, Consumer, Visited); } } - + // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast(Ctx)) { // Traverse categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, + LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2564,7 +2564,7 @@ I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2574,35 +2574,35 @@ LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } - + // If there is an implementation, traverse it. We do this to find // synthesized ivars. if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getImplementation(), Result, + LookupVisibleDecls(IFace->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); } } else if (ObjCProtocolDecl *Protocol = dyn_cast(Ctx)) { for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), E = Category->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } - + // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category->getImplementation(), Result, + LookupVisibleDecls(Category->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); - } + } } } @@ -2613,8 +2613,8 @@ if (!S) return; - if (!S->getEntity() || - (!S->getParent() && + if (!S->getEntity() || + (!S->getParent() && !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. @@ -2627,7 +2627,7 @@ } } } - + // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; if (S->getEntity()) { @@ -2636,7 +2636,7 @@ // where we hit the context stored in the next outer scope. Entity = (DeclContext *)S->getEntity(); DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { @@ -2645,15 +2645,15 @@ LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); - + // Look for properties from which we can synthesize ivars, if // permitted. if (Result.getSema().getLangOptions().ObjCNonFragileABI2 && IFace->getImplementation() && Result.getLookupKind() == Sema::LookupOrdinaryName) { - for (ObjCInterfaceDecl::prop_iterator + for (ObjCInterfaceDecl::prop_iterator P = IFace->prop_begin(), PEnd = IFace->prop_end(); P != PEnd; ++P) { @@ -2662,8 +2662,8 @@ Consumer.FoundDecl(*P, Visited.checkHidden(*P), false); Visited.add(*P); } - } - } + } + } } } @@ -2675,8 +2675,8 @@ if (Ctx->isFunctionOrMethod()) continue; - - LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, + + LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { @@ -2686,14 +2686,14 @@ // FIXME: We would like the translation unit's Scope object to point to the // translation unit, so we don't need this special "if" branch. However, // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. + // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); - LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, + LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); - } - + } + if (Entity) { // Lookup visible declarations in any namespaces found by using // directives. @@ -2701,7 +2701,7 @@ llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast(UI->getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, + Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } @@ -2743,7 +2743,7 @@ if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); } @@ -2764,10 +2764,10 @@ /// \brief The best edit distance found so far. unsigned BestEditDistance; - + public: explicit TypoCorrectionConsumer(IdentifierInfo *Typo) - : Typo(Typo->getName()), + : Typo(Typo->getName()), BestEditDistance((std::numeric_limits::max)()) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); @@ -2785,17 +2785,17 @@ return BestResults[Name]; } - unsigned getBestEditDistance() const { return BestEditDistance; } + unsigned getBestEditDistance() const { return BestEditDistance; } }; } -void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; - + // Only consider entities with identifiers for names, ignoring // special names (constructors, overloaded operators, selectors, // etc.). @@ -2808,24 +2808,24 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { using namespace std; - + // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3)) return; - + // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance); - + // Compute the edit distance between the typo and the name of this // entity. If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Name, true, UpperBound); if (ED == 0) return; - + if (ED < BestEditDistance) { // This result is better than any we've seen before; clear out // the previous results. @@ -2836,15 +2836,15 @@ // ignore it. return; } - + // Add this name to the list of results. By not assigning a value, we // keep the current value if we've seen this name before (either as a // keyword or as a declaration), or get the default value (not a keyword) // if we haven't seen it before. - (void)BestResults[Name]; + (void)BestResults[Name]; } -void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, +void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, llvm::StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit @@ -2858,7 +2858,7 @@ // ignore it. return; } - + BestResults[Keyword] = true; } @@ -2873,7 +2873,7 @@ Res.suppressDiagnostics(); Res.clear(); Res.setLookupName(Name); - if (MemberContext) { + if (MemberContext) { if (ObjCInterfaceDecl *Class = dyn_cast(MemberContext)) { if (CTC == Sema::CTC_ObjCIvarLookup) { if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) { @@ -2882,29 +2882,29 @@ return; } } - + if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) { Res.addDecl(Prop); Res.resolveKind(); return; } } - + SemaRef.LookupQualifiedName(Res, MemberContext); return; } - - SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + + SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); - + // Fake ivar lookup; this should really be part of // LookupParsedName. if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { if (Method->isInstanceMethod() && Method->getClassInterface() && - (Res.empty() || + (Res.empty() || (Res.isSingleResult() && Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) { - if (ObjCIvarDecl *IV + if (ObjCIvarDecl *IV = Method->getClassInterface()->lookupInstanceVariable(Name)) { Res.addDecl(IV); Res.resolveKind(); @@ -2930,7 +2930,7 @@ /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// -/// \param EnteringContext whether we're entering the context described by +/// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param CTC The context in which typo correction occurs, which impacts the @@ -2944,13 +2944,13 @@ /// may contain the results of name lookup for the correct name or it may be /// empty. DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext, + DeclContext *MemberContext, bool EnteringContext, CorrectTypoContext CTC, const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking) return DeclarationName(); - + // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2965,9 +2965,9 @@ // instantiation. if (!ActiveTemplateInstantiations.empty()) return DeclarationName(); - + TypoCorrectionConsumer Consumer(Typo); - + // Perform name lookup to find visible, similarly-named entities. bool IsUnqualifiedLookup = false; if (MemberContext) { @@ -2975,8 +2975,8 @@ // Look in qualified interfaces. if (OPT) { - for (ObjCObjectPointerType::qual_iterator - I = OPT->qual_begin(), E = OPT->qual_end(); + for (ObjCObjectPointerType::qual_iterator + I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); } @@ -2984,7 +2984,7 @@ DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return DeclarationName(); - + // Provide a stop gap for files that are just seriously broken. Trying // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. @@ -3003,14 +3003,14 @@ // some files to take minutes to get rejected by the parser. if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) return DeclarationName(); - + // For unqualified lookup, look through all of the names that we have // seen in this translation unit. - for (IdentifierTable::iterator I = Context.Idents.begin(), + for (IdentifierTable::iterator I = Context.Idents.begin(), IEnd = Context.Idents.end(); I != IEnd; ++I) Consumer.FoundName(I->getKey()); - + // Walk through identifiers in external identifier sources. if (IdentifierInfoLookup *External = Context.Idents.getExternalIdentifierLookup()) { @@ -3028,7 +3028,7 @@ // end up adding the keyword below. if (Cached->second.first.empty()) return DeclarationName(); - + if (!Cached->second.second) Consumer.FoundName(Cached->second.first); } @@ -3045,44 +3045,44 @@ WantExpressionKeywords = true; WantCXXNamedCasts = true; WantRemainingKeywords = true; - + if (ObjCMethodDecl *Method = getCurMethodDecl()) if (Method->getClassInterface() && Method->getClassInterface()->getSuperClass()) Consumer.addKeywordResult(Context, "super"); - + break; - + case CTC_NoKeywords: break; - + case CTC_Type: WantTypeSpecifiers = true; break; - + case CTC_ObjCMessageReceiver: Consumer.addKeywordResult(Context, "super"); // Fall through to handle message receivers like expressions. - + case CTC_Expression: if (getLangOptions().CPlusPlus) WantTypeSpecifiers = true; WantExpressionKeywords = true; // Fall through to get C++ named casts. - + case CTC_CXXCasts: WantCXXNamedCasts = true; break; - + case CTC_ObjCPropertyLookup: // FIXME: Add "isa"? break; - + case CTC_MemberLookup: if (getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "template"); break; - + case CTC_ObjCIvarLookup: break; } @@ -3096,67 +3096,67 @@ // storage-specifiers as well "extern", "inline", "static", "typedef" }; - + const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); for (unsigned I = 0; I != NumCTypeSpecs; ++I) Consumer.addKeywordResult(Context, CTypeSpecs[I]); - + if (getLangOptions().C99) Consumer.addKeywordResult(Context, "restrict"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "bool"); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "class"); Consumer.addKeywordResult(Context, "typename"); Consumer.addKeywordResult(Context, "wchar_t"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "char16_t"); Consumer.addKeywordResult(Context, "char32_t"); Consumer.addKeywordResult(Context, "constexpr"); Consumer.addKeywordResult(Context, "decltype"); Consumer.addKeywordResult(Context, "thread_local"); - } + } } - + if (getLangOptions().GNUMode) Consumer.addKeywordResult(Context, "typeof"); } - + if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "const_cast"); Consumer.addKeywordResult(Context, "dynamic_cast"); Consumer.addKeywordResult(Context, "reinterpret_cast"); Consumer.addKeywordResult(Context, "static_cast"); } - + if (WantExpressionKeywords) { Consumer.addKeywordResult(Context, "sizeof"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "false"); Consumer.addKeywordResult(Context, "true"); } - + if (getLangOptions().CPlusPlus) { - const char *CXXExprs[] = { - "delete", "new", "operator", "throw", "typeid" + const char *CXXExprs[] = { + "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); for (unsigned I = 0; I != NumCXXExprs; ++I) Consumer.addKeywordResult(Context, CXXExprs[I]); - + if (isa(CurContext) && cast(CurContext)->isInstance()) Consumer.addKeywordResult(Context, "this"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "alignof"); Consumer.addKeywordResult(Context, "nullptr"); } } } - + if (WantRemainingKeywords) { if (getCurFunctionOrMethodDecl() || getCurBlock()) { // Statements. @@ -3165,18 +3165,18 @@ const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); for (unsigned I = 0; I != NumCStmts; ++I) Consumer.addKeywordResult(Context, CStmts[I]); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "catch"); Consumer.addKeywordResult(Context, "try"); } - + if (S && S->getBreakParent()) Consumer.addKeywordResult(Context, "break"); - + if (S && S->getContinueParent()) Consumer.addKeywordResult(Context, "continue"); - + if (!getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult(Context, "case"); Consumer.addKeywordResult(Context, "default"); @@ -3197,7 +3197,7 @@ Consumer.addKeywordResult(Context, "virtual"); } } - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "using"); @@ -3205,17 +3205,17 @@ Consumer.addKeywordResult(Context, "static_assert"); } } - + // If we haven't found anything, we're done. if (Consumer.empty()) { // If this was an unqualified lookup, note that no correction was found. if (IsUnqualifiedLookup) (void)UnqualifiedTyposCorrected[Typo]; - + return DeclarationName(); } - // Make sure that the user typed at least 3 characters for each correction + // Make sure that the user typed at least 3 characters for each correction // made. Otherwise, we don't even both looking at the results. // We also suppress exact matches; those should be handled by a @@ -3232,7 +3232,7 @@ // Weed out any names that could not be found by name lookup. bool LastLookupWasAccepted = false; - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), IEnd = Consumer.end(); I != IEnd; /* Increment in loop. */) { // Keywords are always found. @@ -3240,17 +3240,17 @@ ++I; continue; } - + // Perform name lookup on this name. IdentifierInfo *Name = &Context.Idents.get(I->getKey()); - LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, EnteringContext, CTC); - + switch (Res.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: - // We didn't find this name in our scope, or didn't like what we found; + // We didn't find this name in our scope, or didn't like what we found; // ignore it. Res.suppressDiagnostics(); { @@ -3260,8 +3260,8 @@ I = Next; } LastLookupWasAccepted = false; - break; - + break; + case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: @@ -3269,13 +3269,13 @@ LastLookupWasAccepted = true; break; } - + if (Res.isAmbiguous()) { // We don't deal with ambiguities. Res.suppressDiagnostics(); Res.clear(); - return DeclarationName(); - } + return DeclarationName(); + } } // If only a single name remains, return that result. @@ -3284,49 +3284,49 @@ if (Consumer.begin()->second) { Res.suppressDiagnostics(); Res.clear(); - + // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (ED == 0) { Res.setLookupName(Typo); return DeclarationName(); } - + } else if (!LastLookupWasAccepted) { // Perform name lookup on this name. - LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, EnteringContext, CTC); } // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] + UnqualifiedTyposCorrected[Typo] = std::make_pair(Name->getName(), Consumer.begin()->second); - - return &Context.Idents.get(Consumer.begin()->getKey()); + + return &Context.Idents.get(Consumer.begin()->getKey()); } - else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver + else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver && Consumer["super"]) { // Prefix 'super' when we're completing in a message-receiver // context. Res.suppressDiagnostics(); Res.clear(); - + // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (ED == 0) { Res.setLookupName(Typo); return DeclarationName(); } - + // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) UnqualifiedTyposCorrected[Typo] = std::make_pair("super", Consumer.begin()->second); - + return &Context.Idents.get("super"); } - + Res.suppressDiagnostics(); Res.setLookupName(Typo); Res.clear(); Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jan 27 01:10:08 2011 @@ -340,7 +340,7 @@ TemplateArgument SecondArg; }; } - + /// \brief Convert from Sema's representation of template deduction information /// to the form used in overload-candidate information. OverloadCandidate::DeductionFailureInfo @@ -356,12 +356,12 @@ case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: break; - + case Sema::TDK_Incomplete: case Sema::TDK_InvalidExplicitArguments: Result.Data = Info.Param.getOpaqueValue(); break; - + case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. @@ -372,16 +372,16 @@ Result.Data = Saved; break; } - + case Sema::TDK_SubstitutionFailure: Result.Data = Info.take(); break; - + case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: - break; + break; } - + return Result; } @@ -394,7 +394,7 @@ case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: break; - + case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: // FIXME: Destroy the data? @@ -405,15 +405,15 @@ // FIXME: Destroy the template arugment list? Data = 0; break; - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } } - -TemplateParameter + +TemplateParameter OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { switch (static_cast(Result)) { case Sema::TDK_Success: @@ -422,24 +422,24 @@ case Sema::TDK_TooFewArguments: case Sema::TDK_SubstitutionFailure: return TemplateParameter(); - + case Sema::TDK_Incomplete: case Sema::TDK_InvalidExplicitArguments: - return TemplateParameter::getFromOpaqueValue(Data); + return TemplateParameter::getFromOpaqueValue(Data); case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: return static_cast(Data)->Param; - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } - + return TemplateParameter(); } - + TemplateArgumentList * OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { switch (static_cast(Result)) { @@ -455,7 +455,7 @@ case Sema::TDK_SubstitutionFailure: return static_cast(Data); - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: @@ -478,16 +478,16 @@ case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: - return &static_cast(Data)->FirstArg; + return &static_cast(Data)->FirstArg; // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } - + return 0; -} +} const TemplateArgument * OverloadCandidate::DeductionFailureInfo::getSecondArg() { @@ -510,7 +510,7 @@ case Sema::TDK_FailedOverloadResolution: break; } - + return 0; } @@ -518,7 +518,7 @@ inherited::clear(); Functions.clear(); } - + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -701,19 +701,19 @@ (OldMethod->getRefQualifier() == RQ_None || NewMethod->getRefQualifier() == RQ_None)) { // C++0x [over.load]p2: - // - Member function declarations with the same name and the same - // parameter-type-list as well as member function template - // declarations with the same name, the same parameter-type-list, and - // the same template parameter lists cannot be overloaded if any of + // - Member function declarations with the same name and the same + // parameter-type-list as well as member function template + // declarations with the same name, the same parameter-type-list, and + // the same template parameter lists cannot be overloaded if any of // them, but not all, have a ref-qualifier (8.3.5). Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); Diag(OldMethod->getLocation(), diag::note_previous_declaration); } - + return true; } - + // The signatures match; this is not an overload. return false; } @@ -744,7 +744,7 @@ static ImplicitConversionSequence TryImplicitConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, + bool AllowExplicit, bool InOverloadResolution, bool CStyle) { ImplicitConversionSequence ICS; @@ -774,20 +774,20 @@ ICS.Standard.setAsIdentityConversion(); ICS.Standard.setFromType(FromType); ICS.Standard.setAllToTypes(ToType); - + // We don't actually check at this point whether there is a valid // copy/move constructor, since overloading just assumes that it // exists. When we actually perform initialization, we'll find the // appropriate constructor to copy the returned object, if needed. ICS.Standard.CopyConstructor = 0; - + // Determine whether this is considered a derived-to-base conversion. if (!S.Context.hasSameUnqualifiedType(FromType, ToType)) ICS.Standard.Second = ICK_Derived_To_Base; - + return ICS; } - + if (SuppressUserConversions) { // We're not in the case above, so there is no conversion that // we can perform. @@ -865,7 +865,7 @@ ImplicitConversionSequence ICS = clang::TryImplicitConversion(*this, Initializer, Entity.getType(), SuppressUserConversions, - AllowExplicitConversions, + AllowExplicitConversions, InOverloadResolution, CStyle); if (ICS.isBad()) return true; @@ -899,14 +899,14 @@ /*CStyle=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } - -/// \brief Determine whether the conversion from FromType to ToType is a valid + +/// \brief Determine whether the conversion from FromType to ToType is a valid /// conversion that strips "noreturn" off the nested function type. -static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, +static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, QualType ToType, QualType &ResultTy) { if (Context.hasSameUnqualifiedType(FromType, ToType)) return false; - + // Permit the conversion F(t __attribute__((noreturn))) -> F(t) // where F adds one of the following at most once: // - a pointer @@ -947,14 +947,14 @@ ResultTy = ToType; return true; } - + /// \brief Determine whether the conversion from FromType to ToType is a valid /// vector conversion. /// /// \param ICK Will be set to the vector conversion kind, if this is a vector /// conversion. -static bool IsVectorConversion(ASTContext &Context, QualType FromType, - QualType ToType, ImplicitConversionKind &ICK) { +static bool IsVectorConversion(ASTContext &Context, QualType FromType, + QualType ToType, ImplicitConversionKind &ICK) { // We need at least one of these types to be a vector type to have a vector // conversion. if (!ToType->isVectorType() && !FromType->isVectorType()) @@ -970,7 +970,7 @@ // identity conversion. if (FromType->isExtVectorType()) return false; - + // Vector splat from any arithmetic type to a vector. if (FromType->isArithmeticType()) { ICK = ICK_Vector_Splat; @@ -993,7 +993,7 @@ return false; } - + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -1007,7 +1007,7 @@ StandardConversionSequence &SCS, bool CStyle) { QualType FromType = From->getType(); - + // Standard conversions (C++ [conv]) SCS.setAsIdentityConversion(); SCS.DeprecatedStringLiteralToCharPtr = false; @@ -1031,26 +1031,26 @@ if (FromType == S.Context.OverloadTy) { DeclAccessPair AccessPair; if (FunctionDecl *Fn - = S.ResolveAddressOfOverloadedFunction(From, ToType, false, + = S.ResolveAddressOfOverloadedFunction(From, ToType, false, AccessPair)) { // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); if (CXXMethodDecl *Method = dyn_cast(Fn)) { if (!Method->isStatic()) { - const Type *ClassType + const Type *ClassType = S.Context.getTypeDeclType(Method->getParent()).getTypePtr(); FromType = S.Context.getMemberPointerType(FromType, ClassType); } } - + // If the "from" expression takes the address of the overloaded // function, update the type of the resulting expression accordingly. if (FromType->getAs()) if (UnaryOperator *UnOp = dyn_cast(From->IgnoreParens())) if (UnOp->getOpcode() == UO_AddrOf) FromType = S.Context.getPointerType(FromType); - + // Check that we've computed the proper type after overload resolution. assert(S.Context.hasSameType(FromType, S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); @@ -1159,7 +1159,7 @@ // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isRealFloatingType() && + } else if ((FromType->isRealFloatingType() && ToType->isIntegralType(S.Context)) || (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isRealFloatingType())) { @@ -1171,7 +1171,7 @@ // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; - } else if (S.IsMemberPointerConversion(From, FromType, ToType, + } else if (S.IsMemberPointerConversion(From, FromType, ToType, InOverloadResolution, FromType)) { // Pointer to member conversions (4.11). SCS.Second = ICK_Pointer_Member; @@ -1210,7 +1210,7 @@ // a conversion. [...] CanonFrom = S.Context.getCanonicalType(FromType); CanonTo = S.Context.getCanonicalType(ToType); - if (CanonFrom.getLocalUnqualifiedType() + if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) { @@ -1258,17 +1258,17 @@ return To->getKind() == BuiltinType::UInt; } - // C++0x [conv.prom]p3: - // A prvalue of an unscoped enumeration type whose underlying type is not - // fixed (7.2) can be converted to an rvalue a prvalue of the first of the - // following types that can represent all the values of the enumeration - // (i.e., the values in the range bmin to bmax as described in 7.2): int, - // unsigned int, long int, unsigned long int, long long int, or unsigned + // C++0x [conv.prom]p3: + // A prvalue of an unscoped enumeration type whose underlying type is not + // fixed (7.2) can be converted to an rvalue a prvalue of the first of the + // following types that can represent all the values of the enumeration + // (i.e., the values in the range bmin to bmax as described in 7.2): int, + // unsigned int, long int, unsigned long int, long long int, or unsigned // long long int. If none of the types in that list can represent all the - // values of the enumeration, an rvalue a prvalue of an unscoped enumeration + // values of the enumeration, an rvalue a prvalue of an unscoped enumeration // type can be converted to an rvalue a prvalue of the extended integer type - // with lowest integer conversion rank (4.13) greater than the rank of long - // long in which all the values of the enumeration can be represented. If + // with lowest integer conversion rank (4.13) greater than the rank of long + // long in which all the values of the enumeration can be represented. If // there are two such extended types, the signed one is chosen. if (const EnumType *FromEnumType = FromType->getAs()) { // C++0x 7.2p9: Note that this implicit enum to int conversion is not @@ -1277,28 +1277,28 @@ return false; // We have already pre-calculated the promotion type, so this is trivial. - if (ToType->isIntegerType() && + if (ToType->isIntegerType() && !RequireCompleteType(From->getLocStart(), FromType, PDiag())) return Context.hasSameUnqualifiedType(ToType, FromEnumType->getDecl()->getPromotionType()); } // C++0x [conv.prom]p2: - // A prvalue of type char16_t, char32_t, or wchar_t (3.9.1) can be converted - // to an rvalue a prvalue of the first of the following types that can - // represent all the values of its underlying type: int, unsigned int, + // A prvalue of type char16_t, char32_t, or wchar_t (3.9.1) can be converted + // to an rvalue a prvalue of the first of the following types that can + // represent all the values of its underlying type: int, unsigned int, // long int, unsigned long int, long long int, or unsigned long long int. - // If none of the types in that list can represent all the values of its + // If none of the types in that list can represent all the values of its // underlying type, an rvalue a prvalue of type char16_t, char32_t, - // or wchar_t can be converted to an rvalue a prvalue of its underlying + // or wchar_t can be converted to an rvalue a prvalue of its underlying // type. - if (FromType->isAnyCharacterType() && !FromType->isCharType() && + if (FromType->isAnyCharacterType() && !FromType->isCharType() && ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. FromIsSigned = true; @@ -1422,12 +1422,12 @@ assert((FromPtr->getTypeClass() == Type::Pointer || FromPtr->getTypeClass() == Type::ObjCObjectPointer) && "Invalid similarly-qualified pointer type"); - + /// \brief Conversions to 'id' subsume cv-qualifier conversions. if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) return ToType.getUnqualifiedType(); - - QualType CanonFromPointee + + QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); QualType CanonToPointee = Context.getCanonicalType(ToPointee); Qualifiers Quals = CanonFromPointee.getQualifiers(); @@ -1448,12 +1448,12 @@ // Just build a canonical type that has the right qualifiers. QualType QualifiedCanonToPointee = Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), Quals); - + if (isa(ToType)) return Context.getObjCObjectPointerType(QualifiedCanonToPointee); return Context.getPointerType(QualifiedCanonToPointee); } - + static bool isNullPointerConstantForConversion(Expr *Expr, bool InOverloadResolution, ASTContext &Context) { @@ -1532,7 +1532,7 @@ return true; } - // Beyond this point, both types need to be pointers + // Beyond this point, both types need to be pointers // , including objective-c pointers. QualType ToPointeeType = ToTypePtr->getPointeeType(); if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) { @@ -1548,7 +1548,7 @@ QualType FromPointeeType = FromTypePtr->getPointeeType(); - // If the unqualified pointee types are the same, this can't be a + // If the unqualified pointee types are the same, this can't be a // pointer conversion, so don't do all of the work below. if (Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) return false; @@ -1609,7 +1609,7 @@ bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs(); @@ -1646,7 +1646,7 @@ !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( FromObjCPtr->getPointeeType())) return false; - ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, + ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); return true; @@ -1657,7 +1657,7 @@ // interfaces, which is permitted. However, we're going to // complain about it. IncompatibleObjC = true; - ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, + ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); return true; @@ -1667,7 +1667,7 @@ QualType ToPointeeType; if (const PointerType *ToCPtr = ToType->getAs()) ToPointeeType = ToCPtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = + else if (const BlockPointerType *ToBlockPtr = ToType->getAs()) { // Objective C++: We're able to convert from a pointer to any object // to a block pointer type. @@ -1677,9 +1677,9 @@ } ToPointeeType = ToBlockPtr->getPointeeType(); } - else if (FromType->getAs() && + else if (FromType->getAs() && ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { - // Objective C++: We're able to convert from a block pointer type to a + // Objective C++: We're able to convert from a block pointer type to a // pointer to any object. ConvertedType = ToType; return true; @@ -1715,7 +1715,7 @@ ConvertedType = Context.getPointerType(ConvertedType); return true; } - + // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but @@ -1781,17 +1781,17 @@ return false; } - + /// FunctionArgTypesAreEqual - This routine checks two function proto types /// for equlity of their argument types. Caller has already checked that /// they have same number of arguments. This routine assumes that Objective-C /// pointer types which only differ in their protocol qualifiers are equal. -bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType, +bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType) { if (!getLangOptions().ObjC1) return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), NewType->arg_type_begin()); - + for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), N = NewType->arg_type_begin(), E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { @@ -1808,12 +1808,12 @@ } else if (const ObjCObjectPointerType *PTTo = ToType->getAs()) { - if (const ObjCObjectPointerType *PTFr = + if (const ObjCObjectPointerType *PTFr = FromType->getAs()) if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl()) continue; } - return false; + return false; } } return true; @@ -1854,7 +1854,7 @@ From->getSourceRange(), &BasePath, IgnoreBaseAccess)) return true; - + // The conversion was successful. Kind = CK_DerivedToBase; } @@ -1885,7 +1885,7 @@ /// If so, returns true and places the converted type (that might differ from /// ToType in its cv-qualifiers at some level) into ConvertedType. bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, - QualType ToType, + QualType ToType, bool InOverloadResolution, QualType &ConvertedType) { const MemberPointerType *ToTypePtr = ToType->getAs(); @@ -1920,7 +1920,7 @@ return false; } - + /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or /// virtual or inaccessible base-to-derived member pointer conversions @@ -1935,7 +1935,7 @@ const MemberPointerType *FromPtrType = FromType->getAs(); if (!FromPtrType) { // This must be a null pointer to member pointer conversion - assert(From->isNullPointerConstant(Context, + assert(From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull) && "Expr must be null pointer constant!"); Kind = CK_NullToMemberPointer; @@ -1990,7 +1990,7 @@ /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). bool -Sema::IsQualificationConversion(QualType FromType, QualType ToType, +Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool CStyle) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); @@ -2092,13 +2092,13 @@ = cast(ConstructorTmpl->getTemplatedDecl()); else Constructor = cast(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - &From, 1, CandidateSet, + &From, 1, CandidateSet, /*SuppressUserConversions=*/ !ConstructorsOnly); else @@ -2212,19 +2212,19 @@ case OR_Deleted: // No conversion here! We're done. return OR_Deleted; - + case OR_Ambiguous: return OR_Ambiguous; } return OR_No_Viable_Function; } - + bool Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { ImplicitConversionSequence ICS; OverloadCandidateSet CandidateSet(From->getExprLoc()); - OverloadingResult OvResult = + OverloadingResult OvResult = IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, CandidateSet, false); if (OvResult == OR_Ambiguous) @@ -2238,7 +2238,7 @@ else return false; CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &From, 1); - return true; + return true; } /// CompareImplicitConversionSequences - Compare two implicit @@ -2299,12 +2299,12 @@ while (Context.UnwrapSimilarPointerTypes(T1, T2)) { Qualifiers Quals; T1 = Context.getUnqualifiedArrayType(T1, Quals); - T2 = Context.getUnqualifiedArrayType(T2, Quals); + T2 = Context.getUnqualifiedArrayType(T2, Quals); } - + return Context.hasSameUnqualifiedType(T1, T2); } - + // Per 13.3.3.2p3, compare the given standard conversion sequences to // determine if one is a proper subset of the other. static ImplicitConversionSequence::CompareKind @@ -2314,7 +2314,7 @@ ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; - // the identity conversion sequence is considered to be a subsequence of + // the identity conversion sequence is considered to be a subsequence of // any non-identity conversion sequence if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) @@ -2322,7 +2322,7 @@ else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) return ImplicitConversionSequence::Worse; } - + if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) Result = ImplicitConversionSequence::Better; @@ -2347,7 +2347,7 @@ return Result == ImplicitConversionSequence::Better ? ImplicitConversionSequence::Indistinguishable : ImplicitConversionSequence::Worse; - + return ImplicitConversionSequence::Indistinguishable; } @@ -2358,9 +2358,9 @@ // C++0x [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and *either* S1 binds an rvalue reference + // without a ref-qualifier, and *either* S1 binds an rvalue reference // to an rvalue and S2 binds an lvalue reference *or S1 binds an - // lvalue reference to a function lvalue and S2 binds an rvalue + // lvalue reference to a function lvalue and S2 binds an rvalue // reference*. // // FIXME: Rvalue references. We're going rogue with the above edits, @@ -2371,13 +2371,13 @@ if (SCS1.BindsImplicitObjectArgumentWithoutRefQualifier || SCS2.BindsImplicitObjectArgumentWithoutRefQualifier) return false; - + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && SCS2.IsLvalueReference) || (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && !SCS2.IsLvalueReference); } - + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -2488,7 +2488,7 @@ return ImplicitConversionSequence::Better; else if (isBetterReferenceBindingKind(SCS2, SCS1)) return ImplicitConversionSequence::Worse; - + // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -2709,13 +2709,13 @@ if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) { - const MemberPointerType * FromMemPointer1 = + const MemberPointerType * FromMemPointer1 = FromType1->getAs(); - const MemberPointerType * ToMemPointer1 = + const MemberPointerType * ToMemPointer1 = ToType1->getAs(); - const MemberPointerType * FromMemPointer2 = + const MemberPointerType * FromMemPointer2 = FromType2->getAs(); - const MemberPointerType * ToMemPointer2 = + const MemberPointerType * ToMemPointer2 = ToType2->getAs(); const Type *FromPointeeType1 = FromMemPointer1->getClass(); const Type *ToPointeeType1 = ToMemPointer1->getClass(); @@ -2740,7 +2740,7 @@ return ImplicitConversionSequence::Worse; } } - + if (SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, // -- binding of an expression of type C to a reference of type @@ -2864,11 +2864,11 @@ else Conv = cast(D); - // If this is an explicit conversion, and we're not allowed to consider + // If this is an explicit conversion, and we're not allowed to consider // explicit conversions, skip it. if (!AllowExplicit && Conv->isExplicit()) continue; - + if (AllowRvalues) { bool DerivedToBase = false; bool ObjCConversion = false; @@ -2893,7 +2893,7 @@ !RefType->getPointeeType()->isFunctionType())) continue; } - + if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet); @@ -2943,7 +2943,7 @@ // conversion; continue with other checks. return false; } - + return false; } @@ -3035,7 +3035,7 @@ // conversion functions (13.3.1.6) and choosing the best // one through overload resolution (13.3)), if (!SuppressUserConversions && T2->isRecordType() && - !S.RequireCompleteType(DeclLoc, T2, 0) && + !S.RequireCompleteType(DeclLoc, T2, 0) && RefRelationship == Sema::Ref_Incompatible) { if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc, Init, T2, /*AllowRvalues=*/false, @@ -3047,7 +3047,7 @@ // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. - // + // // We actually handle one oddity of C++ [over.ics.ref] at this // point, which is that, due to p2 (which short-circuits reference // binding by only attempting a simple conversion for non-direct @@ -3070,7 +3070,7 @@ (InitCategory.isLValue() && T2->isFunctionType()))) { ICS.setStandard(); ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ObjCConversion? ICK_Compatible_Conversion : ICK_Identity; ICS.Standard.Third = ICK_Identity; @@ -3084,29 +3084,29 @@ // Note: Although xvalues wouldn't normally show up in C++98/03 code, we // allow the use of rvalue references in C++98/03 for the benefit of // standard library implementors; therefore, we need the xvalue check here. - ICS.Standard.DirectBinding = - S.getLangOptions().CPlusPlus0x || + ICS.Standard.DirectBinding = + S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = InitCategory.isRValue(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.CopyConstructor = 0; - return ICS; + return ICS; } - + // -- has a class type (i.e., T2 is a class type), where T1 is not // reference-related to T2, and can be implicitly converted to - // an xvalue, class prvalue, or function lvalue of type - // "cv3 T3", where "cv1 T1" is reference-compatible with + // an xvalue, class prvalue, or function lvalue of type + // "cv3 T3", where "cv1 T1" is reference-compatible with // "cv3 T3", // - // then the reference is bound to the value of the initializer + // then the reference is bound to the value of the initializer // expression in the first case and to the result of the conversion - // in the second case (or, in either case, to an appropriate base + // in the second case (or, in either case, to an appropriate base // class subobject). if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible && - T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && + T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && FindConversionForRefInit(S, ICS, DeclType, DeclLoc, Init, T2, /*AllowRvalues=*/true, AllowExplicit)) { @@ -3114,13 +3114,13 @@ // and the second standard conversion sequence of the // user-defined conversion sequence includes an lvalue-to-rvalue // conversion, the program is ill-formed. - if (ICS.isUserDefined() && isRValRef && + if (ICS.isUserDefined() && isRValRef && ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue) ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); return ICS; } - + // -- Otherwise, a temporary of type "cv1 T1" is created and // initialized from the initializer expression using the // rules for a non-reference copy initialization (8.5). The @@ -3192,7 +3192,7 @@ /// do not permit any user-defined conversion sequences. static ImplicitConversionSequence TryCopyInitialization(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + bool SuppressUserConversions, bool InOverloadResolution) { if (ToType->isReferenceType()) return TryReferenceInit(S, From, ToType, @@ -3239,7 +3239,7 @@ assert(FromType->isRecordType()); // C++0x [over.match.funcs]p4: - // For non-static member functions, the type of the implicit object + // For non-static member functions, the type of the implicit object // parameter is // // - "lvalue reference to cv X" for functions declared without a @@ -3247,10 +3247,10 @@ // - "rvalue reference to cv X" for functions declared with the && // ref-qualifier // - // where X is the class of which the function is a member and cv is the + // where X is the class of which the function is a member and cv is the // cv-qualification on the member function declaration. // - // However, when finding an implicit conversion sequence for the argument, we + // However, when finding an implicit conversion sequence for the argument, we // are not allowed to create temporaries or perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to @@ -3258,7 +3258,7 @@ // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); - if (ImplicitParamType.getCVRQualifiers() + if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { ICS.setBad(BadConversionSequence::bad_qualifiers, @@ -3285,11 +3285,11 @@ case RQ_None: // Do nothing; we don't care about lvalueness or rvalueness. break; - + case RQ_LValue: if (!FromClassification.isLValue() && Quals != Qualifiers::Const) { // non-const lvalue reference cannot bind to an rvalue - ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType, + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType, ImplicitParamType); return ICS; } @@ -3298,13 +3298,13 @@ case RQ_RValue: if (!FromClassification.isRValue()) { // rvalue reference cannot bind to an lvalue - ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType, + ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType, ImplicitParamType); return ICS; } break; } - + // Success. Mark this as a reference binding. ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); @@ -3313,7 +3313,7 @@ ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; + ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; ICS.Standard.BindsToFunctionLvalue = false; ICS.Standard.BindsToRvalue = FromClassification.isRValue(); ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier @@ -3325,8 +3325,8 @@ /// the implicit object parameter for the given Method with the given /// expression. bool -Sema::PerformObjectArgumentInitialization(Expr *&From, - NestedNameSpecifier *Qualifier, +Sema::PerformObjectArgumentInitialization(Expr *&From, + NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; @@ -3398,14 +3398,14 @@ ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); - + if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), diag::err_typecheck_bool_condition) << From->getType() << From->getSourceRange(); return true; } - + /// TryContextuallyConvertToObjCId - Attempt to contextually convert the /// expression From to 'id'. static ImplicitConversionSequence @@ -3429,7 +3429,7 @@ return true; } -/// \brief Attempt to convert the given expression to an integral or +/// \brief Attempt to convert the given expression to an integral or /// enumeration type. /// /// This routine will attempt to convert an expression of class type to an @@ -3457,7 +3457,7 @@ /// \param AmbigDiag The diagnostic to be emitted if there is more than one /// conversion function that could convert to integral or enumeration type. /// -/// \param AmbigNote The note to be emitted with \p AmbigDiag for each +/// \param AmbigNote The note to be emitted with \p AmbigDiag for each /// usable conversion function. /// /// \param ConvDiag The diagnostic to be emitted if we are calling a conversion @@ -3465,7 +3465,7 @@ /// /// \returns The expression, converted to an integral or enumeration type if /// successful. -ExprResult +ExprResult Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const PartialDiagnostic &NotIntDiag, const PartialDiagnostic &IncompleteDiag, @@ -3477,7 +3477,7 @@ // We can't perform any more checking for type-dependent expressions. if (From->isTypeDependent()) return Owned(From); - + // If the expression already has integral or enumeration type, we're golden. QualType T = From->getType(); if (T->isIntegralOrEnumerationType()) @@ -3485,7 +3485,7 @@ // FIXME: Check for missing '()' if T is a function type? - // If we don't have a class type in C++, there's no way we can get an + // If we don't have a class type in C++, there's no way we can get an // expression of integral or enumeration type. const RecordType *RecordTy = T->getAs(); if (!RecordTy || !getLangOptions().CPlusPlus) { @@ -3493,20 +3493,20 @@ << T << From->getSourceRange(); return Owned(From); } - + // We must have a complete class type. if (RequireCompleteType(Loc, T, IncompleteDiag)) return Owned(From); - + // Look for a conversion to an integral or enumeration type. UnresolvedSet<4> ViableConversions; UnresolvedSet<4> ExplicitConversions; const UnresolvedSetImpl *Conversions = cast(RecordTy->getDecl())->getVisibleConversionFunctions(); - + for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; + E = Conversions->end(); + I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast((*I)->getUnderlyingDecl())) @@ -3518,21 +3518,21 @@ ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } - + switch (ViableConversions.size()) { case 0: if (ExplicitConversions.size() == 1) { DeclAccessPair Found = ExplicitConversions[0]; CXXConversionDecl *Conversion = cast(Found->getUnderlyingDecl()); - + // The user probably meant to invoke the given explicit // conversion; use it. QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy); - + Diag(Loc, ExplicitConvDiag) << T << ConvTy << FixItHint::CreateInsertion(From->getLocStart(), @@ -3541,49 +3541,49 @@ ")"); Diag(Conversion->getLocation(), ExplicitConvNote) << ConvTy->isEnumeralType() << ConvTy; - - // If we aren't in a SFINAE context, build a call to the + + // If we aren't in a SFINAE context, build a call to the // explicit conversion function. if (isSFINAEContext()) return ExprError(); - + CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion); if (Result.isInvalid()) return ExprError(); - + From = Result.get(); } - + // We'll complain below about a non-integral condition type. break; - + case 1: { // Apply this conversion. DeclAccessPair Found = ViableConversions[0]; CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - + CXXConversionDecl *Conversion = cast(Found->getUnderlyingDecl()); QualType ConvTy - = Conversion->getConversionType().getNonReferenceType(); + = Conversion->getConversionType().getNonReferenceType(); if (ConvDiag.getDiagID()) { if (isSFINAEContext()) return ExprError(); - + Diag(Loc, ConvDiag) << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange(); } - + ExprResult Result = BuildCXXMemberCallExpr(From, Found, cast(Found->getUnderlyingDecl())); if (Result.isInvalid()) return ExprError(); - + From = Result.get(); break; } - + default: Diag(Loc, AmbigDiag) << T << From->getSourceRange(); @@ -3596,7 +3596,7 @@ } return Owned(From); } - + if (!From->getType()->isIntegralOrEnumerationType()) Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange(); @@ -3635,7 +3635,7 @@ // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), - QualType(), Expr::Classification::makeSimpleLValue(), + QualType(), Expr::Classification::makeSimpleLValue(), Args, NumArgs, CandidateSet, SuppressUserConversions); return; @@ -3655,13 +3655,13 @@ // A member function template is never instantiated to perform the copy // of a class object to an object of its class type. QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); - if (NumArgs == 1 && + if (NumArgs == 1 && Constructor->isSpecializationCopyingObject() && (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) || IsDerivedFrom(Args[0]->getType(), ClassType))) return; } - + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -3671,13 +3671,13 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = NumArgs; - + unsigned NumArgsInProto = Proto->getNumArgs(); // (C++ 13.3.2p2): A candidate function having fewer than m // parameters is viable only if it has an ellipsis in its parameter // list (8.3.5). - if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && + if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_too_many_arguments; @@ -3709,7 +3709,7 @@ QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; @@ -3738,7 +3738,7 @@ AddMethodCandidate(cast(FD), F.getPair(), cast(FD)->getParent(), Args[0]->getType(), Args[0]->Classify(Context), - Args + 1, NumArgs - 1, + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, @@ -3750,7 +3750,7 @@ AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0]->getType(), + Args[0]->getType(), Args[0]->Classify(Context), Args + 1, NumArgs - 1, CandidateSet, @@ -3777,7 +3777,7 @@ if (isa(Decl)) Decl = cast(Decl)->getTargetDecl(); - + if (FunctionTemplateDecl *TD = dyn_cast(Decl)) { assert(isa(TD->getTemplatedDecl()) && "Expected a member function template"); @@ -3882,7 +3882,7 @@ QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -3897,7 +3897,7 @@ } } } - + /// \brief Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. @@ -3937,7 +3937,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = NumArgs; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -3988,7 +3988,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = NumArgs; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -4036,8 +4036,8 @@ Candidate.ExplicitCallArguments = 1; // C++ [over.match.funcs]p4: - // For conversion functions, the function is considered to be a member of - // the class of the implicit implied object argument for the purpose of + // For conversion functions, the function is considered to be a member of + // the class of the implicit implied object argument for the purpose of // defining the type of the implicit object parameter. // // Determine the implicit conversion sequence for the implicit @@ -4047,19 +4047,19 @@ ImplicitParamType = FromPtrType->getPointeeType(); CXXRecordDecl *ConversionContext = cast(ImplicitParamType->getAs()->getDecl()); - + Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, From->getType(), - From->Classify(Context), + = TryObjectArgumentInitialization(*this, From->getType(), + From->Classify(Context), Conversion, ConversionContext); - + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; } - // We won't go through a user-define type conversion function to convert a + // We won't go through a user-define type conversion function to convert a // derived to base as such conversions are given Conversion Rank. They only // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] QualType FromCanon @@ -4070,7 +4070,7 @@ Candidate.FailureKind = ovl_fail_trivial_conversion; return; } - + // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to // convert to (ToType), we need to synthesize a call to the @@ -4109,23 +4109,23 @@ switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; - + // C++ [over.ics.user]p3: // If the user-defined conversion is specified by a specialization of a - // conversion function template, the second standard conversion sequence + // conversion function template, the second standard conversion sequence // shall have exact match rank. if (Conversion->getPrimaryTemplate() && GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_final_conversion_not_exact; } - + // C++0x [dcl.init.ref]p5: // In the second case, if the reference is an rvalue reference and // the second standard conversion sequence of the user-defined // conversion sequence includes an lvalue-to-rvalue conversion, the // program is ill-formed. - if (ToType->isRValueReferenceType() && + if (ToType->isRValueReferenceType() && ICS.Standard.First == ICK_Lvalue_To_Rvalue) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; @@ -4174,7 +4174,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = 1; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -4218,7 +4218,7 @@ // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(*this, Object->getType(), + = TryObjectArgumentInitialization(*this, Object->getType(), Object->Classify(Context), Conversion, ActingContext); if (ObjectInit.isBad()) { @@ -4235,7 +4235,7 @@ Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; - Candidate.Conversions[0].UserDefined.FoundConversionFunction + Candidate.Conversions[0].UserDefined.FoundConversionFunction = FoundDecl.getDecl(); Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; @@ -4332,7 +4332,7 @@ Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args[0]->Classify(Context), Args + 1, NumArgs - 1, + Args[0]->Classify(Context), Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } @@ -4422,7 +4422,7 @@ /// used in the built-in candidates. TypeSet EnumerationTypes; - /// \brief The set of vector types that will be used in the built-in + /// \brief The set of vector types that will be used in the built-in /// candidates. TypeSet VectorTypes; @@ -4454,7 +4454,7 @@ SemaRef(SemaRef), Context(SemaRef.Context) { } - void AddTypesConvertedFrom(QualType Ty, + void AddTypesConvertedFrom(QualType Ty, SourceLocation Loc, bool AllowUserConversions, bool AllowExplicitConversions, @@ -4477,7 +4477,7 @@ /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } - + iterator vector_begin() { return VectorTypes.begin(); } iterator vector_end() { return VectorTypes.end(); } @@ -4501,7 +4501,7 @@ // Insert this type. if (!PointerTypes.insert(Ty)) return false; - + QualType PointeeTy; const PointerType *PointerTy = Ty->getAs(); bool buildObjCPtr = false; @@ -4515,7 +4515,7 @@ } else PointeeTy = PointerTy->getPointeeType(); - + // Don't add qualified variants of arrays. For one, they're not allowed // (the qualifier would sink to the element type), and for another, the // only overload situation where it matters is subscript or pointer +- int, @@ -4527,7 +4527,7 @@ BaseCVR = Array->getElementType().getCVRQualifiers(); bool hasVolatile = VisibleQuals.hasVolatile(); bool hasRestrict = VisibleQuals.hasRestrict(); - + // Iterate through all strict supersets of BaseCVR. for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { if ((CVR | BaseCVR) != CVR) continue; @@ -4578,7 +4578,7 @@ unsigned BaseCVR = PointeeTy.getCVRQualifiers(); for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { if ((CVR | BaseCVR) != CVR) continue; - + QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); MemberPointerTypes.insert( Context.getMemberPointerType(QPointeeTy, ClassTy)); @@ -4713,14 +4713,14 @@ VRQuals.addRestrict(); return VRQuals; } - + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); if (!ClassDecl->hasDefinition()) return VRQuals; const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = I.getDecl(); @@ -4736,7 +4736,7 @@ while (!done) { if (const PointerType *ResTypePtr = CanTy->getAs()) CanTy = ResTypePtr->getPointeeType(); - else if (const MemberPointerType *ResTypeMPtr = + else if (const MemberPointerType *ResTypeMPtr = CanTy->getAs()) CanTy = ResTypeMPtr->getPointeeType(); else @@ -4985,7 +4985,7 @@ // T& operator*(T*); // // C++ [over.built]p7: - // For every function type T that does not have cv-qualifiers or a + // For every function type T that does not have cv-qualifiers or a // ref-qualifier, there exist candidate operator functions of the form // T& operator*(T*); void addUnaryStarPointerOverloads() { @@ -4997,11 +4997,11 @@ QualType PointeeTy = ParamTy->getPointeeType(); if (!PointeeTy->isObjectType() && !PointeeTy->isFunctionType()) continue; - + if (const FunctionProtoType *Proto =PointeeTy->getAs()) if (Proto->getTypeQuals() || Proto->getRefQualifier()) continue; - + S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), &ParamTy, Args, 1, CandidateSet); } @@ -5606,7 +5606,7 @@ QualType PointeeType = (*Ptr)->getPointeeType(); if (!PointeeType->isObjectType()) continue; - + QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) @@ -5966,7 +5966,7 @@ if (FunctionDecl *FD = dyn_cast(*I)) { if (ExplicitTemplateArgs) continue; - + AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, false, PartialOverloading); } else @@ -6048,12 +6048,12 @@ = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, - isa(Cand1.Function)? TPOC_Conversion + isa(Cand1.Function)? TPOC_Conversion : TPOC_Call, Cand1.ExplicitCallArguments)) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } - + // -- the context is an initialization by user-defined conversion // (see 8.5, 13.3.1.5) and the standard conversion sequence // from the return type of F1 to the destination type (i.e., @@ -6103,7 +6103,7 @@ Best = end(); for (iterator Cand = begin(); Cand != end(); ++Cand) { if (Cand->Viable) - if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, + if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, UserDefinedConversion)) Best = Cand; } @@ -6117,7 +6117,7 @@ for (iterator Cand = begin(); Cand != end(); ++Cand) { if (Cand->Viable && Cand != Best && - !isBetterOverloadCandidate(S, *Best, *Cand, Loc, + !isBetterOverloadCandidate(S, *Best, *Cand, Loc, UserDefinedConversion)) { Best = end(); return OR_Ambiguous; @@ -6138,7 +6138,7 @@ // placement new (5.3.4), as well as non-default initialization (8.5). if (Best->Function) S.MarkDeclarationReferenced(Loc, Best->Function); - + return OR_Success; } @@ -6327,7 +6327,7 @@ FromPtrTy->getPointeeType()) && !FromPtrTy->getPointeeType()->isIncompleteType() && !ToPtrTy->getPointeeType()->isIncompleteType() && - S.IsDerivedFrom(ToPtrTy->getPointeeType(), + S.IsDerivedFrom(ToPtrTy->getPointeeType(), FromPtrTy->getPointeeType())) BaseToDerivedConversion = 1; } @@ -6348,17 +6348,17 @@ S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) BaseToDerivedConversion = 3; } - + if (BaseToDerivedConversion) { - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_base_to_derived_conv) << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << (BaseToDerivedConversion - 1) - << FromTy << ToTy << I+1; + << FromTy << ToTy << I+1; return; } - + // TODO: specialize more based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc @@ -6374,14 +6374,14 @@ const FunctionProtoType *FnTy = Fn->getType()->getAs(); unsigned MinParams = Fn->getMinRequiredArguments(); - + // at least / at most / exactly unsigned mode, modeCount; if (NumFormalArgs < MinParams) { assert((Cand->FailureKind == ovl_fail_too_few_arguments) || (Cand->FailureKind == ovl_fail_bad_deduction && Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); - if (MinParams != FnTy->getNumArgs() || + if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic() || FnTy->isTemplateVariadic()) mode = 0; // "at least" else @@ -6402,7 +6402,7 @@ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode << modeCount << NumFormalArgs; } @@ -6461,18 +6461,18 @@ else { which = 2; } - + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) - << which << ParamD->getDeclName() + << which << ParamD->getDeclName() << *Cand->DeductionFailure.getFirstArg() << *Cand->DeductionFailure.getSecondArg(); return; } case Sema::TDK_InvalidExplicitArguments: - assert(ParamD && "no parameter found for invalid explicit arguments"); + assert(ParamD && "no parameter found for invalid explicit arguments"); if (ParamD->getDeclName()) - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_named) << ParamD->getDeclName(); else { @@ -6484,12 +6484,12 @@ index = NTTP->getIndex(); else index = cast(ParamD)->getIndex(); - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) << (index + 1); } return; - + case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: DiagnoseArityMismatch(S, Cand, NumArgs); @@ -6510,7 +6510,7 @@ << ArgString; return; } - + // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_NonDeducedMismatch: @@ -6571,7 +6571,7 @@ for (unsigned N = Cand->Conversions.size(); I != N; ++I) if (Cand->Conversions[I].isBad()) return DiagnoseBadConversion(S, Cand, I); - + // FIXME: this currently happens when we're called from SemaInit // when user-conversion overload fails. Figure out how to handle // those conditions and diagnose them well. @@ -6786,7 +6786,7 @@ Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ConvIdx], Cand->BuiltinTypes.ParamTypes[ConvIdx], - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution*/ true); return; } @@ -6797,7 +6797,7 @@ if (ArgIdx < NumArgsInProto) Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); else Cand->Conversions[ConvIdx].setEllipsis(); @@ -6832,7 +6832,7 @@ std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidatesForDisplay(S)); - + bool ReportedAmbiguousConversions = false; llvm::SmallVectorImpl::iterator I, E; @@ -6927,14 +6927,14 @@ // parentheses. OverloadExpr::FindResult Ovl = OverloadExpr::find(From); OverloadExpr *OvlExpr = Ovl.Expression; - + // We expect a pointer or reference to function, or a function pointer. FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); if (!FunctionType->isFunctionType()) { if (Complain) Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref) << OvlExpr->getName() << ToType; - + return 0; } @@ -6963,7 +6963,7 @@ // whose type matches exactly. llvm::SmallVector, 4> Matches; llvm::SmallVector NonMatches; - + bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -7018,7 +7018,7 @@ // when converting to member pointer. if (Method->isStatic() == IsMember) continue; - + // If we have explicit template arguments, skip non-templates. if (OvlExpr->hasExplicitTemplateArgs()) continue; @@ -7028,7 +7028,7 @@ if (FunctionDecl *FunDecl = dyn_cast(Fn)) { QualType ResultTy; if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || - IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, ResultTy)) { Matches.push_back(std::make_pair(I.getPair(), cast(FunDecl->getCanonicalDecl()))); @@ -7043,16 +7043,16 @@ Diag(From->getLocStart(), diag::err_addr_ovl_no_viable) << OvlExpr->getName() << FunctionType; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); + E = OvlExpr->decls_end(); I != E; ++I) if (FunctionDecl *F = dyn_cast((*I)->getUnderlyingDecl())) NoteOverloadCandidate(F); } - + return 0; } else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; - FoundResult = Matches[0].first; + FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) { CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); @@ -7077,7 +7077,7 @@ UnresolvedSet<4> MatchesCopy; // TODO: avoid! for (unsigned I = 0, E = Matches.size(); I != E; ++I) MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); - + UnresolvedSetIterator Result = getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), TPOC_Other, 0, From->getLocStart(), @@ -7088,7 +7088,7 @@ << (unsigned) oc_function_template); if (Result == MatchesCopy.end()) return 0; - + MarkDeclarationReferenced(From->getLocStart(), *Result); FoundResult = Matches[Result - MatchesCopy.begin()].first; if (Complain) @@ -7106,7 +7106,7 @@ Matches.set_size(N); } } - + // [...] After such eliminations, if any, there shall remain exactly one // selected function. if (Matches.size() == 1) { @@ -7129,12 +7129,12 @@ return 0; } -/// \brief Given an expression that refers to an overloaded function, try to +/// \brief Given an expression that refers to an overloaded function, try to /// resolve that overloaded function expression down to a single function. /// /// This routine can only resolve template-ids that refer to a single function /// template, where that template-id refers to a single template whose template -/// arguments are either provided by the template-id or have defaults, +/// arguments are either provided by the template-id or have defaults, /// as described in C++0x [temp.arg.explicit]p3. FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // C++ [over.over]p1: @@ -7148,14 +7148,14 @@ return 0; OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression; - + // If we didn't actually find any template-ids, we're done. if (!OvlExpr->hasExplicitTemplateArgs()) return 0; TemplateArgumentListInfo ExplicitTemplateArgs; OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); - + // Look through all of the overloaded functions, searching for one // whose type matches exactly. FunctionDecl *Matched = 0; @@ -7163,13 +7163,13 @@ E = OvlExpr->decls_end(); I != E; ++I) { // C++0x [temp.arg.explicit]p3: // [...] In contexts where deduction is done and fails, or in contexts - // where deduction is not done, if a template argument list is - // specified and it, along with any default template arguments, - // identifies a single function template specialization, then the + // where deduction is not done, if a template argument list is + // specified and it, along with any default template arguments, + // identifies a single function template specialization, then the // template-id is an lvalue for the function template specialization. FunctionTemplateDecl *FunctionTemplate = cast((*I)->getUnderlyingDecl()); - + // C++ [over.over]p2: // If the name is a function template, template argument deduction is // done (14.8.2.2), and if the argument deduction succeeds, the @@ -7184,18 +7184,18 @@ // FIXME: make a note of the failed deduction for diagnostics. (void)Result; continue; - } - + } + // Multiple matches; we can't resolve to a single declaration. if (Matched) return 0; Matched = Specialization; } - + return Matched; } - + /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, DeclAccessPair FoundDecl, @@ -7226,7 +7226,7 @@ // do nothing? } - + /// \brief Add the overload candidates named by callee and/or found by argument /// dependent lookup to the given overload set. void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, @@ -7274,7 +7274,7 @@ for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, - Args, NumArgs, CandidateSet, + Args, NumArgs, CandidateSet, PartialOverloading); if (ULE->requiresADL()) @@ -7282,7 +7282,7 @@ Args, NumArgs, ExplicitTemplateArgs, CandidateSet, - PartialOverloading); + PartialOverloading); } /// Attempts to recover from a call where no functions were found. @@ -7360,7 +7360,7 @@ (F = dyn_cast(*ULE->decls_begin())) && F->getBuiltinID() && F->isImplicit()) assert(0 && "performing ADL for builtin"); - + // We don't perform ADL in C. assert(getLangOptions().CPlusPlus && "ADL enabled in C"); } @@ -7469,11 +7469,11 @@ if (Input->isTypeDependent()) { if (Fns.empty()) return Owned(new (Context) UnaryOperator(Input, - Opc, + Opc, Context.DependentTy, VK_RValue, OK_Ordinary, OpLoc)); - + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, NamingClass, @@ -7529,7 +7529,7 @@ = PerformCopyInitialization(InitializedEntity::InitializeParameter( Context, FnDecl->getParamDecl(0)), - SourceLocation(), + SourceLocation(), Input); if (InputInit.isInvalid()) return ExprError(); @@ -7551,7 +7551,7 @@ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, Args, NumArgs, ResultTy, VK, OpLoc); - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -7631,14 +7631,14 @@ // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { if (Fns.empty()) { - // If there are no functions to store, just build a dependent + // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BO_Assign || Opc > BO_OrAssign) return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary, OpLoc)); - + return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, @@ -7653,7 +7653,7 @@ // TODO: provide better source location info in DNLoc component. DeclarationNameInfo OpNameInfo(OpName, OpLoc); UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), + = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, @@ -7752,7 +7752,7 @@ if (Arg1.isInvalid()) return ExprError(); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, Best->FoundDecl, Method)) return ExprError(); @@ -7790,8 +7790,8 @@ CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, Args, 2, ResultTy, VK, OpLoc); - - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, + + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -7822,7 +7822,7 @@ // operator do not fall through to handling in built-in, but report that // no overloaded assignment operator found ExprResult Result = ExprError(); - if (Args[0]->getType()->isRecordType() && + if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign && Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) << BinaryOperator::getOpcodeStr(Opc) @@ -7832,7 +7832,7 @@ // produce an error. Then, show the non-viable candidates. Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } - assert(Result.isInvalid() && + assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, @@ -7925,7 +7925,7 @@ // Convert the arguments. CXXMethodDecl *Method = cast(FnDecl); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, Best->FoundDecl, Method)) return ExprError(); @@ -7934,7 +7934,7 @@ = PerformCopyInitialization(InitializedEntity::InitializeParameter( Context, FnDecl->getParamDecl(0)), - SourceLocation(), + SourceLocation(), Owned(Args[1])); if (InputInit.isInvalid()) return ExprError(); @@ -7989,7 +7989,7 @@ case OR_Ambiguous: Diag(LLoc, diag::err_ovl_ambiguous_oper_binary) - << "[]" + << "[]" << Args[0]->getType() << Args[1]->getType() << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2, @@ -8023,7 +8023,7 @@ // Dig out the member expression. This holds both the object // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); - + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); @@ -8036,7 +8036,7 @@ } else { UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); Qualifier = UnresExpr->getQualifier(); - + QualType ObjectType = UnresExpr->getBaseType(); Expr::Classification ObjectClassification = UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue() @@ -8070,15 +8070,15 @@ // non-template member function. if (TemplateArgs) continue; - + AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, - ObjectClassification, - Args, NumArgs, CandidateSet, + ObjectClassification, + Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast(Func), I.getPair(), ActingDC, TemplateArgs, - ObjectType, ObjectClassification, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } @@ -8137,15 +8137,15 @@ ResultType = ResultType.getNonLValueExprType(Context); assert(Method && "Member call to something that isn't a method?"); - CXXMemberCallExpr *TheCall = + CXXMemberCallExpr *TheCall = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, ResultType, VK, RParenLoc); // Check for a valid return type. - if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), + if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), TheCall, Method)) return ExprError(); - + // Convert the object argument (for a non-static member function call). // We only need to do this if there was actually an overload; otherwise // it was done at lookup. @@ -8194,11 +8194,11 @@ OverloadCandidateSet CandidateSet(LParenLoc); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); - if (RequireCompleteType(LParenLoc, Object->getType(), + if (RequireCompleteType(LParenLoc, Object->getType(), PDiag(diag::err_incomplete_object_call) << Object->getSourceRange())) return true; - + LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); LookupQualifiedName(R, Record->getDecl()); R.suppressDiagnostics(); @@ -8209,7 +8209,7 @@ Object->Classify(Context), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } - + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -8235,7 +8235,7 @@ CXXRecordDecl *ActingContext = cast(D->getDeclContext()); if (isa(D)) D = cast(D)->getTargetDecl(); - + // Skip over templated conversion functions; they aren't // surrogates. if (isa(D)) @@ -8307,13 +8307,13 @@ // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion // on the object argument, then let ActOnCallExpr finish the job. - + // Create an implicit member expr to refer to the conversion operator. // and then call it. ExprResult Call = BuildCXXMemberCallExpr(Object, Best->FoundDecl, Conv); if (Call.isInvalid()) return ExprError(); - + return ActOnCallExpr(S, Call.get(), LParenLoc, MultiExprArg(Args, NumArgs), RParenLoc); } @@ -8359,10 +8359,10 @@ ResultTy, VK, RParenLoc); delete [] MethodArgs; - if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, + if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, Method)) return true; - + // We may have default arguments. If so, we need to allocate more // slots in the call for them. if (NumArgs < NumArgsInProto) @@ -8373,7 +8373,7 @@ bool IsError = false; // Initialize the implicit object parameter. - IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, + IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, Best->FoundDecl, Method); TheCall->setArg(0, Object); @@ -8391,7 +8391,7 @@ Context, Method->getParamDecl(i)), SourceLocation(), Arg); - + IsError |= InputInit.isInvalid(); Arg = InputInit.takeAs(); } else { @@ -8401,7 +8401,7 @@ IsError = true; break; } - + Arg = DefArg.takeAs(); } @@ -8507,15 +8507,15 @@ // Build the operator call. Expr *FnExpr = CreateFunctionRefExpr(*this, Method); - + QualType ResultTy = Method->getResultType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, + new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1, ResultTy, VK, OpLoc); - if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, + if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, Method)) return ExprError(); return Owned(TheCall); @@ -8533,26 +8533,26 @@ Found, Fn); if (SubExpr == PE->getSubExpr()) return PE; - + return new (Context) ParenExpr(PE->getLParen(), PE->getRParen(), SubExpr); - } - + } + if (ImplicitCastExpr *ICE = dyn_cast(E)) { Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn); - assert(Context.hasSameType(ICE->getSubExpr()->getType(), + assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); assert(ICE->path_empty() && "fixing up hierarchy conversion?"); if (SubExpr == ICE->getSubExpr()) return ICE; - - return ImplicitCastExpr::Create(Context, ICE->getType(), + + return ImplicitCastExpr::Create(Context, ICE->getType(), ICE->getCastKind(), SubExpr, 0, ICE->getValueKind()); - } - + } + if (UnaryOperator *UnOp = dyn_cast(E)) { assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); @@ -8591,12 +8591,12 @@ Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp; - + return new (Context) UnaryOperator(SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), VK_RValue, OK_Ordinary, UnOp->getOperatorLoc()); - } + } if (UnresolvedLookupExpr *ULE = dyn_cast(E)) { // FIXME: avoid copy. @@ -8650,10 +8650,10 @@ Base = MemExpr->getBase(); return MemberExpr::Create(Context, Base, - MemExpr->isArrow(), - MemExpr->getQualifier(), + MemExpr->isArrow(), + MemExpr->getQualifier(), MemExpr->getQualifierRange(), - Fn, + Fn, Found, MemExpr->getMemberNameInfo(), TemplateArgs, @@ -8662,12 +8662,12 @@ ? VK_LValue : VK_RValue, OK_Ordinary); } - + llvm_unreachable("Invalid reference to overloaded function"); return E; } -ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, +ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, DeclAccessPair Found, FunctionDecl *Fn) { return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); Modified: cfe/trunk/lib/Sema/SemaStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp (original) +++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jan 27 01:10:08 2011 @@ -61,7 +61,7 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { DeclGroupRef DG = dg.getAsVal(); - + // If we have an invalid decl, just return. if (DG.isNull() || !DG.isSingleDecl()) return; // suppress any potential 'unused variable' warning. @@ -114,7 +114,7 @@ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; return; } - } + } } else if (const ObjCMessageExpr *ME = dyn_cast(E)) { const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr()) { @@ -296,7 +296,7 @@ Expr *ConditionExpr = CondResult.takeAs(); if (!ConditionExpr) return StmtError(); - + DiagnoseUnusedExprResult(thenStmt); // Warn if the if block has a null body without an else value. @@ -318,7 +318,7 @@ DiagnoseUnusedExprResult(elseStmt); - return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, + return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, thenStmt, ElseLoc, elseStmt)); } @@ -356,7 +356,7 @@ } else if (NewSign != Val.isSigned()) { // Convert the sign to match the sign of the condition. This can cause // overflow as well: unsigned(INTMIN) - // We don't diagnose this overflow, because it is implementation-defined + // We don't diagnose this overflow, because it is implementation-defined // behavior. // FIXME: Introduce a second, default-ignored warning for this case? llvm::APSInt OldVal(Val); @@ -425,7 +425,7 @@ } StmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, +Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, Decl *CondVar) { ExprResult CondResult; @@ -435,15 +435,15 @@ CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false); if (CondResult.isInvalid()) return StmtError(); - + Cond = CondResult.release(); } - + if (!Cond) return StmtError(); - + CondResult - = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, + = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, PDiag(diag::err_typecheck_statement_requires_integer), PDiag(diag::err_switch_incomplete_class_type) << Cond->getSourceRange(), @@ -454,7 +454,7 @@ PDiag(0)); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); - + if (!CondVar) { CheckImplicitConversions(Cond, SwitchLoc); CondResult = MaybeCreateExprWithCleanups(Cond); @@ -464,7 +464,7 @@ } getCurFunction()->setHasBranchIntoScope(); - + SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); getCurFunction()->SwitchStack.push_back(SS); return Owned(SS); @@ -490,7 +490,7 @@ if (SS->getCond() == 0) return StmtError(); - + Expr *CondExpr = SS->getCond(); Expr *CondExprBeforePromotion = CondExpr; QualType CondTypeBeforePromotion = @@ -510,7 +510,7 @@ // the pre-promotion type of the switch condition. if (!CondExpr->isTypeDependent()) { // We have already converted the expression to an integral or enumeration - // type, when we started the switch statement. If we don't have an + // type, when we started the switch statement. If we don't have an // appropriate type now, just return an error. if (!CondType->isIntegralOrEnumerationType()) return StmtError(); @@ -787,7 +787,7 @@ RI != CaseRanges.end() && EI != EIend; RI++) { while (EI != EIend && EI->first < RI->first) EI++; - + if (EI == EIend || EI->first != RI->first) { Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) << ED->getDeclName(); @@ -802,20 +802,20 @@ << ED->getDeclName(); } } - + // Check which enum vals aren't in switch CaseValsTy::const_iterator CI = CaseVals.begin(); CaseRangesTy::const_iterator RI = CaseRanges.begin(); bool hasCasesNotInSwitch = false; llvm::SmallVector UnhandledNames; - + for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){ // Drop unneeded case values llvm::APSInt CIVal; while (CI != CaseVals.end() && CI->first < EI->first) CI++; - + if (CI != CaseVals.end() && CI->first == EI->first) continue; @@ -833,7 +833,7 @@ UnhandledNames.push_back(EI->second->getDeclName()); } } - + // Produce a nice diagnostic if multiple values aren't handled. switch (UnhandledNames.size()) { case 0: break; @@ -870,10 +870,10 @@ } StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, +Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, Decl *CondVar, Stmt *Body) { ExprResult CondResult(Cond.release()); - + VarDecl *ConditionVar = 0; if (CondVar) { ConditionVar = cast(CondVar); @@ -884,7 +884,7 @@ Expr *ConditionExpr = CondResult.take(); if (!ConditionExpr) return StmtError(); - + DiagnoseUnusedExprResult(Body); return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr, @@ -905,7 +905,7 @@ if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); - + DiagnoseUnusedExprResult(Body); return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen)); @@ -941,16 +941,16 @@ if (SecondResult.isInvalid()) return StmtError(); } - + Expr *Third = third.release().takeAs(); - + DiagnoseUnusedExprResult(First); DiagnoseUnusedExprResult(Third); DiagnoseUnusedExprResult(Body); - return Owned(new (Context) ForStmt(Context, First, - SecondResult.take(), ConditionVar, - Third, Body, ForLoc, LParenLoc, + return Owned(new (Context) ForStmt(Context, First, + SecondResult.take(), ConditionVar, + Third, Body, ForLoc, LParenLoc, RParenLoc)); } @@ -1010,7 +1010,7 @@ else if (const ObjCObjectPointerType *OPT = SecondType->getAsObjCInterfacePointerType()) { llvm::SmallVector KeyIdents; - IdentifierInfo* selIdent = + IdentifierInfo* selIdent = &Context.Idents.get("countByEnumeratingWithState"); KeyIdents.push_back(selIdent); selIdent = &Context.Idents.get("objects"); @@ -1019,7 +1019,7 @@ KeyIdents.push_back(selIdent); Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { - if (!IDecl->isForwardDecl() && + if (!IDecl->isForwardDecl() && !IDecl->lookupInstanceMethod(CSelector)) { // Must further look into private implementation methods. if (!LookupPrivateInstanceMethod(CSelector, IDecl)) @@ -1089,7 +1089,7 @@ return Owned(new (Context) BreakStmt(BreakLoc)); } -/// \brief Determine whether the given expression is a candidate for +/// \brief Determine whether the given expression is a candidate for /// copy elision in either a return statement or a throw expression. /// /// \param ReturnType If we're determining the copy elision candidate for @@ -1117,8 +1117,8 @@ if (!Context.hasSameUnqualifiedType(ReturnType, ExprType)) return 0; } - - // ... the expression is the name of a non-volatile automatic object + + // ... the expression is the name of a non-volatile automatic object // (other than a function or catch-clause parameter)) ... const DeclRefExpr *DR = dyn_cast(E->IgnoreParens()); if (!DR) @@ -1126,14 +1126,14 @@ const VarDecl *VD = dyn_cast(DR->getDecl()); if (!VD) return 0; - + if (VD->hasLocalStorage() && !VD->isExceptionVariable() && !VD->getType()->isReferenceType() && !VD->hasAttr() && !VD->getType().isVolatileQualified() && ((VD->getKind() == Decl::Var) || (AllowFunctionParameter && VD->getKind() == Decl::ParmVar))) return VD; - + return 0; } @@ -1143,30 +1143,30 @@ /// This routine implements C++0x [class.copy]p33, which attempts to treat /// returned lvalues as rvalues in certain cases (to prefer move construction), /// then falls back to treating them as lvalues if that failed. -ExprResult +ExprResult Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, Expr *Value) { // C++0x [class.copy]p33: - // When the criteria for elision of a copy operation are met or would - // be met save for the fact that the source object is a function - // parameter, and the object to be copied is designated by an lvalue, + // When the criteria for elision of a copy operation are met or would + // be met save for the fact that the source object is a function + // parameter, and the object to be copied is designated by an lvalue, // overload resolution to select the constructor for the copy is first // performed as if the object were designated by an rvalue. ExprResult Res = ExprError(); if (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true)) { - ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_LValueToRValue, Value, VK_XValue); - + Expr *InitExpr = &AsRvalue; - InitializationKind Kind + InitializationKind Kind = InitializationKind::CreateCopy(Value->getLocStart(), Value->getLocStart()); InitializationSequence Seq(*this, Entity, Kind, &InitExpr, 1); - - // [...] If overload resolution fails, or if the type of the first + + // [...] If overload resolution fails, or if the type of the first // parameter of the selected constructor is not an rvalue reference // to the object's type (possibly cv-qualified), overload resolution // is performed again, considering the object as an lvalue. @@ -1174,42 +1174,42 @@ for (InitializationSequence::step_iterator Step = Seq.step_begin(), StepEnd = Seq.step_end(); Step != StepEnd; ++Step) { - if (Step->Kind + if (Step->Kind != InitializationSequence::SK_ConstructorInitialization) continue; - - CXXConstructorDecl *Constructor + + CXXConstructorDecl *Constructor = cast(Step->Function.Function); - + const RValueReferenceType *RRefType = Constructor->getParamDecl(0)->getType() ->getAs(); - + // If we don't meet the criteria, break out now. - if (!RRefType || + if (!RRefType || !Context.hasSameUnqualifiedType(RRefType->getPointeeType(), Context.getTypeDeclType(Constructor->getParent()))) break; - + // Promote "AsRvalue" to the heap, since we now need this // expression node to persist. Value = ImplicitCastExpr::Create(Context, Value->getType(), - CK_LValueToRValue, Value, 0, + CK_LValueToRValue, Value, 0, VK_XValue); - + // Complete type-checking the initialization of the return type // using the constructor we found. Res = Seq.Perform(*this, Entity, Kind, MultiExprArg(&Value, 1)); } } } - + // Either we didn't meet the criteria for treating an lvalue as an rvalue, - // above, or overload resolution failed. Either way, we need to try + // above, or overload resolution failed. Either way, we need to try // (again) now with the return value expression as written. if (Res.isInvalid()) Res = PerformCopyInitialization(Entity, SourceLocation(), Value); - + return Res; } @@ -1258,7 +1258,7 @@ return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); } else { const VarDecl *NRVOCandidate = 0; - + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { // we have a non-void block with an expression, continue checking @@ -1269,35 +1269,35 @@ // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, FnRetType, NRVOCandidate != 0); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, FnRetType, RetValExp); if (Res.isInvalid()) { // FIXME: Cleanup temporaries here, anyway? return StmtError(); } - + if (RetValExp) { CheckImplicitConversions(RetValExp, ReturnLoc); RetValExp = MaybeCreateExprWithCleanups(RetValExp); } RetValExp = Res.takeAs(); - if (RetValExp) + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - // If we need to check for the named return value optimization, save the + // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -1342,7 +1342,7 @@ CheckImplicitConversions(RetValExp, ReturnLoc); RetValExp = MaybeCreateExprWithCleanups(RetValExp); } - + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp && !FnRetType->isDependentType()) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 @@ -1366,10 +1366,10 @@ // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, FnRetType, NRVOCandidate != 0); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, FnRetType, RetValExp); if (Res.isInvalid()) { // FIXME: Cleanup temporaries here, anyway? @@ -1377,23 +1377,23 @@ } RetValExp = Res.takeAs(); - if (RetValExp) + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - + if (RetValExp) { CheckImplicitConversions(RetValExp, ReturnLoc); RetValExp = MaybeCreateExprWithCleanups(RetValExp); } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - - // If we need to check for the named return value optimization, save the + + // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -1408,7 +1408,7 @@ // Type dependent expressions will be checked during instantiation. if (E->isTypeDependent()) return false; - + if (E->isLValue()) return false; // Cool, this is an lvalue. @@ -1544,8 +1544,8 @@ } AsmStmt *NS = - new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, - NumOutputs, NumInputs, Names, Constraints, Exprs, + new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, + NumOutputs, NumInputs, Names, Constraints, Exprs, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. @@ -1579,7 +1579,7 @@ enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; - + if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) @@ -1593,19 +1593,19 @@ OutputDomain = AD_FP; else OutputDomain = AD_Other; - + // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. - // + // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) continue; - + // If the smaller input/output operand is not mentioned in the asm string, // then we can promote it and the asm string won't notice. Check this // case now. @@ -1657,7 +1657,7 @@ VarDecl *Var = cast_or_null(Parm); if (Var && Var->isInvalidDecl()) return StmtError(); - + return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body)); } @@ -1667,7 +1667,7 @@ } StmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg CatchStmts, Stmt *Finally) { getCurFunction()->setHasBranchProtectedScope(); unsigned NumCatchStmts = CatchStmts.size(); @@ -1692,12 +1692,12 @@ << Throw->getType() << Throw->getSourceRange()); } } - + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, Throw)); } StmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope) { if (!Throw) { // @throw without an expression designates a rethrow (which much occur @@ -1707,8 +1707,8 @@ AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); - } - + } + return BuildObjCAtThrowStmt(AtLoc, Throw); } Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 27 01:10:08 2011 @@ -88,12 +88,12 @@ else if (Repl != Orig) { // C++ [temp.local]p3: - // A lookup that finds an injected-class-name (10.2) can result in an + // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than - // one base class). If all of the injected-class-names that are found - // refer to specializations of the same class template, and if the name - // is followed by a template-argument-list, the reference refers to the - // class template itself and not a specialization thereof, and is not + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not // ambiguous. // // FIXME: Will we eventually have to do the same for alias templates? @@ -126,12 +126,12 @@ DeclarationName TName; MemberOfUnknownSpecialization = false; - + switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: TName = DeclarationName(Name.Identifier); break; - + case UnqualifiedId::IK_OperatorFunctionId: TName = Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator); @@ -147,7 +147,7 @@ QualType ObjectType = ObjectTypePtr.get(); - LookupResult R(*this, TName, Name.getSourceRange().getBegin(), + LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization); @@ -200,7 +200,7 @@ return TemplateKind; } -bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, +bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, @@ -212,14 +212,14 @@ if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; - + // The code is missing a 'template' keyword prior to the dependent template // name. NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() << FixItHint::CreateInsertion(IILoc, "template "); - SuggestedTemplate + SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; return true; @@ -240,14 +240,14 @@ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); - assert((isDependent || !ObjectType->isIncompleteType()) && + assert((isDependent || !ObjectType->isIncompleteType()) && "Caller should have completed object type"); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); - + // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return; @@ -287,7 +287,7 @@ if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, + if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, false, CTC_CXXCasts)) { FilterAcceptableTemplateNames(Context, Found); if (!Found.empty()) { @@ -328,7 +328,7 @@ LookupOrdinaryName); LookupName(FoundOuter, S); FilterAcceptableTemplateNames(Context, FoundOuter); - + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise @@ -343,7 +343,7 @@ if (!Found.isSingleResult() || Found.getFoundDecl()->getCanonicalDecl() != FoundOuter.getFoundDecl()->getCanonicalDecl()) { - Diag(Found.getNameLoc(), + Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() << ObjectType; @@ -372,12 +372,12 @@ = static_cast(SS.getScopeRep()); DeclContext *DC = getFunctionLevelDeclContext(); - + if (!isAddressOfOperand && isa(DC) && cast(DC)->isInstance()) { QualType ThisType = cast(DC)->getThisType(Context); - + // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = 0; @@ -439,7 +439,7 @@ ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion( SourceLocation EllipsisLoc) const { - assert(Kind == Template && + assert(Kind == Template && "Only template template arguments can be pack expansions here"); assert(getAsTemplate().get().containsUnexpandedParameterPack() && "Template template argument pack expansion without packs"); @@ -450,21 +450,21 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, const ParsedTemplateArgument &Arg) { - + switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); - if (!DI) + if (!DI) DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } - + case ParsedTemplateArgument::NonType: { Expr *E = static_cast(Arg.getAsExpr()); return TemplateArgumentLoc(TemplateArgument(E), E); } - + case ParsedTemplateArgument::Template: { TemplateName Template = Arg.getAsTemplate().get(); TemplateArgument TArg; @@ -478,11 +478,11 @@ Arg.getEllipsisLoc()); } } - + llvm_unreachable("Unhandled parsed template argument"); return TemplateArgumentLoc(); } - + /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, @@ -491,7 +491,7 @@ TemplateArgs.addArgument(translateTemplateArgument(*this, TemplateArgsIn[I])); } - + /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter @@ -551,23 +551,23 @@ if (DefaultArg) { TypeSourceInfo *DefaultTInfo; GetTypeFromParser(DefaultArg, &DefaultTInfo); - + assert(DefaultTInfo && "expected source information for type"); - + // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, + if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, UPPC_DefaultArgument)) return Param; - + // Check the template argument itself. if (CheckTemplateArgument(Param, DefaultTInfo)) { Param->setInvalidDecl(); return Param; } - + Param->setDefaultArgument(DefaultTInfo, false); } - + return Param; } @@ -614,7 +614,7 @@ else if (T->isFunctionType()) // FIXME: Keep the type prior to promotion? return Context.getPointerType(T); - + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -648,12 +648,12 @@ T = Context.IntTy; // Recover with an 'int' type. Invalid = true; } - + bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), D.getIdentifierLoc(), - Depth, Position, ParamName, T, + Depth, Position, ParamName, T, IsParameterPack, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -663,7 +663,7 @@ S->AddDecl(Param); IdResolver.AddDecl(Param); } - + // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. @@ -683,10 +683,10 @@ Param->setInvalidDecl(); return Param; } - + Param->setDefaultArgument(Default, false); } - + return Param; } @@ -711,11 +711,11 @@ // FIXME: Pack-ness is dropped TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), - NameLoc.isInvalid()? TmpLoc : NameLoc, - Depth, Position, IsParameterPack, + NameLoc.isInvalid()? TmpLoc : NameLoc, + Depth, Position, IsParameterPack, Name, Params); - // If the template template parameter has a name, then link the identifier + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { S->AddDecl(Param); @@ -735,7 +735,7 @@ Diag(EqualLoc, diag::err_template_param_pack_default_arg); Default = ParsedTemplateArgument(); } - + if (!Default.isInvalid()) { // Check only that we have a template template argument. We don't want to // try to check well-formedness now, because our template template parameter @@ -751,16 +751,16 @@ << DefaultArg.getSourceRange(); return Param; } - + // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(), + if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(), DefaultArg.getArgument().getAsTemplate(), UPPC_DefaultArgument)) return Param; - + Param->setDefaultArgument(DefaultArg, false); } - + return Param; } @@ -777,7 +777,7 @@ Diag(ExportLoc, diag::warn_template_export_unsupported); return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - (NamedDecl**)Params, NumParams, + (NamedDecl**)Params, NumParams, RAngleLoc); } @@ -834,7 +834,7 @@ if (Previous.isAmbiguous()) return true; - + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) PrevDecl = (*Previous.begin())->getUnderlyingDecl(); @@ -845,12 +845,12 @@ = dyn_cast_or_null(PrevDecl); // We may have found the injected-class-name of a class template, - // class template partial specialization, or class template specialization. + // class template partial specialization, or class template specialization. // In these cases, grab the template that is being defined or specialized. - if (!PrevClassTemplate && PrevDecl && isa(PrevDecl) && + if (!PrevClassTemplate && PrevDecl && isa(PrevDecl) && cast(PrevDecl)->isInjectedClassName()) { PrevDecl = cast(PrevDecl->getDeclContext()); - PrevClassTemplate + PrevClassTemplate = cast(PrevDecl)->getDescribedClassTemplate(); if (!PrevClassTemplate && isa(PrevDecl)) { PrevClassTemplate @@ -861,8 +861,8 @@ if (TUK == TUK_Friend) { // C++ [namespace.memdef]p3: - // [...] When looking for a prior declaration of a class or a function - // declared as a friend, and when the name of the friend class or + // [...] When looking for a prior declaration of a class or a function + // declared as a friend, and when the name of the friend class or // function is neither a qualified name nor a template-id, scopes outside // the innermost enclosing namespace scope are not considered. if (!SS.isSet()) { @@ -876,7 +876,7 @@ SemanticContext = PrevDecl->getDeclContext(); } else { // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semantic context for our new + // context we computed is the semantic context for our new // declaration. PrevDecl = PrevClassTemplate = 0; SemanticContext = OutermostContext; @@ -892,7 +892,7 @@ } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -950,14 +950,14 @@ Invalid = true; if (SS.isSet()) { - // If the name of the template was qualified, we must be defining the + // If the name of the template was qualified, we must be defining the // template out-of-line. if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && !(TUK == TUK_Friend && CurContext->isDependentContext())) Diag(NameLoc, diag::err_member_def_does_not_match) << Name << SemanticContext << SS.getRange(); - } - + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -977,12 +977,12 @@ assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; - // If we are providing an explicit specialization of a member that is a + // If we are providing an explicit specialization of a member that is a // class template, make a note of that. - if (PrevClassTemplate && + if (PrevClassTemplate && PrevClassTemplate->getInstantiatedFromMemberTemplate()) PrevClassTemplate->setMemberSpecialization(); - + // Set the access specifier. if (!Invalid && TUK != TUK_Friend) SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); @@ -1007,16 +1007,16 @@ NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevClassTemplate != NULL); - + // Friend templates are visible in fairly strange ways. if (!CurContext->isDependentContext()) { DeclContext *DC = SemanticContext->getRedeclContext(); DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(NewTemplate, EnclosingScope, - /* AddToContext = */ false); + /* AddToContext = */ false); } - + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NewClass->getLocation(), NewTemplate, @@ -1036,7 +1036,7 @@ /// template parameter, which is ill-formed in certain contexts. /// /// \returns true if the default template argument should be dropped. -static bool DiagnoseDefaultTemplateArgument(Sema &S, +static bool DiagnoseDefaultTemplateArgument(Sema &S, Sema::TemplateParamListContext TPC, SourceLocation ParamLoc, SourceRange DefArgRange) { @@ -1045,13 +1045,13 @@ return false; case Sema::TPC_FunctionTemplate: - // C++ [temp.param]p9: + // C++ [temp.param]p9: // A default template-argument shall not be specified in a // function template declaration or a function template // definition [...] // (This sentence is not in C++0x, per DR226). if (!S.getLangOptions().CPlusPlus0x) - S.Diag(ParamLoc, + S.Diag(ParamLoc, diag::err_template_parameter_default_in_function_template) << DefArgRange; return false; @@ -1088,20 +1088,20 @@ for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); if (NonTypeTemplateParmDecl *NTTP = dyn_cast(P)) { - if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), + if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), NTTP->getTypeSourceInfo(), Sema::UPPC_NonTypeTemplateParameterType)) return true; - + continue; } - - if (TemplateTemplateParmDecl *InnerTTP + + if (TemplateTemplateParmDecl *InnerTTP = dyn_cast(P)) if (DiagnoseUnexpandedParameterPacks(S, InnerTTP)) return true; } - + return false; } @@ -1162,7 +1162,7 @@ bool MissingDefaultArg = false; // C++0x [temp.param]p11: - // If a template parameter of a primary class template is a template + // If a template parameter of a primary class template is a template // parameter pack, it shall be the last template parameter. if (SawParameterPack && TPC == TPC_ClassTemplate) { Diag(ParameterPackLoc, @@ -1173,9 +1173,9 @@ if (TemplateTypeParmDecl *NewTypeParm = dyn_cast(*NewParam)) { // Check the presence of a default argument here. - if (NewTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewTypeParm->getLocation(), + if (NewTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTypeParm->getLocation(), NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() .getSourceRange())) NewTypeParm->removeDefaultArgument(); @@ -1212,16 +1212,16 @@ = dyn_cast(*NewParam)) { // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), - NewNonTypeParm->getTypeSourceInfo(), + NewNonTypeParm->getTypeSourceInfo(), UPPC_NonTypeTemplateParameterType)) { Invalid = true; continue; } // Check the presence of a default argument here. - if (NewNonTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewNonTypeParm->getLocation(), + if (NewNonTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewNonTypeParm->getLocation(), NewNonTypeParm->getDefaultArgument()->getSourceRange())) { NewNonTypeParm->removeDefaultArgument(); } @@ -1261,16 +1261,16 @@ // Check the presence of a default argument here. TemplateTemplateParmDecl *NewTemplateParm = cast(*NewParam); - + // Check for unexpanded parameter packs, recursively. if (DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) { Invalid = true; continue; } - - if (NewTemplateParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewTemplateParm->getLocation(), + + if (NewTemplateParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTemplateParm->getLocation(), NewTemplateParm->getDefaultArgument().getSourceRange())) NewTemplateParm->removeDefaultArgument(); @@ -1317,8 +1317,8 @@ Invalid = true; } else if (MissingDefaultArg) { // C++ [temp.param]p11: - // If a template-parameter of a class template has a default - // template-argument, each subsequent template-parameter shall either + // If a template-parameter of a class template has a default + // template-argument, each subsequent template-parameter shall either // have a default template-argument supplied or be a template parameter // pack. Diag((*NewParam)->getLocation(), @@ -1342,14 +1342,14 @@ NewParam != NewParamEnd; ++NewParam) { if (TemplateTypeParmDecl *TTP = dyn_cast(*NewParam)) TTP->removeDefaultArgument(); - else if (NonTypeTemplateParmDecl *NTTP + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*NewParam)) NTTP->removeDefaultArgument(); else cast(*NewParam)->removeDefaultArgument(); } } - + return Invalid; } @@ -1455,7 +1455,7 @@ bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; - + // Find the template-ids that occur within the nested-name-specifier. These // template-ids will match up with the template parameter lists. llvm::SmallVector @@ -1610,12 +1610,12 @@ ExplicitSpecializationsInSpecifier.pop_back(); } - // We have a template parameter list with no corresponding scope, which + // We have a template parameter list with no corresponding scope, which // means that the resulting template declaration can't be instantiated // properly (we'll end up with dependent nodes when we shouldn't). if (!isExplicitSpecHeader) Invalid = true; - + ++ParamIdx; } } @@ -1688,7 +1688,7 @@ if (!isa(Record) && !Record->getDescribedClassTemplate()) continue; - + // Fetch the injected class name type and check whether its // injected type is equal to the type we just built. QualType ICNT = Context.getTypeDeclType(Record); @@ -1711,7 +1711,7 @@ // corresponds to these arguments. void *InsertPos = 0; ClassTemplateSpecializationDecl *Decl - = ClassTemplate->findSpecialization(Converted.data(), Converted.size(), + = ClassTemplate->findSpecialization(Converted.data(), Converted.size(), InsertPos); if (!Decl) { // This is the first time we have referenced this class template @@ -1722,7 +1722,7 @@ ClassTemplate->getDeclContext(), ClassTemplate->getLocation(), ClassTemplate, - Converted.data(), + Converted.data(), Converted.size(), 0); ClassTemplate->AddSpecialization(Decl, InsertPos); Decl->setLexicalDeclContext(CurContext); @@ -1830,12 +1830,12 @@ // We don't want lookup warnings at this point. R.suppressDiagnostics(); - + UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupNameInfo(), - RequiresADL, TemplateArgs, + RequiresADL, TemplateArgs, R.begin(), R.end()); return Owned(ULE); @@ -1859,7 +1859,7 @@ if (R.isAmbiguous()) return ExprError(); - + if (R.empty()) { Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_non_template) << NameInfo.getName() << SS.getRange(); @@ -1884,7 +1884,7 @@ /// example, given "MetaFun::template apply", the scope specifier \p /// SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. -TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, +TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, SourceLocation TemplateKWLoc, CXXScopeSpec &SS, UnqualifiedId &Name, @@ -1894,8 +1894,8 @@ if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TemplateKWLoc, diag::ext_template_outside_of_template) - << FixItHint::CreateRemoval(TemplateKWLoc); - + << FixItHint::CreateRemoval(TemplateKWLoc); + DeclContext *LookupCtx = 0; if (SS.isSet()) LookupCtx = computeDeclContext(SS, EnteringContext); @@ -1927,7 +1927,7 @@ cast(LookupCtx)->hasAnyDependentBases()) { // This is a dependent template. Handle it below. } else if (TNK == TNK_Non_template) { - Diag(Name.getSourceRange().getBegin(), + Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() @@ -1941,13 +1941,13 @@ NestedNameSpecifier *Qualifier = static_cast(SS.getScopeRep()); - + switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.Identifier)); return TNK_Dependent_template_name; - + case UnqualifiedId::IK_OperatorFunctionId: Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.OperatorFunctionId.Operator)); @@ -1959,8 +1959,8 @@ default: break; } - - Diag(Name.getSourceRange().getBegin(), + + Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() @@ -2018,7 +2018,7 @@ /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -2046,9 +2046,9 @@ // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. if (ArgType->getType()->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); - + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); @@ -2056,7 +2056,7 @@ Template, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - + ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, Param->getDefaultArgumentLoc(), Param->getDeclName()); @@ -2071,7 +2071,7 @@ /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -2094,12 +2094,12 @@ SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, llvm::SmallVectorImpl &Converted) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); - + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted.data(), Converted.size(), @@ -2114,7 +2114,7 @@ /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -2137,27 +2137,27 @@ SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, llvm::SmallVectorImpl &Converted) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); - + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - + return SemaRef.SubstTemplateName( Param->getDefaultArgument().getArgument().getAsTemplate(), - Param->getDefaultArgument().getTemplateNameLoc(), + Param->getDefaultArgument().getTemplateNameLoc(), AllTemplateArgs); } /// \brief If the given template parameter has a default template /// argument, substitute into that default template argument and /// return the corresponding template argument. -TemplateArgumentLoc +TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, @@ -2201,14 +2201,14 @@ return TemplateArgumentLoc(); TemplateName TName = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, + TemplateLoc, RAngleLoc, TempTempParm, Converted); if (TName.isNull()) return TemplateArgumentLoc(); - return TemplateArgumentLoc(TemplateArgument(TName), + return TemplateArgumentLoc(TemplateArgument(TName), TempTempParm->getDefaultArgument().getTemplateQualifierRange(), TempTempParm->getDefaultArgument().getTemplateNameLoc()); } @@ -2216,7 +2216,7 @@ /// \brief Check that the given template argument corresponds to the given /// template parameter. /// -/// \param Param The template parameter against which the argument will be +/// \param Param The template parameter against which the argument will be /// checked. /// /// \param Arg The template argument. @@ -2250,16 +2250,16 @@ // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) return CheckTemplateTypeArgument(TTP, Arg, Converted); - + // Check non-type template parameters. - if (NonTypeTemplateParmDecl *NTTP =dyn_cast(Param)) { + if (NonTypeTemplateParmDecl *NTTP =dyn_cast(Param)) { // Do substitution on the type of the non-type template parameter // with the template arguments we've seen thus far. But if the // template has a dependent context then we cannot substitute yet. QualType NTTPType = NTTP->getType(); if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) NTTPType = NTTP->getExpansionType(ArgumentPackIndex); - + if (NTTPType->isDependentType() && !isa(Template) && !Template->getDeclContext()->isDependentContext()) { @@ -2267,8 +2267,8 @@ InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); NTTPType = SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), @@ -2282,29 +2282,29 @@ if (NTTPType.isNull()) return true; } - + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); return true; - + case TemplateArgument::Expression: { Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK)) return true; - + Converted.push_back(Result); break; } - + case TemplateArgument::Declaration: case TemplateArgument::Integral: // We've already checked this template argument, so just copy // it to the list of converted arguments. Converted.push_back(Arg.getArgument()); break; - + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: // We were given a template template argument. It may not be ill-formed; @@ -2324,39 +2324,39 @@ DTN->getQualifier(), Arg.getTemplateQualifierRange(), NameInfo); - + // If we parsed the template argument as a pack expansion, create a // pack expansion expression. if (Arg.getArgument().getKind() == TemplateArgument::TemplateExpansion){ - ExprResult Expansion = ActOnPackExpansion(E, + ExprResult Expansion = ActOnPackExpansion(E, Arg.getTemplateEllipsisLoc()); if (Expansion.isInvalid()) return true; - + E = Expansion.get(); } - + TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) return true; - + Converted.push_back(Result); break; } - + // We have a template argument that actually does refer to a class // template, template alias, or template template parameter, and // therefore cannot be a non-type template argument. Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) << Arg.getSourceRange(); - + Diag(Param->getLocation(), diag::note_template_param_here); return true; - + case TemplateArgument::Type: { // We have a non-type template parameter but the template // argument is a type. - + // C++ [temp.arg]p2: // In a template-argument, an ambiguity between a type-id and // an expression is resolved to a type-id, regardless of the @@ -2373,19 +2373,19 @@ Diag(Param->getLocation(), diag::note_template_param_here); return true; } - + case TemplateArgument::Pack: llvm_unreachable("Caller must expand template argument packs"); break; } - + return false; - } - - + } + + // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast(Param); - + // Substitute into the template parameter list of the template // template parameter, since previously-supplied template arguments // may appear within the template template parameter. @@ -2395,36 +2395,36 @@ InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); TempParm = cast_or_null( - SubstDecl(TempParm, CurContext, + SubstDecl(TempParm, CurContext, MultiLevelTemplateArgumentList(TemplateArgs))); if (!TempParm) return true; } - + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); return true; - + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: if (CheckTemplateArgument(TempParm, Arg)) return true; - + Converted.push_back(Arg.getArgument()); break; - + case TemplateArgument::Expression: case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); return true; - + case TemplateArgument::Declaration: llvm_unreachable( "Declaration argument with template template parameter"); @@ -2433,12 +2433,12 @@ llvm_unreachable( "Integral argument with template template parameter"); break; - + case TemplateArgument::Pack: llvm_unreachable("Caller must expand template argument packs"); break; } - + return false; } @@ -2496,9 +2496,9 @@ if (ArgIdx < NumArgs) { // If we have an expanded parameter pack, make sure we don't have too // many arguments. - if (NonTypeTemplateParmDecl *NTTP + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { - if (NTTP->isExpandedParameterPack() && + if (NTTP->isExpandedParameterPack() && ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << true @@ -2511,13 +2511,13 @@ return true; } } - + // Check the template argument we were given. - if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, + if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, + TemplateLoc, RAngleLoc, ArgumentPack.size(), Converted)) return true; - + if ((*Param)->isTemplateParameterPack()) { // The template parameter was a template parameter pack, so take the // deduced argument and place it on the argument pack. Note that we @@ -2532,19 +2532,19 @@ ++ArgIdx; continue; } - - // If we have a template parameter pack with no more corresponding + + // If we have a template parameter pack with no more corresponding // arguments, just break out now and we'll fill in the argument pack below. if ((*Param)->isTemplateParameterPack()) break; - + // We have a default template argument that we will use. TemplateArgumentLoc Arg; - + // Retrieve the default template argument from the template // parameter. For each kind of template parameter, we substitute the // template arguments provided thus far and any "outer" template arguments - // (when the template parameter was part of a nested template) into + // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast(*Param)) { if (!TTP->hasDefaultArgument()) { @@ -2552,7 +2552,7 @@ break; } - TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, @@ -2560,7 +2560,7 @@ Converted); if (!ArgType) return true; - + Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType); } else if (NonTypeTemplateParmDecl *NTTP @@ -2571,9 +2571,9 @@ } ExprResult E = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NTTP, + TemplateLoc, + RAngleLoc, + NTTP, Converted); if (E.isInvalid()) return true; @@ -2590,74 +2590,74 @@ } TemplateName Name = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, + TemplateLoc, + RAngleLoc, TempParm, Converted); if (Name.isNull()) return true; - - Arg = TemplateArgumentLoc(TemplateArgument(Name), + + Arg = TemplateArgumentLoc(TemplateArgument(Name), TempParm->getDefaultArgument().getTemplateQualifierRange(), TempParm->getDefaultArgument().getTemplateNameLoc()); } - + // Introduce an instantiation record that describes where we are using // the default template argument. InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param, Converted.data(), Converted.size(), - SourceRange(TemplateLoc, RAngleLoc)); - + SourceRange(TemplateLoc, RAngleLoc)); + // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, Converted)) return true; - + // Move to the next template parameter and argument. ++Param; ++ArgIdx; } - + // Form argument packs for each of the parameter packs remaining. while (Param != ParamEnd) { // If we're checking a partial list of template arguments, don't fill // in arguments for non-template parameter packs. - - if ((*Param)->isTemplateParameterPack()) { + + if ((*Param)->isTemplateParameterPack()) { if (PartialTemplateArgs && ArgumentPack.empty()) { Converted.push_back(TemplateArgument()); } else if (ArgumentPack.empty()) Converted.push_back(TemplateArgument(0, 0)); else { - Converted.push_back(TemplateArgument::CreatePackCopy(Context, - ArgumentPack.data(), + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), ArgumentPack.size())); ArgumentPack.clear(); } } - + ++Param; } - + return Invalid; } namespace { - class UnnamedLocalNoLinkageFinder - : public TypeVisitor + class UnnamedLocalNoLinkageFinder + : public TypeVisitor { Sema &S; SourceRange SR; - + typedef TypeVisitor inherited; - + public: UnnamedLocalNoLinkageFinder(Sema &S, SourceRange SR) : S(S), SR(SR) { } - bool Visit(QualType T) { - return inherited::Visit(T.getTypePtr()); + bool Visit(QualType T) { + return inherited::Visit(T.getTypePtr()); } - + #define TYPE(Class, Parent) \ bool Visit##Class##Type(const Class##Type *); #define ABSTRACT_TYPE(Class, Parent) \ @@ -2665,13 +2665,13 @@ #define NON_CANONICAL_TYPE(Class, Parent) \ bool Visit##Class##Type(const Class##Type *) { return false; } #include "clang/AST/TypeNodes.def" - + bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); }; } -bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { +bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { return false; } @@ -2679,52 +2679,52 @@ return Visit(T->getElementType()); } -bool UnnamedLocalNoLinkageFinder::VisitPointerType(const PointerType* T) { +bool UnnamedLocalNoLinkageFinder::VisitPointerType(const PointerType* T) { return Visit(T->getPointeeType()); } bool UnnamedLocalNoLinkageFinder::VisitBlockPointerType( - const BlockPointerType* T) { + const BlockPointerType* T) { return Visit(T->getPointeeType()); } bool UnnamedLocalNoLinkageFinder::VisitLValueReferenceType( - const LValueReferenceType* T) { + const LValueReferenceType* T) { return Visit(T->getPointeeType()); } bool UnnamedLocalNoLinkageFinder::VisitRValueReferenceType( - const RValueReferenceType* T) { + const RValueReferenceType* T) { return Visit(T->getPointeeType()); } bool UnnamedLocalNoLinkageFinder::VisitMemberPointerType( - const MemberPointerType* T) { + const MemberPointerType* T) { return Visit(T->getPointeeType()) || Visit(QualType(T->getClass(), 0)); } bool UnnamedLocalNoLinkageFinder::VisitConstantArrayType( - const ConstantArrayType* T) { + const ConstantArrayType* T) { return Visit(T->getElementType()); } bool UnnamedLocalNoLinkageFinder::VisitIncompleteArrayType( - const IncompleteArrayType* T) { + const IncompleteArrayType* T) { return Visit(T->getElementType()); } bool UnnamedLocalNoLinkageFinder::VisitVariableArrayType( - const VariableArrayType* T) { + const VariableArrayType* T) { return Visit(T->getElementType()); } bool UnnamedLocalNoLinkageFinder::VisitDependentSizedArrayType( - const DependentSizedArrayType* T) { + const DependentSizedArrayType* T) { return Visit(T->getElementType()); } bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( - const DependentSizedExtVectorType* T) { + const DependentSizedExtVectorType* T) { return Visit(T->getElementType()); } @@ -2739,12 +2739,12 @@ bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType( const FunctionProtoType* T) { for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), - AEnd = T->arg_type_end(); + AEnd = T->arg_type_end(); A != AEnd; ++A) { if (Visit(*A)) return true; } - + return Visit(T->getResultType()); } @@ -2832,8 +2832,8 @@ S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) << S.Context.getTypeDeclType(Tag) << SR; return true; - } - + } + if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) { S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here); @@ -2847,13 +2847,13 @@ NestedNameSpecifier *NNS) { if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix())) return true; - + switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::Global: return false; - + case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: return Visit(QualType(NNS->getAsType(), 0)); @@ -2896,7 +2896,7 @@ /// \brief Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -static bool +static bool CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, @@ -3037,7 +3037,7 @@ // A value of reference type is not an object. if (Var->getType()->isReferenceType()) { - S.Diag(Arg->getSourceRange().getBegin(), + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_reference_var) << Var->getType() << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); @@ -3101,7 +3101,7 @@ return true; } - if (ParamType->isPointerType() && + if (ParamType->isPointerType() && !ParamType->getAs()->getPointeeType()->isFunctionType() && S.IsQualificationConversion(ArgType, ParamType, false)) { // For pointer-to-object types, qualification conversions are @@ -3128,7 +3128,7 @@ << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; - } + } } } @@ -3157,7 +3157,7 @@ /// \brief Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, +bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted) { bool Invalid = false; @@ -3194,13 +3194,13 @@ if (DRE && !DRE->getQualifier()) DRE = 0; } - } + } // A constant of pointer-to-member type. else if ((DRE = dyn_cast(Arg))) { if (ValueDecl *VD = dyn_cast(DRE->getDecl())) { if (VD->getType()->isMemberPointerType()) { if (isa(VD) || - (isa(VD) && + (isa(VD) && Context.getCanonicalType(VD->getType()).isConstQualified())) { if (Arg->isTypeDependent() || Arg->isValueDependent()) Converted = TemplateArgument(Arg); @@ -3210,10 +3210,10 @@ } } } - + DRE = 0; } - + if (!DRE) return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_pointer_to_member_form) @@ -3343,8 +3343,8 @@ if (!Arg->isValueDependent()) { llvm::APSInt OldValue = Value; - - // Coerce the template argument's value to the value it will have + + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) @@ -3399,7 +3399,7 @@ // from a template argument of type std::nullptr_t to a non-type // template parameter of type pointer to object, pointer to // function, or pointer-to-member, respectively. - if (ArgType->isNullPtrType() && + if (ArgType->isNullPtrType() && (ParamType->isPointerType() || ParamType->isMemberPointerType())) { Converted = TemplateArgument((NamedDecl *)0); return false; @@ -3430,7 +3430,7 @@ ->isFunctionType())) { if (Arg->getType() == Context.OverloadTy) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) @@ -3441,10 +3441,10 @@ } else return true; } - + if (!ParamType->isMemberPointerType()) return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, + ParamType, Arg, Converted); if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), @@ -3471,7 +3471,7 @@ assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); } @@ -3487,8 +3487,8 @@ "Only object references allowed here"); if (Arg->getType() == Context.OverloadTy) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, - ParamRefType->getPointeeType(), + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) @@ -3499,8 +3499,8 @@ } else return true; } - - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); } @@ -3562,7 +3562,7 @@ return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Param->getTemplateParameters(), - true, + true, TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); } @@ -3571,7 +3571,7 @@ /// declaration and the type of its corresponding non-type template /// parameter, produce an expression that properly refers to that /// declaration. -ExprResult +ExprResult Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc) { @@ -3579,7 +3579,7 @@ "Only declaration template arguments permitted here"); ValueDecl *VD = cast(Arg.getAsDecl()); - if (VD->getDeclContext()->isRecord() && + if (VD->getDeclContext()->isRecord() && (isa(VD) || isa(VD))) { // If the value is a class member, we might have a pointer-to-member. // Determine whether the non-type template template parameter is of @@ -3602,16 +3602,16 @@ if (isa(VD) && cast(VD)->isInstance()) VK = VK_RValue; - ExprResult RefExpr = BuildDeclRefExpr(VD, + ExprResult RefExpr = BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), VK, Loc, &SS); if (RefExpr.isInvalid()) return ExprError(); - + RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - + // We might need to perform a trailing qualification conversion, since // the element type on the parameter could be more qualified than the // element type in the expression we constructed. @@ -3621,14 +3621,14 @@ ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp); RefExpr = Owned(RefE); } - + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), ParamType.getUnqualifiedType())); return move(RefExpr); } } - + QualType T = VD->getType().getNonReferenceType(); if (ParamType->isPointerType()) { // When the non-type template parameter is a pointer, take the @@ -3648,7 +3648,7 @@ return move(RefExpr); } - + // Take the address of everything else return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); } @@ -3663,7 +3663,7 @@ T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers()); } - + return BuildDeclRefExpr(VD, T, VK, Loc); } @@ -3674,7 +3674,7 @@ /// This routine takes care of the mapping from an integral template /// argument (which may have any integral type) to the appropriate /// literal value. -ExprResult +ExprResult Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc) { assert(Arg.getKind() == TemplateArgument::Integral && @@ -3722,12 +3722,12 @@ S.Diag(Old->getLocation(), diag::note_template_prev_declaration) << (Kind != Sema::TPL_TemplateMatch); } - + return false; } - // Check that both are parameter packs are neither are parameter packs. - // However, if we are matching a template template argument to a + // Check that both are parameter packs are neither are parameter packs. + // However, if we are matching a template template argument to a // template template parameter, the template template parameter can have // a parameter pack where the template template argument does not. if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() && @@ -3740,7 +3740,7 @@ diag::err_template_arg_template_params_mismatch); NextDiag = diag::note_template_parameter_pack_non_pack; } - + unsigned ParamKind = isa(New)? 0 : isa(New)? 1 : 2; @@ -3749,15 +3749,15 @@ S.Diag(Old->getLocation(), diag::note_template_parameter_pack_here) << ParamKind << Old->isParameterPack(); } - + return false; } - + // For non-type template parameters, check the type of the parameter. if (NonTypeTemplateParmDecl *OldNTTP = dyn_cast(Old)) { NonTypeTemplateParmDecl *NewNTTP = cast(New); - + // If we are matching a template template argument to a template // template parameter and one of the non-type template parameter types // is dependent, then we must wait until template instantiation time @@ -3766,12 +3766,12 @@ (OldNTTP->getType()->isDependentType() || NewNTTP->getType()->isDependentType())) return true; - + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { if (Complain) { unsigned NextDiag = diag::err_template_nontype_parm_different_type; if (TemplateArgLoc.isValid()) { - S.Diag(TemplateArgLoc, + S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); NextDiag = diag::note_template_nontype_parm_different_type; } @@ -3782,35 +3782,35 @@ diag::note_template_nontype_parm_prev_declaration) << OldNTTP->getType(); } - + return false; } - + return true; } - + // For template template parameters, check the template parameter types. // The template parameter lists of template template // parameters must agree. if (TemplateTemplateParmDecl *OldTTP = dyn_cast(Old)) { - TemplateTemplateParmDecl *NewTTP = cast(New); + TemplateTemplateParmDecl *NewTTP = cast(New); return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), OldTTP->getTemplateParameters(), Complain, (Kind == Sema::TPL_TemplateMatch - ? Sema::TPL_TemplateTemplateParmMatch + ? Sema::TPL_TemplateTemplateParmMatch : Kind), TemplateArgLoc); } - + return true; } /// \brief Diagnose a known arity mismatch when comparing template argument /// lists. static -void DiagnoseTemplateParameterListArityMismatch(Sema &S, +void DiagnoseTemplateParameterListArityMismatch(Sema &S, TemplateParameterList *New, TemplateParameterList *Old, Sema::TemplateParameterListEqualKind Kind, @@ -3883,18 +3883,18 @@ if (Complain) DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, TemplateArgLoc); - + return false; } - + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, Kind, TemplateArgLoc)) - return false; - + return false; + ++NewParm; continue; } - + // C++0x [temp.arg.template]p3: // [...] When P's template- parameter-list contains a template parameter // pack (14.5.3), the template parameter pack will match zero or more @@ -3905,19 +3905,19 @@ for (; NewParm != NewParmEnd; ++NewParm) { if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, Kind, TemplateArgLoc)) - return false; + return false; } } - + // Make sure we exhausted all of the arguments. if (NewParm != NewParmEnd) { if (Complain) DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, TemplateArgLoc); - + return false; } - + return true; } @@ -3957,18 +3957,18 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) { if (!D) return TSK_Undeclared; - + if (CXXRecordDecl *Record = dyn_cast(D)) return Record->getTemplateSpecializationKind(); if (FunctionDecl *Function = dyn_cast(D)) return Function->getTemplateSpecializationKind(); if (VarDecl *Var = dyn_cast(D)) return Var->getTemplateSpecializationKind(); - + return TSK_Undeclared; } -/// \brief Check whether a specialization is well-formed in the current +/// \brief Check whether a specialization is well-formed in the current /// context. /// /// This routine determines whether a template specialization can be declared @@ -3979,7 +3979,7 @@ /// /// \param Specialized the entity being specialized or instantiated, which /// may be a kind of template (class template, function template, etc.) or -/// a member of a class template (member function, static data member, +/// a member of a class template (member function, static data member, /// member class). /// /// \param PrevDecl the previous declaration of this entity, if any. @@ -4040,28 +4040,28 @@ << Specialized; return true; } - + // C++ [temp.class.spec]p6: // A class template partial specialization may be declared or redeclared - // in any namespace scope in which its definition may be defined (14.5.1 - // and 14.5.2). + // in any namespace scope in which its definition may be defined (14.5.1 + // and 14.5.2). bool ComplainedAboutScope = false; - DeclContext *SpecializedContext + DeclContext *SpecializedContext = Specialized->getDeclContext()->getEnclosingNamespaceContext(); DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); - if ((!PrevDecl || + if ((!PrevDecl || getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared || getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){ // C++ [temp.exp.spec]p2: // An explicit specialization shall be declared in the namespace of which - // the template is a member, or, for member templates, in the namespace + // the template is a member, or, for member templates, in the namespace // of which the enclosing class or enclosing class template is a member. - // An explicit specialization of a member function, member class or - // static data member of a class template shall be declared in the + // An explicit specialization of a member function, member class or + // static data member of a class template shall be declared in the // namespace of which the class template is a member. // // C++0x [temp.expl.spec]p2: - // An explicit specialization shall be declared in a namespace enclosing + // An explicit specialization shall be declared in a namespace enclosing // the specialized template. if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) && !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) { @@ -4078,15 +4078,15 @@ : diag::err_template_spec_decl_out_of_scope) << EntityKind << Specialized << cast(SpecializedContext); - + S.Diag(Specialized->getLocation(), diag::note_specialized_entity); ComplainedAboutScope = true; } } - - // Make sure that this redeclaration (or definition) occurs in an enclosing + + // Make sure that this redeclaration (or definition) occurs in an enclosing // namespace. - // Note that HandleDeclarator() performs this check for explicit + // Note that HandleDeclarator() performs this check for explicit // specializations of function templates, static data members, and member // functions, so we skip the check here for those kinds of entities. // FIXME: HandleDeclarator's diagnostics aren't quite as good, though. @@ -4101,15 +4101,15 @@ S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope) << EntityKind << Specialized << cast(SpecializedContext); - + S.Diag(Specialized->getLocation(), diag::note_specialized_entity); } - + // FIXME: check for specialization-after-instantiation errors and such. - + return false; } - + /// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs /// that checks non-type template partial specialization arguments. static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, @@ -4119,13 +4119,13 @@ for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].getKind() == TemplateArgument::Pack) { if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, - Args[I].pack_begin(), + Args[I].pack_begin(), Args[I].pack_size())) return true; - + continue; } - + Expr *ArgExpr = Args[I].getAsExpr(); if (!ArgExpr) { continue; @@ -4138,7 +4138,7 @@ // Strip off any implicit casts we added as part of type checking. while (ImplicitCastExpr *ICE = dyn_cast(ArgExpr)) ArgExpr = ICE->getSubExpr(); - + // C++ [temp.class.spec]p8: // A non-type argument is non-specialized if it is the name of a // non-type parameter. All other non-type arguments are @@ -4150,7 +4150,7 @@ if (DeclRefExpr *DRE = dyn_cast(ArgExpr)) if (isa(DRE->getDecl())) continue; - + // C++ [temp.class.spec]p9: // Within the argument list of a class template partial // specialization, the following restrictions apply: @@ -4164,7 +4164,7 @@ << ArgExpr->getSourceRange(); return true; } - + // -- The type of a template parameter corresponding to a // specialized non-type argument shall not be dependent on a // parameter of the specialization. @@ -4177,10 +4177,10 @@ return true; } } - + return false; } - + /// \brief Check the non-type template arguments of a class template /// partial specialization according to C++ [temp.class.spec]p9. /// @@ -4202,7 +4202,7 @@ if (!Param) continue; - if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, + if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1)) return true; } @@ -4248,7 +4248,7 @@ if (!ClassTemplate) { Diag(TemplateNameLoc, diag::err_not_class_template_specialization) - << (Name.getAsTemplateDecl() && + << (Name.getAsTemplateDecl() && isa(Name.getAsTemplateDecl())); return true; } @@ -4270,7 +4270,7 @@ Invalid); if (Invalid) return true; - + unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); if (TemplateParams) --NumMatchedTemplateParamLists; @@ -4283,7 +4283,7 @@ << SourceRange(LAngleLoc, RAngleLoc); return true; } - + // C++ [temp.class.spec]p10: // The template parameter list of a specialization shall not // contain default template argument values. @@ -4352,10 +4352,10 @@ // Check for unexpanded parameter packs in any of the template arguments. for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - if (DiagnoseUnexpandedParameterPack(TemplateArgs[I], + if (DiagnoseUnexpandedParameterPack(TemplateArgs[I], UPPC_PartialSpecialization)) return true; - + // Check that the template argument list is well-formed for this // template. llvm::SmallVector Converted; @@ -4374,9 +4374,9 @@ Converted)) return true; - if (!Name.isDependent() && + if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), + TemplateArgs.getArgumentArray(), TemplateArgs.size())) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); @@ -4403,14 +4403,14 @@ // Check whether we can declare a class template specialization in // the current scope. if (TUK != TUK_Friend && - CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, - TemplateNameLoc, + CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, + TemplateNameLoc, isPartialSpecialization)) return true; - + // The canonical type QualType CanonType; - if (PrevDecl && + if (PrevDecl && (PrevDecl->getSpecializationKind() == TSK_Undeclared || TUK == TUK_Friend)) { // Since the only prior class template specialization with these @@ -4429,8 +4429,8 @@ CanonType = Context.getTemplateSpecializationType(CanonTemplate, Converted.data(), Converted.size()); - - if (Context.hasSameType(CanonType, + + if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization())) { // C++ [temp.class.spec]p9b3: // @@ -4475,18 +4475,18 @@ ClassTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; - // If we are providing an explicit specialization of a member class + // If we are providing an explicit specialization of a member class // template specialization, make a note of that. if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - + // Check that all of the template parameters of the class template // partial specialization are deducible from the template // arguments. If not, this class template partial specialization // will never be used. llvm::SmallVector DeducibleParams; DeducibleParams.resize(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, TemplateParams->getDepth(), DeducibleParams); unsigned NumNonDeducible = 0; @@ -4538,9 +4538,9 @@ // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that specialization shall be declared + // explicitly specialized then that specialization shall be declared // before the first use of that specialization that would cause an implicit - // instantiation to take place, in every translation unit in which such a + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { bool Okay = false; @@ -4557,14 +4557,14 @@ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) << Context.getTypeDeclType(Specialization) << Range; - Diag(PrevDecl->getPointOfInstantiation(), + Diag(PrevDecl->getPointOfInstantiation(), diag::note_instantiation_required_here) - << (PrevDecl->getTemplateSpecializationKind() + << (PrevDecl->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); return true; } } - + // If this is not a friend, note that this is an explicit specialization. if (TUK != TUK_Friend) Specialization->setSpecializationKind(TSK_ExplicitSpecialization); @@ -4671,12 +4671,12 @@ } } -/// \brief Diagnose cases where we have an explicit template specialization +/// \brief Diagnose cases where we have an explicit template specialization /// before/after an explicit template instantiation, producing diagnostics -/// for those cases where they are required and determining whether the +/// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. /// -/// \param NewLoc the location of the new explicit specialization or +/// \param NewLoc the location of the new explicit specialization or /// instantiation. /// /// \param NewTSK the kind of the new explicit specialization or instantiation. @@ -4685,10 +4685,10 @@ /// /// \param PrevTSK the kind of the old explicit specialization or instantiatin. /// -/// \param PrevPointOfInstantiation if valid, indicates where the previus +/// \param PrevPointOfInstantiation if valid, indicates where the previus /// declaration was instantiated (either implicitly or explicitly). /// -/// \param HasNoEffect will be set to true to indicate that the new +/// \param HasNoEffect will be set to true to indicate that the new /// specialization or instantiation has no effect and should be ignored. /// /// \returns true if there was an error that should prevent the introduction of @@ -4701,18 +4701,18 @@ SourceLocation PrevPointOfInstantiation, bool &HasNoEffect) { HasNoEffect = false; - + switch (NewTSK) { case TSK_Undeclared: case TSK_ImplicitInstantiation: assert(false && "Don't check implicit instantiations here"); return false; - + case TSK_ExplicitSpecialization: switch (PrevTSK) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - // Okay, we're just specializing something that is either already + // Okay, we're just specializing something that is either already // explicitly specialized or has merely been mentioned without any // instantiation. return false; @@ -4725,17 +4725,17 @@ return false; } // Fall through - + case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: - assert((PrevTSK == TSK_ImplicitInstantiation || - PrevPointOfInstantiation.isValid()) && + assert((PrevTSK == TSK_ImplicitInstantiation || + PrevPointOfInstantiation.isValid()) && "Explicit instantiation without point of instantiation?"); - + // C++ [temp.expl.spec]p6: - // If a template, a member template or the member of a class template + // If a template, a member template or the member of a class template // is explicitly specialized then that specialization shall be declared - // before the first use of that specialization that would cause an + // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { @@ -4748,41 +4748,41 @@ << PrevDecl; Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) << (PrevTSK != TSK_ImplicitInstantiation); - + return true; } break; - + case TSK_ExplicitInstantiationDeclaration: switch (PrevTSK) { case TSK_ExplicitInstantiationDeclaration: // This explicit instantiation declaration is redundant (that's okay). HasNoEffect = true; return false; - + case TSK_Undeclared: case TSK_ImplicitInstantiation: // We're explicitly instantiating something that may have already been // implicitly instantiated; that's fine. return false; - + case TSK_ExplicitSpecialization: // C++0x [temp.explicit]p4: // For a given set of template parameters, if an explicit instantiation - // of a template appears after a declaration of an explicit + // of a template appears after a declaration of an explicit // specialization for that template, the explicit instantiation has no // effect. HasNoEffect = true; return false; - + case TSK_ExplicitInstantiationDefinition: // C++0x [temp.explicit]p10: - // If an entity is the subject of both an explicit instantiation - // declaration and an explicit instantiation definition in the same + // If an entity is the subject of both an explicit instantiation + // declaration and an explicit instantiation definition in the same // translation unit, the definition shall follow the declaration. - Diag(NewLoc, + Diag(NewLoc, diag::err_explicit_instantiation_declaration_after_definition); - Diag(PrevPointOfInstantiation, + Diag(PrevPointOfInstantiation, diag::note_explicit_instantiation_definition_here); assert(PrevPointOfInstantiation.isValid() && "Explicit instantiation without point of instantiation?"); @@ -4790,7 +4790,7 @@ return false; } break; - + case TSK_ExplicitInstantiationDefinition: switch (PrevTSK) { case TSK_Undeclared: @@ -4798,7 +4798,7 @@ // We're explicitly instantiating something that may have already been // implicitly instantiated; that's fine. return false; - + case TSK_ExplicitSpecialization: // C++ DR 259, C++0x [temp.explicit]p4: // For a given set of template parameters, if an explicit @@ -4806,7 +4806,7 @@ // an explicit specialization for that template, the explicit // instantiation has no effect. // - // In C++98/03 mode, we only give an extension warning here, because it + // In C++98/03 mode, we only give an extension warning here, because it // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. if (!getLangOptions().CPlusPlus0x) { @@ -4817,12 +4817,12 @@ } HasNoEffect = true; return false; - + case TSK_ExplicitInstantiationDeclaration: // We're explicity instantiating a definition for something for which we - // were previously asked to suppress instantiations. That's fine. + // were previously asked to suppress instantiations. That's fine. return false; - + case TSK_ExplicitInstantiationDefinition: // C++0x [temp.spec]p5: // For a given template and a given set of template-arguments, @@ -4830,16 +4830,16 @@ // in a program, Diag(NewLoc, diag::err_explicit_instantiation_duplicate) << PrevDecl; - Diag(PrevPointOfInstantiation, + Diag(PrevPointOfInstantiation, diag::note_previous_explicit_instantiation); HasNoEffect = true; - return false; + return false; } break; } - + assert(false && "Missing specialization/instantiation case?"); - + return false; } @@ -4905,21 +4905,21 @@ // The set of function template specializations that could match this // explicit function template specialization. UnresolvedSet<8> Candidates; - + DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { NamedDecl *Ovl = (*I)->getUnderlyingDecl(); if (FunctionTemplateDecl *FunTmpl = dyn_cast(Ovl)) { - // Only consider templates found within the same semantic lookup scope as + // Only consider templates found within the same semantic lookup scope as // FD. if (!FDLookupContext->InEnclosingNamespaceSetOf( Ovl->getDeclContext()->getRedeclContext())) continue; - + // C++ [temp.expl.spec]p11: - // A trailing template-argument can be left unspecified in the - // template-id naming an explicit function template specialization + // A trailing template-argument can be left unspecified in the + // template-id naming an explicit function template specialization // provided it can be deduced from the function argument type. // Perform template argument deduction to determine whether we may be // specializing this template. @@ -4936,17 +4936,17 @@ (void)TDK; continue; } - + // Record this candidate. Candidates.addDecl(Specialization, I.getAccess()); } } - + // Find the most specialized function template. UnresolvedSetIterator Result = getMostSpecialized(Candidates.begin(), Candidates.end(), TPOC_Other, 0, FD->getLocation(), - PDiag(diag::err_function_template_spec_no_match) + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), PDiag(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), @@ -4957,27 +4957,27 @@ // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast(*Result); Specialization->setLocation(FD->getLocation()); - + // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . // If this is a friend declaration, then we're not really declaring // an explicit specialization. bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None); - + // Check the scope of this explicit specialization. if (!isFriend && - CheckTemplateSpecializationScope(*this, + CheckTemplateSpecializationScope(*this, Specialization->getPrimaryTemplate(), - Specialization, FD->getLocation(), + Specialization, FD->getLocation(), false)) return true; // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that specialization shall be declared + // explicitly specialized then that specialization shall be declared // before the first use of that specialization that would cause an implicit - // instantiation to take place, in every translation unit in which such a + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); @@ -4992,14 +4992,14 @@ SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } - + // Turn the given function declaration into a function template // specialization, with the template arguments from the previous // specialization. @@ -5023,7 +5023,7 @@ /// \brief Perform semantic analysis for the given non-template member /// specialization. /// -/// This routine performs all of the semantic analysis required for an +/// This routine performs all of the semantic analysis required for an /// explicit member function specialization. On successful completion, /// the function declaration \p FD will become a member function /// specialization. @@ -5034,7 +5034,7 @@ /// \param Previous the set of declarations, one of which may be specialized /// by this function specialization; the set will be modified to contain the /// redeclared member. -bool +bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa(Member) && "Only for non-template members"); @@ -5076,7 +5076,7 @@ MSInfo = PrevRecord->getMemberSpecializationInfo(); } } - + if (!Instantiation) { // There is no previous declaration that matches. Since member // specializations are always out-of-line, the caller will complain about @@ -5102,7 +5102,7 @@ Previous.addDecl(Instantiation); return false; } - + // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { Diag(Member->getLocation(), diag::err_spec_member_not_instantiated) @@ -5110,12 +5110,12 @@ Diag(Instantiation->getLocation(), diag::note_specialized_decl); return true; } - + // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that spe- cialization shall be declared + // explicitly specialized then that spe- cialization shall be declared // before the first use of that specialization that would cause an implicit - // instantiation to take place, in every translation unit in which such a + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. assert(MSInfo && "Member specialization info missing?"); @@ -5127,11 +5127,11 @@ MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Check the scope of this explicit specialization. - if (CheckTemplateSpecializationScope(*this, + if (CheckTemplateSpecializationScope(*this, InstantiatedFrom, - Instantiation, Member->getLocation(), + Instantiation, Member->getLocation(), false)) return true; @@ -5147,7 +5147,7 @@ TSK_ExplicitSpecialization); InstantiationFunction->setLocation(Member->getLocation()); } - + cast(Member)->setInstantiationOfMemberFunction( cast(InstantiatedFrom), TSK_ExplicitSpecialization); @@ -5160,7 +5160,7 @@ TSK_ExplicitSpecialization); InstantiationVar->setLocation(Member->getLocation()); } - + Context.setInstantiatedFromStaticDataMember(cast(Member), cast(InstantiatedFrom), TSK_ExplicitSpecialization); @@ -5174,12 +5174,12 @@ TSK_ExplicitSpecialization); InstantiationClass->setLocation(Member->getLocation()); } - + cast(Member)->setInstantiationOfMemberClass( cast(InstantiatedFrom), TSK_ExplicitSpecialization); } - + // Save the caller the trouble of having to figure out which declaration // this specialization matches. Previous.clear(); @@ -5195,28 +5195,28 @@ bool WasQualifiedName) { DeclContext *OrigContext= D->getDeclContext()->getEnclosingNamespaceContext(); DeclContext *CurContext = S.CurContext->getRedeclContext(); - + if (CurContext->isRecord()) { S.Diag(InstLoc, diag::err_explicit_instantiation_in_class) << D; return true; } - + // C++0x [temp.explicit]p2: - // An explicit instantiation shall appear in an enclosing namespace of its + // An explicit instantiation shall appear in an enclosing namespace of its // template. // // This is DR275, which we do not retroactively apply to C++98/03. - if (S.getLangOptions().CPlusPlus0x && + if (S.getLangOptions().CPlusPlus0x && !CurContext->Encloses(OrigContext)) { if (NamespaceDecl *NS = dyn_cast(OrigContext)) - S.Diag(InstLoc, - S.getLangOptions().CPlusPlus0x? + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_out_of_scope : diag::warn_explicit_instantiation_out_of_scope_0x) << D << NS; else - S.Diag(InstLoc, + S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_must_be_global : diag::warn_explicit_instantiation_out_of_scope_0x) @@ -5226,8 +5226,8 @@ } // C++0x [temp.explicit]p2: - // If the name declared in the explicit instantiation is an unqualified - // name, the explicit instantiation shall appear in the namespace where + // If the name declared in the explicit instantiation is an unqualified + // name, the explicit instantiation shall appear in the namespace where // its template is declared or, if that namespace is inline (7.3.1), any // namespace from its enclosing namespace set. if (WasQualifiedName) @@ -5236,7 +5236,7 @@ if (CurContext->InEnclosingNamespaceSetOf(OrigContext)) return false; - S.Diag(InstLoc, + S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_unqualified_wrong_namespace : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) @@ -5249,9 +5249,9 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) return false; - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. @@ -5304,12 +5304,12 @@ // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation - // definition and an explicit instantiation declaration. An explicit - // instantiation declaration begins with the extern keyword. [...] + // definition and an explicit instantiation declaration. An explicit + // instantiation declaration begins with the extern keyword. [...] TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); @@ -5342,7 +5342,7 @@ if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc, SS.isSet())) return true; - + ClassTemplateSpecializationDecl *Specialization = 0; bool HasNoEffect = false; @@ -5489,7 +5489,7 @@ if (Tag->isInvalidDecl()) return true; - + CXXRecordDecl *Record = cast(Tag); CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); if (!Pattern) { @@ -5500,32 +5500,32 @@ } // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a class or member class, the - // elaborated-type-specifier in the declaration shall include a + // If the explicit instantiation is for a class or member class, the + // elaborated-type-specifier in the declaration shall include a // simple-template-id. // // C++98 has the same restriction, just worded differently. if (!ScopeSpecifierHasTemplateId(SS)) Diag(TemplateLoc, diag::ext_explicit_instantiation_without_qualified_id) << Record << SS.getRange(); - + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation - // definition and an explicit instantiation declaration. An explicit + // definition and an explicit instantiation declaration. An explicit // instantiation declaration begins with the extern keyword. [...] TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - + // C++0x [temp.explicit]p2: // [...] An explicit instantiation shall appear in an enclosing // namespace of its template. [...] // // This is C++ DR 275. CheckExplicitInstantiationScope(*this, Record, NameLoc, true); - + // Verify that it is okay to explicitly instantiate here. - CXXRecordDecl *PrevDecl + CXXRecordDecl *PrevDecl = cast_or_null(Record->getPreviousDeclaration()); if (!PrevDecl && Record->getDefinition()) PrevDecl = Record; @@ -5533,23 +5533,23 @@ MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); bool HasNoEffect = false; assert(MSInfo && "No member specialization information?"); - if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, PrevDecl, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; if (HasNoEffect) return TagD; } - + CXXRecordDecl *RecordDef = cast_or_null(Record->getDefinition()); if (!RecordDef) { // C++ [temp.explicit]p3: - // A definition of a member class of a class template shall be in scope + // A definition of a member class of a class template shall be in scope // at the point of an explicit instantiation of the member class. - CXXRecordDecl *Def + CXXRecordDecl *Def = cast_or_null(Pattern->getDefinition()); if (!Def) { Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) @@ -5567,8 +5567,8 @@ if (!RecordDef) return true; } - } - + } + // Instantiate all of the members of the class. InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); @@ -5597,7 +5597,7 @@ diag::err_explicit_instantiation_requires_name) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); - + return true; } @@ -5612,7 +5612,7 @@ QualType R = T->getType(); if (R.isNull()) return true; - + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { // Cannot explicitly instantiate a typedef. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) @@ -5626,31 +5626,31 @@ // Presumably, this also applies to member functions of class templates as // well. if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) - Diag(D.getDeclSpec().getInlineSpecLoc(), + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) <isFunctionType()) { // C++ [temp.explicit]p1: - // A [...] static data member of a class template can be explicitly - // instantiated from the member definition associated with its class + // A [...] static data member of a class template can be explicitly + // instantiated from the member definition associated with its class // template. if (Previous.isAmbiguous()) return true; - + VarDecl *Prev = Previous.getAsSingle(); if (!Prev || !Prev->isStaticDataMember()) { // We expect to see a data data member here. @@ -5661,54 +5661,54 @@ Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); return true; } - + if (!Prev->getInstantiatedFromStaticDataMember()) { // FIXME: Check for explicit specialization? - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_data_member_not_instantiated) << Prev; Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); // FIXME: Can we provide a note showing where this was declared? return true; } - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); - + // Check the scope of this explicit instantiation. CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); - + // Verify that it is okay to explicitly instantiate here. MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); assert(MSInfo && "Missing static data member specialization info?"); bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; if (HasNoEffect) return (Decl*) 0; - + // Instantiate static data member. Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev); - + // FIXME: Create an ExplicitInstantiation node? return (Decl*) 0; } - - // If the declarator is a template-id, translate the parser's template + + // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; @@ -5723,11 +5723,11 @@ HasExplicitTemplateArgs = true; TemplateArgsPtr.release(); } - + // C++ [temp.explicit]p1: - // A [...] function [...] can be explicitly instantiated from its template. - // A member function [...] of a class template can be explicitly - // instantiated from the member definition associated with its class + // A [...] function [...] can be explicitly instantiated from its template. + // A member function [...] of a class template can be explicitly + // instantiated from the member definition associated with its class // template. UnresolvedSet<8> Matches; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -5744,7 +5744,7 @@ } } } - + FunctionTemplateDecl *FunTmpl = dyn_cast(Prev); if (!FunTmpl) continue; @@ -5752,21 +5752,21 @@ TemplateDeductionInfo Info(Context, D.getIdentifierLoc()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, + = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? (void)TDK; continue; } - + Matches.addDecl(Specialization, P.getAccess()); } - + // Find the most specialized function template specialization. UnresolvedSetIterator Result = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, 0, - D.getIdentifierLoc(), + D.getIdentifierLoc(), PDiag(diag::err_explicit_instantiation_not_known) << Name, PDiag(diag::err_explicit_instantiation_ambiguous) << Name, PDiag(diag::note_explicit_instantiation_candidate)); @@ -5776,17 +5776,17 @@ // Ignore access control bits, we don't need them for redeclaration checking. FunctionDecl *Specialization = cast(*Result); - + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) << Specialization << (Specialization->getTemplateSpecializationKind() == TSK_ExplicitSpecialization); Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here); return true; - } - + } + FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration(); if (!PrevDecl && Specialization->isThisDeclarationADefinition()) PrevDecl = Specialization; @@ -5794,12 +5794,12 @@ if (PrevDecl) { bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, - PrevDecl, - PrevDecl->getTemplateSpecializationKind(), + PrevDecl, + PrevDecl->getTemplateSpecializationKind(), PrevDecl->getPointOfInstantiation(), HasNoEffect)) return true; - + // FIXME: We may still want to build some representation of this // explicit specialization. if (HasNoEffect) @@ -5807,12 +5807,12 @@ } Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); - + if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization); - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. @@ -5820,18 +5820,18 @@ // C++98 has the same restriction, just worded differently. FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); if (D.getName().getKind() != UnqualifiedId::IK_TemplateId && !FunTmpl && - D.getCXXScopeSpec().isSet() && + D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); - + CheckExplicitInstantiationScope(*this, - FunTmpl? (NamedDecl *)FunTmpl + FunTmpl? (NamedDecl *)FunTmpl : Specialization->getInstantiatedFromMemberFunction(), - D.getIdentifierLoc(), + D.getIdentifierLoc(), D.getCXXScopeSpec().isSet()); - + // FIXME: Create some kind of ExplicitInstantiationDecl here. return (Decl*) 0; } @@ -5861,8 +5861,8 @@ } TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, +Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); @@ -5872,8 +5872,8 @@ if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); - + << FixItHint::CreateRemoval(TypenameLoc); + QualType T = CheckTypenameType(ETK_Typename, NNS, II, TypenameLoc, SS.getRange(), IdLoc); if (T.isNull()) @@ -5891,23 +5891,23 @@ TL.setQualifierRange(SS.getRange()); cast(TL.getNamedTypeLoc()).setNameLoc(IdLoc); } - + return CreateParsedType(T, TSI); } TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, SourceLocation TemplateLoc, +Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, SourceLocation TemplateLoc, ParsedType Ty) { if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); - + << FixItHint::CreateRemoval(TypenameLoc); + TypeSourceInfo *InnerTSI = 0; QualType T = GetTypeFromParser(Ty, &InnerTSI); - assert(isa(T) && + assert(isa(T) && "Expected a template specialization type"); if (computeDeclContext(SS, false)) { @@ -6019,13 +6019,13 @@ } // Fall through to create a dependent typename type, from which we can recover // better. - + case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. return Context.getDependentNameType(Keyword, NNS, &II); case LookupResult::Found: - if (TypeDecl *Type = dyn_cast(Result.getFoundDecl())) { + if (TypeDecl *Type = dyn_cast(Result.getFoundDecl())) { // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. return Context.getElaboratedType(ETK_Typename, NNS, @@ -6036,7 +6036,7 @@ Referenced = Result.getFoundDecl(); break; - + llvm_unreachable("unresolved using decl in non-dependent context"); return QualType(); @@ -6069,7 +6069,7 @@ public: typedef TreeTransform inherited; - + CurrentInstantiationRebuilder(Sema &SemaRef, SourceLocation Loc, DeclarationName Entity) @@ -6149,7 +6149,7 @@ NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), DeclarationName()); - NestedNameSpecifier *Rebuilt = + NestedNameSpecifier *Rebuilt = Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); if (!Rebuilt) return true; @@ -6174,22 +6174,22 @@ if (!Params || Params->size() == 0 || NumArgs == 0) return std::string(); - + for (unsigned I = 0, N = Params->size(); I != N; ++I) { if (I >= NumArgs) break; - + if (I == 0) Out << "[with "; else Out << ", "; - + if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) { Out << Id->getName(); } else { Out << '$' << I; } - + Out << " = "; Args[I].print(Context.PrintingPolicy, Out); } Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jan 27 01:10:08 2011 @@ -51,7 +51,7 @@ /// may apply. TDF_SkipNonDependent = 0x08, /// \brief Whether we are performing template argument deduction for - /// parameters and arguments in a top-level template argument + /// parameters and arguments in a top-level template argument TDF_TopLevelParameterTypeList = 0x10 }; } @@ -90,21 +90,21 @@ /// \brief Whether template argument deduction for two reference parameters /// resulted in the argument type, parameter type, or neither type being more /// qualified than the other. -enum DeductionQualifierComparison { - NeitherMoreQualified = 0, - ParamMoreQualified, - ArgMoreQualified +enum DeductionQualifierComparison { + NeitherMoreQualified = 0, + ParamMoreQualified, + ArgMoreQualified }; /// \brief Stores the result of comparing two reference parameters while /// performing template argument deduction for partial ordering of function -/// templates. +/// templates. struct RefParamPartialOrderingComparison { /// \brief Whether the parameter type is an rvalue reference type. bool ParamIsRvalueRef; /// \brief Whether the argument type is an rvalue reference type. bool ArgIsRvalueRef; - + /// \brief Whether the parameter or argument (or neither) is more qualified. DeductionQualifierComparison Qualifiers; }; @@ -150,12 +150,12 @@ static bool isSameDeclaration(Decl *X, Decl *Y) { if (!X || !Y) return !X && !Y; - + if (NamedDecl *NX = dyn_cast(X)) X = NX->getUnderlyingDecl(); if (NamedDecl *NY = dyn_cast(Y)) Y = NY->getUnderlyingDecl(); - + return X->getCanonicalDecl() == Y->getCanonicalDecl(); } @@ -163,7 +163,7 @@ /// /// \returns The deduced template argument, or a NULL template argument if /// the deduced template arguments were incompatible. -static DeducedTemplateArgument +static DeducedTemplateArgument checkDeducedTemplateArguments(ASTContext &Context, const DeducedTemplateArgument &X, const DeducedTemplateArgument &Y) { @@ -171,7 +171,7 @@ if (X.isNull()) return Y; if (Y.isNull()) - return X; + return X; switch (X.getKind()) { case TemplateArgument::Null: @@ -182,9 +182,9 @@ if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(X.getAsType(), Y.getAsType())) return X; - + return DeducedTemplateArgument(); - + case TemplateArgument::Integral: // If we deduced a constant in one case and either a dependent expression or // declaration in another case, keep the integral constant. @@ -193,39 +193,39 @@ Y.getKind() == TemplateArgument::Declaration || (Y.getKind() == TemplateArgument::Integral && hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral()))) - return DeducedTemplateArgument(X, + return DeducedTemplateArgument(X, X.wasDeducedFromArrayBound() && Y.wasDeducedFromArrayBound()); // All other combinations are incompatible. return DeducedTemplateArgument(); - + case TemplateArgument::Template: if (Y.getKind() == TemplateArgument::Template && Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate())) return X; - + // All other combinations are incompatible. - return DeducedTemplateArgument(); + return DeducedTemplateArgument(); case TemplateArgument::TemplateExpansion: if (Y.getKind() == TemplateArgument::TemplateExpansion && - Context.hasSameTemplateName(X.getAsTemplateOrTemplatePattern(), + Context.hasSameTemplateName(X.getAsTemplateOrTemplatePattern(), Y.getAsTemplateOrTemplatePattern())) return X; - + // All other combinations are incompatible. - return DeducedTemplateArgument(); + return DeducedTemplateArgument(); case TemplateArgument::Expression: - // If we deduced a dependent expression in one case and either an integral - // constant or a declaration in another case, keep the integral constant + // If we deduced a dependent expression in one case and either an integral + // constant or a declaration in another case, keep the integral constant // or declaration. if (Y.getKind() == TemplateArgument::Integral || Y.getKind() == TemplateArgument::Declaration) return DeducedTemplateArgument(Y, X.wasDeducedFromArrayBound() && Y.wasDeducedFromArrayBound()); - + if (Y.getKind() == TemplateArgument::Expression) { // Compare the expressions for equality llvm::FoldingSetNodeID ID1, ID2; @@ -234,49 +234,49 @@ if (ID1 == ID2) return X; } - + // All other combinations are incompatible. return DeducedTemplateArgument(); - + case TemplateArgument::Declaration: // If we deduced a declaration and a dependent expression, keep the // declaration. if (Y.getKind() == TemplateArgument::Expression) return X; - + // If we deduced a declaration and an integral constant, keep the // integral constant. if (Y.getKind() == TemplateArgument::Integral) return Y; - + // If we deduced two declarations, make sure they they refer to the // same declaration. if (Y.getKind() == TemplateArgument::Declaration && isSameDeclaration(X.getAsDecl(), Y.getAsDecl())) return X; - + // All other combinations are incompatible. return DeducedTemplateArgument(); - + case TemplateArgument::Pack: if (Y.getKind() != TemplateArgument::Pack || X.pack_size() != Y.pack_size()) return DeducedTemplateArgument(); - - for (TemplateArgument::pack_iterator XA = X.pack_begin(), + + for (TemplateArgument::pack_iterator XA = X.pack_begin(), XAEnd = X.pack_end(), YA = Y.pack_begin(); XA != XAEnd; ++XA, ++YA) { - if (checkDeducedTemplateArguments(Context, - DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), + if (checkDeducedTemplateArguments(Context, + DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound())) .isNull()) return DeducedTemplateArgument(); } - + return X; } - + return DeducedTemplateArgument(); } @@ -293,16 +293,16 @@ "Cannot deduce non-type template argument with depth > 0"); DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[NTTP->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return Sema::TDK_Inconsistent; } - + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -323,17 +323,17 @@ "Expression template argument must be type- or value-dependent."); DeducedTemplateArgument NewDeduced(Value); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[NTTP->getIndex()], + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[NTTP->getIndex()], NewDeduced); - + if (Result.isNull()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return Sema::TDK_Inconsistent; } - + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -350,18 +350,18 @@ llvm::SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - + DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[NTTP->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return Sema::TDK_Inconsistent; } - + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -379,28 +379,28 @@ // so there is nothing that we can deduce. return Sema::TDK_Success; } - + if (TemplateTemplateParmDecl *TempParam = dyn_cast(ParamDecl)) { DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg)); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[TempParam->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = TempParam; Info.FirstArg = Deduced[TempParam->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return Sema::TDK_Inconsistent; } - + Deduced[TempParam->getIndex()] = Result; - return Sema::TDK_Success; + return Sema::TDK_Success; } - + // Verify that the two template names are equivalent. if (S.Context.hasSameTemplateName(Param, Arg)) return Sema::TDK_Success; - + // Mismatch of non-dependent template parameter to argument. Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); @@ -449,8 +449,8 @@ // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, - Param->getArgs(), Param->getNumArgs(), + return DeduceTemplateArguments(S, TemplateParams, + Param->getArgs(), Param->getNumArgs(), SpecArg->getArgs(), SpecArg->getNumArgs(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); @@ -478,7 +478,7 @@ return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, Param->getArgs(), Param->getNumArgs(), SpecArg->getTemplateArgs().data(), SpecArg->getTemplateArgs().size(), @@ -510,25 +510,25 @@ } /// \brief Retrieve the depth and index of a template parameter. -static std::pair +static std::pair getDepthAndIndex(NamedDecl *ND) { if (TemplateTypeParmDecl *TTP = dyn_cast(ND)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(ND)) return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - + TemplateTemplateParmDecl *TTP = cast(ND); return std::make_pair(TTP->getDepth(), TTP->getIndex()); } /// \brief Retrieve the depth and index of an unexpanded parameter pack. -static std::pair +static std::pair getDepthAndIndex(UnexpandedParameterPack UPP) { if (const TemplateTypeParmType *TTP = UPP.first.dyn_cast()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - + return getDepthAndIndex(UPP.first.get()); } @@ -539,16 +539,16 @@ return TemplateParameter(TTP); else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) return TemplateParameter(NTTP); - + return TemplateParameter(cast(D)); } /// \brief Prepare to perform template argument deduction for all of the /// arguments in a set of argument packs. -static void PrepareArgumentPackDeduction(Sema &S, - llvm::SmallVectorImpl &Deduced, +static void PrepareArgumentPackDeduction(Sema &S, + llvm::SmallVectorImpl &Deduced, const llvm::SmallVectorImpl &PackIndices, - llvm::SmallVectorImpl &SavedPacks, + llvm::SmallVectorImpl &SavedPacks, llvm::SmallVectorImpl< llvm::SmallVector > &NewlyDeducedPacks) { // Save the deduced template arguments for each parameter pack expanded @@ -557,18 +557,18 @@ // Save the previously-deduced argument pack, then clear it out so that we // can deduce a new argument pack. SavedPacks[I] = Deduced[PackIndices[I]]; - Deduced[PackIndices[I]] = TemplateArgument(); - + Deduced[PackIndices[I]] = TemplateArgument(); + // If the template arugment pack was explicitly specified, add that to // the set of deduced arguments. const TemplateArgument *ExplicitArgs; unsigned NumExplicitArgs; - if (NamedDecl *PartiallySubstitutedPack + if (NamedDecl *PartiallySubstitutedPack = S.CurrentInstantiationScope->getPartiallySubstitutedPack( &ExplicitArgs, &NumExplicitArgs)) { if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I]) - NewlyDeducedPacks[I].append(ExplicitArgs, + NewlyDeducedPacks[I].append(ExplicitArgs, ExplicitArgs + NumExplicitArgs); } } @@ -581,9 +581,9 @@ FinishArgumentPackDeduction(Sema &S, TemplateParameterList *TemplateParams, bool HasAnyArguments, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, const llvm::SmallVectorImpl &PackIndices, - llvm::SmallVectorImpl &SavedPacks, + llvm::SmallVectorImpl &SavedPacks, llvm::SmallVectorImpl< llvm::SmallVector > &NewlyDeducedPacks, TemplateDeductionInfo &Info) { @@ -596,9 +596,9 @@ Deduced[PackIndices[I]] = SavedPacks[I]; continue; } - + DeducedTemplateArgument NewPack; - + if (NewlyDeducedPacks[I].empty()) { // If we deduced an empty argument pack, create it now. NewPack = DeducedTemplateArgument(TemplateArgument(0, 0)); @@ -610,9 +610,9 @@ NewPack = DeducedTemplateArgument(TemplateArgument(ArgumentPack, NewlyDeducedPacks[I].size()), - NewlyDeducedPacks[I][0].wasDeducedFromArrayBound()); + NewlyDeducedPacks[I][0].wasDeducedFromArrayBound()); } - + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack); if (Result.isNull()) { @@ -622,16 +622,16 @@ Info.SecondArg = NewPack; return Sema::TDK_Inconsistent; } - + Deduced[PackIndices[I]] = Result; } - + return Sema::TDK_Success; } /// \brief Deduce the template arguments by comparing the list of parameter -/// types to the list of argument types, as in the parameter-type-lists of -/// function types (C++ [temp.deduct.type]p10). +/// types to the list of argument types, as in the parameter-type-lists of +/// function types (C++ [temp.deduct.type]p10). /// /// \param S The semantic analysis object within which we are deducing /// @@ -653,7 +653,7 @@ /// how template argument deduction is performed. /// /// \param PartialOrdering If true, we are performing template argument -/// deduction for during partial ordering for a call +/// deduction for during partial ordering for a call /// (C++0x [temp.deduct.partial]). /// /// \param RefParamComparisons If we're performing template argument deduction @@ -678,24 +678,24 @@ !(NumParams && isa(Params[NumParams - 1])) && !(NumArgs && isa(Args[NumArgs - 1]))) return Sema::TDK_NonDeducedMismatch; - + // C++0x [temp.deduct.type]p10: - // Similarly, if P has a form that contains (T), then each parameter type - // Pi of the respective parameter-type- list of P is compared with the - // corresponding parameter type Ai of the corresponding parameter-type-list - // of A. [...] + // Similarly, if P has a form that contains (T), then each parameter type + // Pi of the respective parameter-type- list of P is compared with the + // corresponding parameter type Ai of the corresponding parameter-type-list + // of A. [...] unsigned ArgIdx = 0, ParamIdx = 0; for (; ParamIdx != NumParams; ++ParamIdx) { // Check argument types. - const PackExpansionType *Expansion + const PackExpansionType *Expansion = dyn_cast(Params[ParamIdx]); if (!Expansion) { // Simple case: compare the parameter and argument types at this point. - + // Make sure we have an argument. if (ArgIdx >= NumArgs) return Sema::TDK_NonDeducedMismatch; - + if (isa(Args[ArgIdx])) { // C++0x [temp.deduct.type]p22: // If the original function parameter associated with A is a function @@ -703,7 +703,7 @@ // a function parameter pack, then template argument deduction fails. return Sema::TDK_NonDeducedMismatch; } - + if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Params[ParamIdx], @@ -712,25 +712,25 @@ PartialOrdering, RefParamComparisons)) return Result; - + ++ArgIdx; continue; } - + // C++0x [temp.deduct.type]p5: // The non-deduced contexts are: - // - A function parameter pack that does not occur at the end of the + // - A function parameter pack that does not occur at the end of the // parameter-declaration-clause. if (ParamIdx + 1 < NumParams) return Sema::TDK_Success; // C++0x [temp.deduct.type]p10: - // If the parameter-declaration corresponding to Pi is a function + // If the parameter-declaration corresponding to Pi is a function // parameter pack, then the type of its declarator- id is compared with - // each remaining parameter type in the parameter-type-list of A. Each + // each remaining parameter type in the parameter-type-list of A. Each // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by the function parameter pack. - + // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. llvm::SmallVector PackIndices; @@ -751,26 +751,26 @@ assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); // Keep track of the deduced template arguments for each parameter pack - // expanded by this pack expansion (the outer index) and for each + // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). llvm::SmallVector, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector + llvm::SmallVector SavedPacks(PackIndices.size()); - PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, + PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); - + bool HasAnyArguments = false; for (; ArgIdx < NumArgs; ++ArgIdx) { HasAnyArguments = true; - + // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result + if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], Info, Deduced, TDF, PartialOrdering, RefParamComparisons)) return Result; - + // Capture the deduced template arguments for each parameter pack expanded // by this pack expansion, add them to the list of arguments we've deduced // for that pack, then clear out the deduced argument. @@ -782,20 +782,20 @@ } } } - + // Build argument packs for each of the parameter packs expanded by this // pack expansion. if (Sema::TemplateDeductionResult Result - = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, + = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks, Info)) - return Result; + return Result; } - + // Make sure we don't have any extra arguments. if (ArgIdx < NumArgs) return Sema::TDK_NonDeducedMismatch; - + return Sema::TDK_Success; } @@ -841,34 +841,34 @@ QualType Arg = S.Context.getCanonicalType(ArgIn); // If the argument type is a pack expansion, look at its pattern. - // This isn't explicitly called out + // This isn't explicitly called out if (const PackExpansionType *ArgExpansion = dyn_cast(Arg)) Arg = ArgExpansion->getPattern(); - + if (PartialOrdering) { // C++0x [temp.deduct.partial]p5: - // Before the partial ordering is done, certain transformations are - // performed on the types used for partial ordering: - // - If P is a reference type, P is replaced by the type referred to. + // Before the partial ordering is done, certain transformations are + // performed on the types used for partial ordering: + // - If P is a reference type, P is replaced by the type referred to. const ReferenceType *ParamRef = Param->getAs(); if (ParamRef) Param = ParamRef->getPointeeType(); - + // - If A is a reference type, A is replaced by the type referred to. const ReferenceType *ArgRef = Arg->getAs(); if (ArgRef) Arg = ArgRef->getPointeeType(); - + if (RefParamComparisons && ParamRef && ArgRef) { // C++0x [temp.deduct.partial]p6: - // If both P and A were reference types (before being replaced with the - // type referred to above), determine which of the two types (if any) is + // If both P and A were reference types (before being replaced with the + // type referred to above), determine which of the two types (if any) is // more cv-qualified than the other; otherwise the types are considered - // to be equally cv-qualified for partial ordering purposes. The result + // to be equally cv-qualified for partial ordering purposes. The result // of this determination will be used below. // - // We save this information for later, using it only when deduction + // We save this information for later, using it only when deduction // succeeds in both directions. RefParamPartialOrderingComparison Comparison; Comparison.ParamIsRvalueRef = ParamRef->getAs(); @@ -880,13 +880,13 @@ Comparison.Qualifiers = ArgMoreQualified; RefParamComparisons->push_back(Comparison); } - + // C++0x [temp.deduct.partial]p7: // Remove any top-level cv-qualifiers: - // - If P is a cv-qualified type, P is replaced by the cv-unqualified + // - If P is a cv-qualified type, P is replaced by the cv-unqualified // version of P. Param = Param.getUnqualifiedType(); - // - If A is a cv-qualified type, A is replaced by the cv-unqualified + // - If A is a cv-qualified type, A is replaced by the cv-unqualified // version of A. Arg = Arg.getUnqualifiedType(); } else { @@ -901,21 +901,21 @@ Arg.getCVRQualifiers()); Param = S.Context.getQualifiedType(UnqualParam, Quals); } - + if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { // C++0x [temp.deduct.type]p10: // If P and A are function types that originated from deduction when // taking the address of a function template (14.8.2.2) or when deducing // template arguments from a function declaration (14.8.2.6) and Pi and - // Ai are parameters of the top-level parameter-type-list of P and A, - // respectively, Pi is adjusted if it is an rvalue reference to a - // cv-unqualified template parameter and Ai is an lvalue reference, in - // which case the type of Pi is changed to be the template parameter + // Ai are parameters of the top-level parameter-type-list of P and A, + // respectively, Pi is adjusted if it is an rvalue reference to a + // cv-unqualified template parameter and Ai is an lvalue reference, in + // which case the type of Pi is changed to be the template parameter // type (i.e., T&& is changed to simply T). [ Note: As a result, when // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; - + if (const RValueReferenceType *ParamRef = Param->getAs()) { if (isa(ParamRef->getPointeeType()) && @@ -925,12 +925,12 @@ } } } - + // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { if (!(TDF & TDF_SkipNonDependent) && Param != Arg) return Sema::TDK_NonDeducedMismatch; - + return Sema::TDK_Success; } @@ -977,18 +977,18 @@ DeducedType = S.Context.getCanonicalType(DeducedType); DeducedTemplateArgument NewDeduced(DeducedType); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); if (Result.isNull()) { Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return Sema::TDK_Inconsistent; } - + Deduced[Index] = Result; - return Sema::TDK_Success; + return Sema::TDK_Success; } // Set up the template argument deduction information for a failure. @@ -1125,7 +1125,7 @@ if (const ConstantArrayType *ConstantArrayArg = dyn_cast(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); @@ -1154,9 +1154,9 @@ const FunctionProtoType *FunctionProtoParam = cast(Param); - if (FunctionProtoParam->getTypeQuals() + if (FunctionProtoParam->getTypeQuals() != FunctionProtoArg->getTypeQuals() || - FunctionProtoParam->getRefQualifier() + FunctionProtoParam->getRefQualifier() != FunctionProtoArg->getRefQualifier() || FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; @@ -1347,7 +1347,7 @@ // partial ordering. if (Arg.isPackExpansion()) Arg = Arg.getPackExpansionPattern(); - + switch (Param.getKind()) { case TemplateArgument::Null: assert(false && "Null template argument in parameter list"); @@ -1363,7 +1363,7 @@ case TemplateArgument::Template: if (Arg.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(S, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, Param.getAsTemplate(), Arg.getAsTemplate(), Info, Deduced); Info.FirstArg = Param; @@ -1373,13 +1373,13 @@ case TemplateArgument::TemplateExpansion: llvm_unreachable("caller should handle pack expansions"); break; - + case TemplateArgument::Declaration: if (Arg.getKind() == TemplateArgument::Declaration && Param.getAsDecl()->getCanonicalDecl() == Arg.getAsDecl()->getCanonicalDecl()) return Sema::TDK_Success; - + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -1419,7 +1419,7 @@ if (Arg.getKind() == TemplateArgument::Declaration) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(), Info, Deduced); - + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -1443,12 +1443,12 @@ /// /// \returns true if there is another template argument (which will be at /// \c Args[ArgIdx]), false otherwise. -static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, +static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, unsigned &ArgIdx, unsigned &NumArgs) { if (ArgIdx == NumArgs) return false; - + const TemplateArgument &Arg = Args[ArgIdx]; if (Arg.getKind() != TemplateArgument::Pack) return true; @@ -1467,7 +1467,7 @@ unsigned ArgIdx = 0; while (ArgIdx < NumArgs) { const TemplateArgument &Arg = Args[ArgIdx]; - + // Unwrap argument packs. if (Args[ArgIdx].getKind() == TemplateArgument::Pack) { Args = Arg.pack_begin(); @@ -1475,15 +1475,15 @@ ArgIdx = 0; continue; } - + ++ArgIdx; if (ArgIdx == NumArgs) return false; - + if (Arg.isPackExpansion()) return true; } - + return false; } @@ -1496,54 +1496,54 @@ llvm::SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch) { // C++0x [temp.deduct.type]p9: - // If the template argument list of P contains a pack expansion that is not - // the last template argument, the entire template argument list is a + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a // non-deduced context. if (hasPackExpansionBeforeEnd(Params, NumParams)) return Sema::TDK_Success; - + // C++0x [temp.deduct.type]p9: - // If P has a form that contains or , then each argument Pi of the - // respective template argument list P is compared with the corresponding + // If P has a form that contains or , then each argument Pi of the + // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. unsigned ArgIdx = 0, ParamIdx = 0; - for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams); + for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams); ++ParamIdx) { if (!Params[ParamIdx].isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. - + // Check whether we have enough arguments. if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) return NumberOfArgumentsMustMatch? Sema::TDK_NonDeducedMismatch : Sema::TDK_Success; - + if (Args[ArgIdx].isPackExpansion()) { // FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here, // but applied to pack expansions that are template arguments. return Sema::TDK_NonDeducedMismatch; } - + // Perform deduction for this Pi/Ai pair. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Params[ParamIdx], Args[ArgIdx], Info, Deduced)) - return Result; - + return Result; + // Move to the next argument. ++ArgIdx; continue; } - + // The parameter is a pack expansion. - + // C++0x [temp.deduct.type]p9: - // If Pi is a pack expansion, then the pattern of Pi is compared with - // each remaining argument in the template argument list of A. Each - // comparison deduces template arguments for subsequent positions in the + // If Pi is a pack expansion, then the pattern of Pi is compared with + // each remaining argument in the template argument list of A. Each + // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by Pi. TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern(); - + // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. llvm::SmallVector PackIndices; @@ -1561,33 +1561,33 @@ } } assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); - + // FIXME: If there are no remaining arguments, we can bail out early // and set any deduced parameter packs to an empty argument pack. // The latter part of this is a (minor) correctness issue. - + // Save the deduced template arguments for each parameter pack expanded // by this pack expansion, then clear out the deduction. - llvm::SmallVector + llvm::SmallVector SavedPacks(PackIndices.size()); llvm::SmallVector, 2> NewlyDeducedPacks(PackIndices.size()); - PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, + PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); // Keep track of the deduced template arguments for each parameter pack - // expanded by this pack expansion (the outer index) and for each + // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). bool HasAnyArguments = false; while (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) { HasAnyArguments = true; - + // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result + if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], Info, Deduced)) return Result; - + // Capture the deduced template arguments for each parameter pack expanded // by this pack expansion, add them to the list of arguments we've deduced // for that pack, then clear out the deduced argument. @@ -1598,24 +1598,24 @@ DeducedArg = DeducedTemplateArgument(); } } - + ++ArgIdx; } - + // Build argument packs for each of the parameter packs expanded by this // pack expansion. if (Sema::TemplateDeductionResult Result - = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, + = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks, Info)) - return Result; + return Result; } - + // If there is an argument remaining, then we had too many arguments. if (NumberOfArgumentsMustMatch && hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) return Sema::TDK_NonDeducedMismatch; - + return Sema::TDK_Success; } @@ -1626,7 +1626,7 @@ const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced) { - return DeduceTemplateArguments(S, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, ParamList.data(), ParamList.size(), ArgList.data(), ArgList.size(), Info, Deduced); @@ -1658,14 +1658,14 @@ X.getAsTemplateOrTemplatePattern()).getAsVoidPointer() == Context.getCanonicalTemplateName( Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer(); - + case TemplateArgument::Integral: return *X.getAsIntegral() == *Y.getAsIntegral(); case TemplateArgument::Expression: { llvm::FoldingSetNodeID XID, YID; X.getAsExpr()->Profile(XID, Context, true); - Y.getAsExpr()->Profile(YID, Context, true); + Y.getAsExpr()->Profile(YID, Context, true); return XID == YID; } @@ -1700,33 +1700,33 @@ /// /// \param Loc The source location to use for the resulting template /// argument. -static TemplateArgumentLoc +static TemplateArgumentLoc getTrivialTemplateArgumentLoc(Sema &S, - const TemplateArgument &Arg, + const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc) { switch (Arg.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't get a NULL template argument here"); break; - + case TemplateArgument::Type: - return TemplateArgumentLoc(Arg, + return TemplateArgumentLoc(Arg, S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); - + case TemplateArgument::Declaration: { Expr *E = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) .takeAs(); return TemplateArgumentLoc(TemplateArgument(E), E); } - + case TemplateArgument::Integral: { Expr *E = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs(); return TemplateArgumentLoc(TemplateArgument(E), E); } - + case TemplateArgument::Template: return TemplateArgumentLoc(Arg, SourceRange(), Loc); @@ -1735,21 +1735,21 @@ case TemplateArgument::Expression: return TemplateArgumentLoc(Arg, Arg.getAsExpr()); - + case TemplateArgument::Pack: return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); } - + return TemplateArgumentLoc(); } /// \brief Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. -static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, +static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, - NamedDecl *Template, - QualType NTTPType, + NamedDecl *Template, + QualType NTTPType, unsigned ArgumentPackIndex, TemplateDeductionInfo &Info, bool InFunctionTemplate, @@ -1758,7 +1758,7 @@ // This is a template argument pack, so check each of its arguments against // the template parameter. llvm::SmallVector PackedArgsBuilder; - for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), + for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), PAEnd = Arg.pack_end(); PA != PAEnd; ++PA) { // When converting the deduced template argument, append it to the @@ -1766,29 +1766,29 @@ // checking logic has all of the prior template arguments available. DeducedTemplateArgument InnerArg(*PA); InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); - if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, + if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, NTTPType, PackedArgsBuilder.size(), Info, InFunctionTemplate, Output)) return true; - + // Move the converted template argument into our argument pack. PackedArgsBuilder.push_back(Output.back()); Output.pop_back(); } - + // Create the resulting argument pack. - Output.push_back(TemplateArgument::CreatePackCopy(S.Context, + Output.push_back(TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder.data(), PackedArgsBuilder.size())); return false; } - + // Convert the deduced template argument into a template // argument that we can check, almost as if the user had written // the template argument explicitly. TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation()); - + // Check the template argument, converting it as necessary. return S.CheckTemplateArgument(Param, ArgLoc, Template, @@ -1798,7 +1798,7 @@ Output, InFunctionTemplate ? (Arg.wasDeducedFromArrayBound() - ? Sema::CTAK_DeducedFromArrayBound + ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) : Sema::CTAK_Specified); } @@ -1806,14 +1806,14 @@ /// Complete template argument deduction for a class template partial /// specialization. static Sema::TemplateDeductionResult -FinishTemplateArgumentDeduction(Sema &S, +FinishTemplateArgumentDeduction(Sema &S, ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, llvm::SmallVectorImpl &Deduced, TemplateDeductionInfo &Info) { // Trap errors. Sema::SFINAETrap Trap(S); - + Sema::ContextRAII SavedContext(S, Partial); // C++ [temp.deduct.type]p2: @@ -1827,19 +1827,19 @@ Info.Param = makeTemplateParameter(Param); return Sema::TDK_Incomplete; } - + // We have deduced this argument, so it still needs to be // checked and converted. - + // First, for a non-type template parameter type that is // initialized by a declaration, we need the type of the // corresponding non-type template parameter. QualType NTTPType; - if (NonTypeTemplateParmDecl *NTTP + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(Param)) { NTTPType = NTTP->getType(); if (NTTPType->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Builder.data(), Builder.size()); NTTPType = S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), @@ -1848,8 +1848,8 @@ if (NTTPType.isNull()) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, - Builder.data(), + Info.reset(TemplateArgumentList::CreateCopy(S.Context, + Builder.data(), Builder.size())); return Sema::TDK_SubstitutionFailure; } @@ -1861,15 +1861,15 @@ Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), - Builder.size())); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); return Sema::TDK_SubstitutionFailure; } } - + // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + = TemplateArgumentList::CreateCopy(S.Context, Builder.data(), Builder.size()); Info.reset(DeducedArgumentList); @@ -1906,7 +1906,7 @@ if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - + TemplateParameterList *TemplateParams = ClassTemplate->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -1954,8 +1954,8 @@ if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - - return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, Deduced, Info); } @@ -2056,14 +2056,14 @@ TemplateArgumentList *ExplicitArgumentList = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size()); Info.reset(ExplicitArgumentList); - + // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit // argument substitution, on the other hand, needs to happen in the // calling context. ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); - // If we deduced template arguments for a template parameter pack, + // If we deduced template arguments for a template parameter pack, // note that the template argument pack is partially substituted and record // the explicit template arguments. They'll be used as part of deduction // for this template parameter pack. @@ -2071,7 +2071,7 @@ const TemplateArgument &Arg = Builder[I]; if (Arg.getKind() == TemplateArgument::Pack) { CurrentInstantiationScope->SetPartiallySubstitutedPack( - TemplateParams->getParam(I), + TemplateParams->getParam(I), Arg.pack_begin(), Arg.pack_size()); break; @@ -2080,7 +2080,7 @@ // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. - if (SubstParmTypes(Function->getLocation(), + if (SubstParmTypes(Function->getLocation(), Function->param_begin(), Function->getNumParams(), MultiLevelTemplateArgumentList(*ExplicitArgumentList), ParamTypes)) @@ -2169,11 +2169,11 @@ llvm::SmallVector Builder; for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NamedDecl *Param = TemplateParams->getParam(I); - + if (!Deduced[I].isNull()) { if (I < NumExplicitlySpecified) { // We have already fully type-checked and converted this - // argument, because it was explicitly-specified. Just record the + // argument, because it was explicitly-specified. Just record the // presence of this argument. Builder.push_back(Deduced[I]); continue; @@ -2186,11 +2186,11 @@ // initialized by a declaration, we need the type of the // corresponding non-type template parameter. QualType NTTPType; - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(Param)) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(Param)) { NTTPType = NTTP->getType(); if (NTTPType->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Builder.data(), Builder.size()); NTTPType = SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), @@ -2199,8 +2199,8 @@ if (NTTPType.isNull()) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, - Builder.data(), + Info.reset(TemplateArgumentList::CreateCopy(Context, + Builder.data(), Builder.size())); return TDK_SubstitutionFailure; } @@ -2212,16 +2212,16 @@ true, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), - Builder.size())); + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), + Builder.size())); return TDK_SubstitutionFailure; } continue; } - + // C++0x [temp.arg.explicit]p3: - // A trailing template parameter pack (14.5.3) not otherwise deduced will + // A trailing template parameter pack (14.5.3) not otherwise deduced will // be deduced to an empty sequence of template arguments. // FIXME: Where did the word "trailing" come from? if (Param->isTemplateParameterPack()) { @@ -2234,13 +2234,13 @@ &NumExplicitArgs) == Param) Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs)); - else + else Builder.push_back(TemplateArgument(0, 0)); - + continue; } - // Substitute into the default template argument, if available. + // Substitute into the default template argument, if available. TemplateArgumentLoc DefArg = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, FunctionTemplate->getLocation(), @@ -2254,7 +2254,7 @@ const_cast(TemplateParams->getParam(I))); return TDK_Incomplete; } - + // Check whether we can actually use the default argument. if (CheckTemplateArgument(Param, DefArg, FunctionTemplate, @@ -2265,7 +2265,7 @@ Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size())); return TDK_SubstitutionFailure; } @@ -2289,9 +2289,9 @@ if (!Specialization) return TDK_SubstitutionFailure; - assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == + assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == FunctionTemplate->getCanonicalDecl()); - + // If the template argument list is owned by the function template // specialization, release it. if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && @@ -2316,7 +2316,7 @@ if (Pos == SuppressedDiagnostics.end()) SuppressedDiagnostics[Specialization->getCanonicalDecl()] .append(Info.diag_begin(), Info.diag_end()); - } + } return TDK_Success; } @@ -2348,7 +2348,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, Expr *Arg, QualType ParamType, bool ParamWasReference) { - + OverloadExpr::FindResult R = OverloadExpr::find(Arg); OverloadExpr *Ovl = R.Expression; @@ -2396,10 +2396,10 @@ if (ArgType.isNull()) continue; // Function-to-pointer conversion. - if (!ParamWasReference && ParamType->isPointerType() && + if (!ParamWasReference && ParamType->isPointerType() && ArgType->isFunctionType()) ArgType = S.Context.getPointerType(ArgType); - + // - If the argument is an overload set (not containing function // templates), trial argument deduction is attempted using each // of the members of the set. If deduction succeeds for only one @@ -2412,7 +2412,7 @@ // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector + llvm::SmallVector Deduced(TemplateParams->size()); TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); Sema::TemplateDeductionResult Result @@ -2427,7 +2427,7 @@ return Match; } -/// \brief Perform the adjustments to the parameter and argument types +/// \brief Perform the adjustments to the parameter and argument types /// described in C++ [temp.deduct.call]. /// /// \returns true if the caller should not attempt to perform any template @@ -2461,7 +2461,7 @@ // for type deduction. ParamType = ParamRefType->getPointeeType(); } - + // Overload sets usually make this parameter an undeduced // context, but there are sometimes special circumstances. if (ArgType == S.Context.OverloadTy) { @@ -2471,7 +2471,7 @@ if (ArgType.isNull()) return true; } - + if (ParamRefType) { // C++0x [temp.deduct.call]p3: // [...] If P is of the form T&&, where T is a template parameter, and @@ -2501,13 +2501,13 @@ ArgType = ArgType.getUnqualifiedType(); } } - + // C++0x [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument // values that will make the deduced A identical to A (after the type A // is transformed as described above). [...] TDF = TDF_SkipNonDependent; - + // - If the original P is a reference type, the deduced A (i.e., the // type referred to by the reference) can be more cv-qualified than // the transformed A. @@ -2529,7 +2529,7 @@ isSimpleTemplateIdType( ParamType->getAs()->getPointeeType()))) TDF |= TDF_DerivedClass; - + return false; } @@ -2549,7 +2549,7 @@ /// \param Name the name of the function being called. This is only significant /// when the function template is a conversion function template, in which /// case this routine will also perform template argument deduction based on -/// the function to which +/// the function to which /// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by @@ -2581,7 +2581,7 @@ /* Do nothing */; else if (Proto->isVariadic()) CheckArgs = Function->getNumParams(); - else + else return TDK_TooManyArguments; } @@ -2614,17 +2614,17 @@ // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); unsigned ArgIdx = 0; - for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); + for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); ParamIdx != NumParams; ++ParamIdx) { QualType ParamType = ParamTypes[ParamIdx]; - - const PackExpansionType *ParamExpansion + + const PackExpansionType *ParamExpansion = dyn_cast(ParamType); if (!ParamExpansion) { // Simple case: matching a function parameter to a function argument. if (ArgIdx >= CheckArgs) break; - + Expr *Arg = Args[ArgIdx++]; QualType ArgType = Arg->getType(); unsigned TDF = 0; @@ -2632,7 +2632,7 @@ ParamType, ArgType, Arg, TDF)) continue; - + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, ParamType, ArgType, Info, Deduced, @@ -2643,19 +2643,19 @@ // modulo the various allowed differences. continue; } - + // C++0x [temp.deduct.call]p1: - // For a function parameter pack that occurs at the end of the - // parameter-declaration-list, the type A of each remaining argument of - // the call is compared with the type P of the declarator-id of the - // function parameter pack. Each comparison deduces template arguments - // for subsequent positions in the template parameter packs expanded by + // For a function parameter pack that occurs at the end of the + // parameter-declaration-list, the type A of each remaining argument of + // the call is compared with the type P of the declarator-id of the + // function parameter pack. Each comparison deduces template arguments + // for subsequent positions in the template parameter packs expanded by // the function parameter pack. For a function parameter pack that does - // not occur at the end of the parameter-declaration-list, the type of + // not occur at the end of the parameter-declaration-list, the type of // the parameter pack is a non-deduced context. if (ParamIdx + 1 < NumParams) break; - + QualType ParamPattern = ParamExpansion->getPattern(); llvm::SmallVector PackIndices; { @@ -2672,20 +2672,20 @@ } } assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); - + // Keep track of the deduced template arguments for each parameter pack - // expanded by this pack expansion (the outer index) and for each + // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). llvm::SmallVector, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector + llvm::SmallVector SavedPacks(PackIndices.size()); PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks, - NewlyDeducedPacks); + NewlyDeducedPacks); bool HasAnyArguments = false; for (; ArgIdx < NumArgs; ++ArgIdx) { HasAnyArguments = true; - + ParamType = ParamPattern; Expr *Arg = Args[ArgIdx]; QualType ArgType = Arg->getType(); @@ -2698,7 +2698,7 @@ ++ArgIdx; break; } - + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, ParamType, ArgType, Info, Deduced, @@ -2716,14 +2716,14 @@ } } } - + // Build argument packs for each of the parameter packs expanded by this // pack expansion. if (Sema::TemplateDeductionResult Result - = FinishArgumentPackDeduction(*this, TemplateParams, HasAnyArguments, + = FinishArgumentPackDeduction(*this, TemplateParams, HasAnyArguments, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks, Info)) - return Result; + return Result; // After we've matching against a parameter pack, we're done. break; @@ -2741,7 +2741,7 @@ /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param ExplicitTemplateArguments the explicitly-specified template +/// \param ExplicitTemplateArguments the explicitly-specified template /// arguments. /// /// \param ArgFunctionType the function type that will be used as the @@ -2799,7 +2799,7 @@ return Result; } - if (TemplateDeductionResult Result + if (TemplateDeductionResult Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info)) @@ -2914,7 +2914,7 @@ LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, Info); Specialization = cast_or_null(Spec); return Result; @@ -2926,7 +2926,7 @@ /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param ExplicitTemplateArguments the explicitly-specified template +/// \param ExplicitTemplateArguments the explicitly-specified template /// arguments. /// /// \param Specialization if template argument deduction was successful, @@ -2951,8 +2951,8 @@ bool OnlyDeduced, unsigned Level, llvm::SmallVectorImpl &Deduced); - -/// \brief If this is a non-static member function, + +/// \brief If this is a non-static member function, static void MaybeAddImplicitObjectParameterType(ASTContext &Context, CXXMethodDecl *Method, llvm::SmallVectorImpl &ArgTypes) { @@ -2983,13 +2983,13 @@ FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, - unsigned NumCallArguments, + unsigned NumCallArguments, llvm::SmallVectorImpl *RefParamComparisons) { FunctionDecl *FD1 = FT1->getTemplatedDecl(); - FunctionDecl *FD2 = FT2->getTemplatedDecl(); + FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs(); const FunctionProtoType *Proto2 = FD2->getType()->getAs(); - + assert(Proto1 && Proto2 && "Function templates must have prototypes"); TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); llvm::SmallVector Deduced; @@ -3025,21 +3025,21 @@ // first argument of the free function or static member, which // seems to match existing practice. llvm::SmallVector Args1; - unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && + unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1; if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) - MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); - Args1.insert(Args1.end(), + MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); + Args1.insert(Args1.end(), Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); llvm::SmallVector Args2; - Skip2 = !S.getLangOptions().CPlusPlus0x && + Skip2 = !S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2; if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2); - Args2.insert(Args2.end(), + Args2.insert(Args2.end(), Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end()); - + // C++ [temp.func.order]p5: // The presence of unused ellipsis and default arguments has no effect on // the partial ordering of function templates. @@ -3052,10 +3052,10 @@ TDF_None, /*PartialOrdering=*/true, RefParamComparisons)) return false; - + break; } - + case TPOC_Conversion: // - In the context of a call to a conversion operator, the return types // of the conversion function templates are used. @@ -3065,23 +3065,23 @@ RefParamComparisons)) return false; break; - + case TPOC_Other: // - In other contexts (14.6.6.2) the function template's function type // is used. // FIXME: Don't we actually want to perform the adjustments on the parameter // types? - if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(), + if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced, TDF_None, /*PartialOrdering=*/true, RefParamComparisons)) return false; break; } - + // C++0x [temp.deduct.partial]p11: - // In most cases, all template parameters must have values in order for - // deduction to succeed, but for partial ordering purposes a template - // parameter may remain without a value provided it is not used in the + // In most cases, all template parameters must have values in order for + // deduction to succeed, but for partial ordering purposes a template + // parameter may remain without a value provided it is not used in the // types being used for partial ordering. [ Note: a template parameter used // in a non-deduced context is considered used. -end note] unsigned ArgIdx = 0, NumArgs = Deduced.size(); @@ -3090,7 +3090,7 @@ break; if (ArgIdx == NumArgs) { - // All template arguments were deduced. FT1 is at least as specialized + // All template arguments were deduced. FT1 is at least as specialized // as FT2. return true; } @@ -3100,41 +3100,41 @@ UsedParameters.resize(TemplateParams->size()); switch (TPOC) { case TPOC_Call: { - unsigned NumParams = std::min(NumCallArguments, - std::min(Proto1->getNumArgs(), + unsigned NumParams = std::min(NumCallArguments, + std::min(Proto1->getNumArgs(), Proto2->getNumArgs())); if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) - ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false, + ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false, TemplateParams->getDepth(), UsedParameters); for (unsigned I = Skip2; I < NumParams; ++I) - ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, TemplateParams->getDepth(), UsedParameters); break; } - + case TPOC_Conversion: - ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, TemplateParams->getDepth(), UsedParameters); break; - + case TPOC_Other: - ::MarkUsedTemplateParameters(S, FD2->getType(), false, + ::MarkUsedTemplateParameters(S, FD2->getType(), false, TemplateParams->getDepth(), UsedParameters); break; } - + for (; ArgIdx != NumArgs; ++ArgIdx) // If this argument had no value deduced but was used in one of the types // used for partial ordering, then deduction fails. if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx]) return false; - + return true; } - + /// \brief Determine whether this a function template whose parameter-type-list /// ends with a function parameter pack. static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { @@ -3142,20 +3142,20 @@ unsigned NumParams = Function->getNumParams(); if (NumParams == 0) return false; - + ParmVarDecl *Last = Function->getParamDecl(NumParams - 1); if (!Last->isParameterPack()) return false; - + // Make sure that no previous parameter is a parameter pack. while (--NumParams > 0) { if (Function->getParamDecl(NumParams - 1)->isParameterPack()) return false; } - + return true; } - + /// \brief Returns the more specialized function template according /// to the rules of function template partial ordering (C++ [temp.func.order]). /// @@ -3178,22 +3178,22 @@ TemplatePartialOrderingContext TPOC, unsigned NumCallArguments) { llvm::SmallVector RefParamComparisons; - bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments, 0); - bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, + bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, NumCallArguments, &RefParamComparisons); - + if (Better1 != Better2) // We have a clear winner return Better1? FT1 : FT2; - + if (!Better1 && !Better2) // Neither is better than the other return 0; // C++0x [temp.deduct.partial]p10: - // If for each type being considered a given template is at least as + // If for each type being considered a given template is at least as // specialized for all types and more specialized for some set of types and - // the other template is not more specialized for any types or is not at + // the other template is not more specialized for any types or is not at // least as specialized for any types, then the given template is more // specialized than the other template. Otherwise, neither template is more // specialized than the other. @@ -3206,7 +3206,7 @@ // were reference types (before being replaced with the type referred to // above): - // -- if the type from the argument template was an lvalue reference + // -- if the type from the argument template was an lvalue reference // and the type from the parameter template was not, the argument // type is considered to be more specialized than the other; // otherwise, @@ -3223,7 +3223,7 @@ return 0; continue; } - + // -- if the type from the argument template is more cv-qualified than // the type from the parameter template (as described above), the // argument type is considered to be more specialized than the @@ -3231,29 +3231,29 @@ switch (RefParamComparisons[I].Qualifiers) { case NeitherMoreQualified: break; - + case ParamMoreQualified: Better1 = true; if (Better2) return 0; continue; - + case ArgMoreQualified: Better2 = true; if (Better1) return 0; continue; } - + // -- neither type is more specialized than the other. } - + assert(!(Better1 && Better2) && "Should have broken out in the loop above"); if (Better1) return FT1; else if (Better2) return FT2; - + // FIXME: This mimics what GCC implements, but doesn't match up with the // proposed resolution for core issue 692. This area needs to be sorted out, // but for now we attempt to maintain compatibility. @@ -3261,7 +3261,7 @@ bool Variadic2 = isVariadicFunctionTemplate(FT2); if (Variadic1 != Variadic2) return Variadic1? FT2 : FT1; - + return 0; } @@ -3269,10 +3269,10 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { if (T1 == T2) return true; - + if (!T1 || !T2) return false; - + return T1->getCanonicalDecl() == T2->getCanonicalDecl(); } @@ -3291,7 +3291,7 @@ /// \param NumCallArguments The number of arguments in a call, used only /// when \c TPOC is \c TPOC_Call. /// -/// \param Loc the location where the ambiguity or no-specializations +/// \param Loc the location where the ambiguity or no-specializations /// diagnostic should occur. /// /// \param NoneDiag partial diagnostic used to diagnose cases where there are @@ -3305,14 +3305,14 @@ /// in this diagnostic should be unbound, which will correspond to the string /// describing the template arguments for the function template specialization. /// -/// \param Index if non-NULL and the result of this function is non-nULL, +/// \param Index if non-NULL and the result of this function is non-nULL, /// receives the index corresponding to the resulting function template /// specialization. /// -/// \returns the most specialized function template specialization, if +/// \returns the most specialized function template specialization, if /// found. Otherwise, returns SpecEnd. /// -/// \todo FIXME: Consider passing in the "also-ran" candidates that failed +/// \todo FIXME: Consider passing in the "also-ran" candidates that failed /// template argument deduction. UnresolvedSetIterator Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, @@ -3327,14 +3327,14 @@ Diag(Loc, NoneDiag); return SpecEnd; } - - if (SpecBegin + 1 == SpecEnd) + + if (SpecBegin + 1 == SpecEnd) return SpecBegin; - + // Find the function template that is better than all of the templates it // has been compared to. UnresolvedSetIterator Best = SpecBegin; - FunctionTemplateDecl *BestTemplate + FunctionTemplateDecl *BestTemplate = cast(*Best)->getPrimaryTemplate(); assert(BestTemplate && "Not a function template specialization?"); for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) { @@ -3348,7 +3348,7 @@ BestTemplate = Challenger; } } - + // Make sure that the "best" function template is more specialized than all // of the others. bool Ambiguous = false; @@ -3356,29 +3356,29 @@ FunctionTemplateDecl *Challenger = cast(*I)->getPrimaryTemplate(); if (I != Best && - !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, Loc, TPOC, NumCallArguments), BestTemplate)) { Ambiguous = true; break; } } - + if (!Ambiguous) { // We found an answer. Return it. return Best; } - + // Diagnose the ambiguity. Diag(Loc, AmbigDiag); - + // FIXME: Can we order the candidates in some sane way? for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) Diag((*I)->getLocation(), CandidateDiag) << getTemplateArgumentBindingsText( cast(*I)->getPrimaryTemplate()->getTemplateParameters(), *cast(*I)->getTemplateSpecializationArgs()); - + return SpecEnd; } @@ -3399,17 +3399,17 @@ SourceLocation Loc) { // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as - // specialized as the second if, given the following rewrite to two - // function templates, the first function template is at least as - // specialized as the second according to the ordering rules for function + // specialized as the second if, given the following rewrite to two + // function templates, the first function template is at least as + // specialized as the second according to the ordering rules for function // templates (14.6.6.2): // - the first function template has the same template parameters as the - // first partial specialization and has a single function parameter - // whose type is a class template specialization with the template + // first partial specialization and has a single function parameter + // whose type is a class template specialization with the template // arguments of the first partial specialization, and // - the second function template has the same template parameters as the - // second partial specialization and has a single function parameter - // whose type is a class template specialization with the template + // second partial specialization and has a single function parameter + // whose type is a class template specialization with the template // arguments of the second partial specialization. // // Rather than synthesize function templates, we merely perform the @@ -3426,21 +3426,21 @@ QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType(); - + // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, + /*PartialOrdering=*/true, /*RefParamComparisons=*/0); if (Better1) { InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, Deduced.data(), Deduced.size(), Info); - Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, - PS1->getTemplateArgs(), + Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, + PS1->getTemplateArgs(), Deduced, Info); } - + // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); @@ -3451,14 +3451,14 @@ if (Better2) { InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, Deduced.data(), Deduced.size(), Info); - Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, - PS2->getTemplateArgs(), + Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, + PS2->getTemplateArgs(), Deduced, Info); } - + if (Better1 == Better2) return 0; - + return Better1? PS1 : PS2; } @@ -3480,12 +3480,12 @@ // We can deduce from a pack expansion. if (const PackExpansionExpr *Expansion = dyn_cast(E)) E = Expansion->getPattern(); - + // Skip through any implicit casts we added while type-checking. while (const ImplicitCastExpr *ICE = dyn_cast(E)) E = ICE->getSubExpr(); - - // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to + + // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) @@ -3510,13 +3510,13 @@ llvm::SmallVectorImpl &Used) { if (!NNS) return; - + MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth, Used); - MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), + MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), OnlyDeduced, Depth, Used); } - + /// \brief Mark the template parameters that are used by the given /// template name. static void @@ -3533,12 +3533,12 @@ } return; } - + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) - MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, Depth, Used); if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) - MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Depth, Used); } @@ -3551,7 +3551,7 @@ llvm::SmallVectorImpl &Used) { if (T.isNull()) return; - + // Non-dependent types have nothing deducible if (!T->isDependentType()) return; @@ -3617,7 +3617,7 @@ = cast(T); MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced, Depth, Used); - MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, Depth, Used); break; } @@ -3642,7 +3642,7 @@ case Type::SubstTemplateTypeParmPack: { const SubstTemplateTypeParmPackType *Subst = cast(T); - MarkUsedTemplateParameters(SemaRef, + MarkUsedTemplateParameters(SemaRef, QualType(Subst->getReplacedParameter(), 0), OnlyDeduced, Depth, Used); MarkUsedTemplateParameters(SemaRef, Subst->getArgumentPack(), @@ -3659,12 +3659,12 @@ = cast(T); MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, Depth, Used); - + // C++0x [temp.deduct.type]p9: - // If the template argument list of P contains a pack expansion that is not - // the last template argument, the entire template argument list is a + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a // non-deduced context. - if (OnlyDeduced && + if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) break; @@ -3676,7 +3676,7 @@ case Type::Complex: if (!OnlyDeduced) - MarkUsedTemplateParameters(SemaRef, + MarkUsedTemplateParameters(SemaRef, cast(T)->getElementType(), OnlyDeduced, Depth, Used); break; @@ -3694,12 +3694,12 @@ if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(), OnlyDeduced, Depth, Used); - + // C++0x [temp.deduct.type]p9: - // If the template argument list of P contains a pack expansion that is not - // the last template argument, the entire template argument list is a + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a // non-deduced context. - if (OnlyDeduced && + if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) break; @@ -3731,7 +3731,7 @@ break; case Type::PackExpansion: - MarkUsedTemplateParameters(SemaRef, + MarkUsedTemplateParameters(SemaRef, cast(T)->getPattern(), OnlyDeduced, Depth, Used); break; @@ -3776,16 +3776,16 @@ case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - MarkUsedTemplateParameters(SemaRef, - TemplateArg.getAsTemplateOrTemplatePattern(), + MarkUsedTemplateParameters(SemaRef, + TemplateArg.getAsTemplateOrTemplatePattern(), OnlyDeduced, Depth, Used); break; case TemplateArgument::Expression: - MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, Depth, Used); break; - + case TemplateArgument::Pack: for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(), PEnd = TemplateArg.pack_end(); @@ -3809,28 +3809,28 @@ bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl &Used) { // C++0x [temp.deduct.type]p9: - // If the template argument list of P contains a pack expansion that is not - // the last template argument, the entire template argument list is a + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a // non-deduced context. - if (OnlyDeduced && + if (OnlyDeduced && hasPackExpansionBeforeEnd(TemplateArgs.data(), TemplateArgs.size())) return; for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, + ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Depth, Used); } /// \brief Marks all of the template parameters that will be deduced by a /// call to the given function template. -void +void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl &Deduced) { - TemplateParameterList *TemplateParams + TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); Deduced.resize(TemplateParams->size()); - + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), Modified: cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp?rev=124364&r1=124363&r2=124364&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/BasicStore.cpp Thu Jan 27 01:10:08 2011 @@ -592,4 +592,3 @@ SVal V = svalBuilder.getConjuredSymbolVal(R, E, T, Count); return Bind(store, loc::MemRegionVal(R), V); } - From rjmccall at apple.com Thu Jan 27 00:17:49 2011 From: rjmccall at apple.com (John McCall) Date: Thu, 27 Jan 2011 08:17:49 -0000 Subject: [cfe-commits] r124367 - /cfe/trunk/include/clang/AST/Type.h Message-ID: <20110127081749.C965D2A6C12C@llvm.org> Author: rjmccall Date: Thu Jan 27 02:17:49 2011 New Revision: 124367 URL: http://llvm.org/viewvc/llvm-project?rev=124367&view=rev Log: Provide Type::castAs<>, which is to getAs<> what cast<> is to dyn_cast<>. Also provide a method to grab the base element type of a type without stressing out over qualifiers (but give it a nice scary name). Modified: cfe/trunk/include/clang/AST/Type.h Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=124367&r1=124366&r2=124367&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Thu Jan 27 02:17:49 2011 @@ -1315,18 +1315,35 @@ /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; - // Member-template getAs'. Look through sugar for - // an instance of . This scheme will eventually - // replace the specific getAsXXXX methods above. - // - // There are some specializations of this member template listed - // immediately following this class. + /// Member-template getAs'. Look through sugar for + /// an instance of . This scheme will eventually + /// replace the specific getAsXXXX methods above. + /// + /// There are some specializations of this member template listed + /// immediately following this class. template const T *getAs() const; /// A variant of getAs<> for array types which silently discards /// qualifiers from the outermost type. const ArrayType *getAsArrayTypeUnsafe() const; + /// Member-template castAs. Look through sugar for + /// the underlying instance of . + /// + /// This method has the same relationship to getAs as cast has + /// to dyn_cast; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template const T *castAs() const; + + /// A variant of castAs<> for array type which silently discards + /// qualifiers from the outermost type. + const ArrayType *castAsArrayTypeUnsafe() const; + + /// getBaseElementTypeUnsafe - Get the base element type of this + /// type, potentially discarding type qualifiers. This method + /// should never be used when type qualifiers are meaningful. + const Type *getBaseElementTypeUnsafe() const; + /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -1400,6 +1417,9 @@ #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ return dyn_cast(CanonicalType); \ +} \ +template <> inline const Class##Type *Type::castAs() const { \ + return cast(CanonicalType); \ } #include "clang/AST/TypeNodes.def" @@ -1655,7 +1675,7 @@ // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; while (T->isInnerRef()) - T = T->PointeeType->getAs(); + T = T->PointeeType->castAs(); return T->PointeeType; } @@ -3737,7 +3757,7 @@ /// would return 'A1P' (and we'd have to make iterating over /// qualifiers more complicated). const ObjCObjectType *getObjectType() const { - return PointeeType->getAs(); + return PointeeType->castAs(); } /// getInterfaceType - If this pointer points to an Objective C @@ -4050,7 +4070,7 @@ return isa(CanonicalType); } inline bool Type::isFunctionPointerType() const { - if (const PointerType* T = getAs()) + if (const PointerType *T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; @@ -4174,6 +4194,13 @@ return isObjCObjectPointerType(); } +inline const Type *Type::getBaseElementTypeUnsafe() const { + const Type *type = this; + while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) + type = arrayType->getElementType().getTypePtr(); + return type; +} + /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, @@ -4234,6 +4261,21 @@ return cast(getUnqualifiedDesugaredType()); } +template const T *Type::castAs() const { + ArrayType_cannot_be_used_with_getAs at; + (void) at; + + assert(isa(CanonicalType)); + if (const T *ty = dyn_cast(this)) return ty; + return cast(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa(CanonicalType)); + if (const ArrayType *arr = dyn_cast(this)) return arr; + return cast(getUnqualifiedDesugaredType()); +} + } // end namespace clang #endif From geek4civic at gmail.com Thu Jan 27 01:09:24 2011 From: geek4civic at gmail.com (NAKAMURA Takumi) Date: Thu, 27 Jan 2011 18:09:24 +0900 Subject: [cfe-commits] [PATCH] 7bit-ize In-Reply-To: References: Message-ID: Committed in r124363, thank you! ...Takumi From rjmccall at apple.com Thu Jan 27 01:37:57 2011 From: rjmccall at apple.com (John McCall) Date: Thu, 27 Jan 2011 09:37:57 -0000 Subject: [cfe-commits] r124373 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/CodeGen/CGCXXABI.cpp lib/CodeGen/CGCXXABI.h lib/CodeGen/CGExprCXX.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Sema/SemaExprCXX.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/delete-two-arg.cpp Message-ID: <20110127093757.25C5F2A6C12C@llvm.org> Author: rjmccall Date: Thu Jan 27 03:37:56 2011 New Revision: 124373 URL: http://llvm.org/viewvc/llvm-project?rev=124373&view=rev Log: Do a proper recursive lookup when deciding whether a class's usual deallocation function has a two-argument form. Store the result of this check in new[] and delete[] nodes. Fixes rdar://problem/8913519 Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/CodeGen/CGCXXABI.cpp cfe/trunk/lib/CodeGen/CGCXXABI.h cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriterStmt.cpp cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Jan 27 03:37:56 2011 @@ -992,8 +992,11 @@ bool Initializer : 1; // Do we allocate an array? If so, the first SubExpr is the size expression. bool Array : 1; + // If this is an array allocation, does the usual deallocation + // function for the allocated type want to know the allocated size? + bool UsualArrayDeleteWantsSize : 1; // The number of placement new arguments. - unsigned NumPlacementArgs : 15; + unsigned NumPlacementArgs : 14; // The number of constructor arguments. This may be 1 even for non-class // types; use the pseudo copy constructor. unsigned NumConstructorArgs : 14; @@ -1029,8 +1032,8 @@ SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, - FunctionDecl *operatorDelete, QualType ty, - TypeSourceInfo *AllocatedTypeInfo, + FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, + QualType ty, TypeSourceInfo *AllocatedTypeInfo, SourceLocation startLoc, SourceLocation endLoc, SourceLocation constructorLParen, SourceLocation constructorRParen); @@ -1082,9 +1085,14 @@ SourceRange getTypeIdParens() const { return TypeIdParens; } bool isGlobalNew() const { return GlobalNew; } - void setGlobalNew(bool V) { GlobalNew = V; } bool hasInitializer() const { return Initializer; } - void setHasInitializer(bool V) { Initializer = V; } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } unsigned getNumConstructorArgs() const { return NumConstructorArgs; } @@ -1169,6 +1177,9 @@ // to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm // will be true). bool ArrayFormAsWritten : 1; + // Does the usual deallocation function for the element type require + // a size_t argument? + bool UsualArrayDeleteWantsSize : 1; // Points to the operator delete overload that is used. Could be a member. FunctionDecl *OperatorDelete; // The pointer expression to be deleted. @@ -1177,12 +1188,13 @@ SourceLocation Loc; public: CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, - bool arrayFormAsWritten, FunctionDecl *operatorDelete, - Expr *arg, SourceLocation loc) + bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, + FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, arg->containsUnexpandedParameterPack()), GlobalDelete(globalDelete), ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), OperatorDelete(operatorDelete), Argument(arg), Loc(loc) { } explicit CXXDeleteExpr(EmptyShell Shell) : Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { } @@ -1191,6 +1203,14 @@ bool isArrayForm() const { return ArrayForm; } bool isArrayFormAsWritten() const { return ArrayFormAsWritten; } + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. This can be true even if the actual deallocation + /// function that we're using doesn't want a size. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } Expr *getArgument() { return cast(Argument); } Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Jan 27 03:37:56 2011 @@ -111,7 +111,8 @@ SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, - FunctionDecl *operatorDelete, QualType ty, + FunctionDecl *operatorDelete, + bool usualArrayDeleteWantsSize, QualType ty, TypeSourceInfo *AllocatedTypeInfo, SourceLocation startLoc, SourceLocation endLoc, SourceLocation constructorLParen, @@ -119,8 +120,9 @@ : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->containsUnexpandedParameterPack()), - GlobalNew(globalNew), - Initializer(initializer), SubExprs(0), OperatorNew(operatorNew), + GlobalNew(globalNew), Initializer(initializer), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), + SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens), StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen), Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Thu Jan 27 03:37:56 2011 @@ -142,13 +142,14 @@ CGF.EmitReturnOfRValue(RV, ResultType); } -CharUnits CGCXXABI::GetArrayCookieSize(QualType ElementType) { +CharUnits CGCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { return CharUnits::Zero(); } llvm::Value *CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType) { // Should never be called. ErrorUnsupportedABI(CGF, "array cookie initialization"); @@ -156,7 +157,8 @@ } void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, - QualType ElementType, llvm::Value *&NumElements, + const CXXDeleteExpr *expr, QualType ElementType, + llvm::Value *&NumElements, llvm::Value *&AllocPtr, CharUnits &CookieSize) { ErrorUnsupportedABI(CGF, "array cookie reading"); Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Thu Jan 27 03:37:56 2011 @@ -189,7 +189,7 @@ /// /// \param ElementType - the allocated type of the expression, /// i.e. the pointee type of the expression result type - virtual CharUnits GetArrayCookieSize(QualType ElementType); + virtual CharUnits GetArrayCookieSize(const CXXNewExpr *expr); /// Initialize the array cookie for the given allocation. /// @@ -202,6 +202,7 @@ virtual llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType); /// Reads the array cookie associated with the given pointer, @@ -218,6 +219,7 @@ /// \param CookieSize - an out parameter which will be initialized /// with the size of the cookie, or zero if there is no cookie virtual void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + const CXXDeleteExpr *expr, QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, CharUnits &CookieSize); Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Jan 27 03:37:56 2011 @@ -395,7 +395,7 @@ if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew)) return CharUnits::Zero(); - return CGF.CGM.getCXXABI().GetArrayCookieSize(E->getAllocatedType()); + return CGF.CGM.getCXXABI().GetArrayCookieSize(E); } static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, @@ -1065,7 +1065,7 @@ if (AllocSize != AllocSizeWithoutCookie) { assert(E->isArray()); NewPtr = CGM.getCXXABI().InitializeArrayCookie(CGF, NewPtr, NumElements, - AllocType); + E, AllocType); } // If there's an operator delete, enter a cleanup to call it if an @@ -1271,18 +1271,19 @@ /// Emit the code for deleting an array of objects. static void EmitArrayDelete(CodeGenFunction &CGF, - const FunctionDecl *OperatorDelete, + const CXXDeleteExpr *E, llvm::Value *Ptr, QualType ElementType) { llvm::Value *NumElements = 0; llvm::Value *AllocatedPtr = 0; CharUnits CookieSize; - CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, ElementType, + CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, E, ElementType, NumElements, AllocatedPtr, CookieSize); assert(AllocatedPtr && "ReadArrayCookie didn't set AllocatedPtr"); // Make sure that we call delete even if one of the dtors throws. + const FunctionDecl *OperatorDelete = E->getOperatorDelete(); CGF.EHStack.pushCleanup(NormalAndEHCleanup, AllocatedPtr, OperatorDelete, NumElements, ElementType, @@ -1352,7 +1353,7 @@ cast(Ptr->getType())->getElementType()); if (E->isArrayForm()) { - EmitArrayDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy); + EmitArrayDelete(*this, E, Ptr, DeleteTy); } else { EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy); } Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Jan 27 03:37:56 2011 @@ -47,7 +47,9 @@ return PtrDiffTy; } - bool NeedsArrayCookie(QualType ElementType); + bool NeedsArrayCookie(const CXXNewExpr *expr); + bool NeedsArrayCookie(const CXXDeleteExpr *expr, + QualType elementType); public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : @@ -105,12 +107,14 @@ void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - CharUnits GetArrayCookieSize(QualType ElementType); + CharUnits GetArrayCookieSize(const CXXNewExpr *expr); llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType); void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + const CXXDeleteExpr *expr, QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, CharUnits &CookieSize); @@ -140,12 +144,14 @@ void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); - CharUnits GetArrayCookieSize(QualType ElementType); + CharUnits GetArrayCookieSize(const CXXNewExpr *expr); llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType); void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + const CXXDeleteExpr *expr, QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, CharUnits &CookieSize); @@ -794,67 +800,49 @@ /************************** Array allocation cookies **************************/ -bool ItaniumCXXABI::NeedsArrayCookie(QualType ElementType) { - ElementType = getContext().getBaseElementType(ElementType); - const RecordType *RT = ElementType->getAs(); - if (!RT) return false; - - const CXXRecordDecl *RD = cast(RT->getDecl()); - - // If the class has a non-trivial destructor, it always needs a cookie. - if (!RD->hasTrivialDestructor()) return true; - +bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) { // If the class's usual deallocation function takes two arguments, - // it needs a cookie. Otherwise we don't need a cookie. - const CXXMethodDecl *UsualDeallocationFunction = 0; + // it needs a cookie. + if (expr->doesUsualArrayDeleteWantSize()) + return true; + + // Otherwise, if the class has a non-trivial destructor, it always + // needs a cookie. + const CXXRecordDecl *record = + expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + return (record && !record->hasTrivialDestructor()); +} - // Usual deallocation functions of this form are always found on the - // class. - // - // FIXME: what exactly is this code supposed to do if there's an - // ambiguity? That's possible with using declarations. - DeclarationName OpName = - getContext().DeclarationNames.getCXXOperatorName(OO_Array_Delete); - DeclContext::lookup_const_iterator Op, OpEnd; - for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); Op != OpEnd; ++Op) { - const CXXMethodDecl *Delete = - cast((*Op)->getUnderlyingDecl()); - - if (Delete->isUsualDeallocationFunction()) { - UsualDeallocationFunction = Delete; - break; - } - } - - // No usual deallocation function, we don't need a cookie. - if (!UsualDeallocationFunction) - return false; - - // The usual deallocation function doesn't take a size_t argument, - // so we don't need a cookie. - if (UsualDeallocationFunction->getNumParams() == 1) - return false; - - assert(UsualDeallocationFunction->getNumParams() == 2 && - "Unexpected deallocation function type!"); - return true; +bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr, + QualType elementType) { + // If the class's usual deallocation function takes two arguments, + // it needs a cookie. + if (expr->doesUsualArrayDeleteWantSize()) + return true; + + // Otherwise, if the class has a non-trivial destructor, it always + // needs a cookie. + const CXXRecordDecl *record = + elementType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + return (record && !record->hasTrivialDestructor()); } -CharUnits ItaniumCXXABI::GetArrayCookieSize(QualType ElementType) { - if (!NeedsArrayCookie(ElementType)) +CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { + if (!NeedsArrayCookie(expr)) return CharUnits::Zero(); - // Padding is the maximum of sizeof(size_t) and alignof(ElementType) + // Padding is the maximum of sizeof(size_t) and alignof(elementType) ASTContext &Ctx = getContext(); return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()), - Ctx.getTypeAlignInChars(ElementType)); + Ctx.getTypeAlignInChars(expr->getAllocatedType())); } llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType) { - assert(NeedsArrayCookie(ElementType)); + assert(NeedsArrayCookie(expr)); unsigned AS = cast(NewPtr->getType())->getAddressSpace(); @@ -887,6 +875,7 @@ void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + const CXXDeleteExpr *expr, QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, @@ -896,7 +885,7 @@ const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); // If we don't need an array cookie, bail out early. - if (!NeedsArrayCookie(ElementType)) { + if (!NeedsArrayCookie(expr, ElementType)) { AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); NumElements = 0; CookieSize = CharUnits::Zero(); @@ -927,8 +916,8 @@ NumElements = CGF.Builder.CreateLoad(NumElementsPtr); } -CharUnits ARMCXXABI::GetArrayCookieSize(QualType ElementType) { - if (!NeedsArrayCookie(ElementType)) +CharUnits ARMCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { + if (!NeedsArrayCookie(expr)) return CharUnits::Zero(); // On ARM, the cookie is always: @@ -944,8 +933,9 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, + const CXXNewExpr *expr, QualType ElementType) { - assert(NeedsArrayCookie(ElementType)); + assert(NeedsArrayCookie(expr)); // NewPtr is a char*. @@ -978,6 +968,7 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + const CXXDeleteExpr *expr, QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, @@ -987,7 +978,7 @@ const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); // If we don't need an array cookie, bail out early. - if (!NeedsArrayCookie(ElementType)) { + if (!NeedsArrayCookie(expr, ElementType)) { AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); NumElements = 0; CookieSize = CharUnits::Zero(); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 03:37:56 2011 @@ -664,6 +664,61 @@ return move(Result); } +/// doesUsualArrayDeleteWantSize - Answers whether the usual +/// operator delete[] for the given type has a size_t parameter. +static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, + QualType allocType) { + const RecordType *record = + allocType->getBaseElementTypeUnsafe()->getAs(); + if (!record) return false; + + // Try to find an operator delete[] in class scope. + + DeclarationName deleteName = + S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(ops, record->getDecl()); + + // We're just doing this for information. + ops.suppressDiagnostics(); + + // Very likely: there's no operator delete[]. + if (ops.empty()) return false; + + // If it's ambiguous, it should be illegal to call operator delete[] + // on this thing, so it doesn't matter if we allocate extra space or not. + if (ops.isAmbiguous()) return false; + + LookupResult::Filter filter = ops.makeFilter(); + while (filter.hasNext()) { + NamedDecl *del = filter.next()->getUnderlyingDecl(); + + // C++0x [basic.stc.dynamic.deallocation]p2: + // A template instance is never a usual deallocation function, + // regardless of its signature. + if (isa(del)) { + filter.erase(); + continue; + } + + // C++0x [basic.stc.dynamic.deallocation]p2: + // If class T does not declare [an operator delete[] with one + // parameter] but does declare a member deallocation function + // named operator delete[] with exactly two parameters, the + // second of which has type std::size_t, then this function + // is a usual deallocation function. + if (!cast(del)->isUsualDeallocationFunction()) { + filter.erase(); + continue; + } + } + filter.done(); + + if (!ops.isSingleResult()) return false; + + const FunctionDecl *del = cast(ops.getFoundDecl()); + return (del->getNumParams() == 2); +} /// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode @@ -839,6 +894,14 @@ UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); + + // If this is an array allocation, compute whether the usual array + // deallocation function for the type has a size_t parameter. + bool UsualArrayDeleteWantsSize = false; + if (ArraySize && !AllocType->isDependentType()) + UsualArrayDeleteWantsSize + = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); + llvm::SmallVector AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. @@ -938,6 +1001,7 @@ PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, + UsualArrayDeleteWantsSize, ResultType, AllocTypeInfo, StartLoc, Init ? ConstructorRParen : @@ -1492,6 +1556,7 @@ FunctionDecl *OperatorDelete = 0; bool ArrayFormAsWritten = ArrayForm; + bool UsualArrayDeleteWantsSize = false; if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); @@ -1587,6 +1652,21 @@ FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) return ExprError(); + // If we're allocating an array of records, check whether the + // usual operator delete[] has a size_t parameter. + if (ArrayForm) { + // If the user specifically asked to use the global allocator, + // we'll need to do the lookup into the class. + if (UseGlobal) + UsualArrayDeleteWantsSize = + doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); + + // Otherwise, the usual operator delete[] should be the + // function we just found. + else if (isa(OperatorDelete)) + UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); + } + if (!RD->hasTrivialDestructor()) if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { MarkDeclarationReferenced(StartLoc, @@ -1606,13 +1686,14 @@ } MarkDeclarationReferenced(StartLoc, OperatorDelete); - + // FIXME: Check access and ambiguity of operator delete and destructor. } return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, - ArrayFormAsWritten, OperatorDelete, - Ex, StartLoc)); + ArrayFormAsWritten, + UsualArrayDeleteWantsSize, + OperatorDelete, Ex, StartLoc)); } /// \brief Check the use of the given variable as a C++ condition in an if, Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Thu Jan 27 03:37:56 2011 @@ -1106,8 +1106,9 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { VisitExpr(E); - E->setGlobalNew(Record[Idx++]); - E->setHasInitializer(Record[Idx++]); + E->GlobalNew = Record[Idx++]; + E->Initializer = Record[Idx++]; + E->UsualArrayDeleteWantsSize = Record[Idx++]; bool isArray = Record[Idx++]; unsigned NumPlacementArgs = Record[Idx++]; unsigned NumCtorArgs = Record[Idx++]; @@ -1140,6 +1141,7 @@ E->GlobalDelete = Record[Idx++]; E->ArrayForm = Record[Idx++]; E->ArrayFormAsWritten = Record[Idx++]; + E->UsualArrayDeleteWantsSize = Record[Idx++]; E->OperatorDelete = cast_or_null(Reader.GetDecl(Record[Idx++])); E->Argument = Reader.ReadSubExpr(); E->Loc = ReadSourceLocation(Record, Idx); Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Thu Jan 27 03:37:56 2011 @@ -1101,6 +1101,7 @@ VisitExpr(E); Record.push_back(E->isGlobalNew()); Record.push_back(E->hasInitializer()); + Record.push_back(E->doesUsualArrayDeleteWantSize()); Record.push_back(E->isArray()); Record.push_back(E->getNumPlacementArgs()); Record.push_back(E->getNumConstructorArgs()); @@ -1125,6 +1126,7 @@ Record.push_back(E->isGlobalDelete()); Record.push_back(E->isArrayForm()); Record.push_back(E->isArrayFormAsWritten()); + Record.push_back(E->doesUsualArrayDeleteWantSize()); Writer.AddDeclRef(E->getOperatorDelete(), Record); Writer.AddStmt(E->getArgument()); Writer.AddSourceLocation(E->getSourceRange().getBegin(), Record); Modified: cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp?rev=124373&r1=124372&r2=124373&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp (original) +++ cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp Thu Jan 27 03:37:56 2011 @@ -1,6 +1,70 @@ // RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s -struct A { void operator delete(void*,__typeof(sizeof(int))); int x; }; -void a(A* x) { delete x; } +typedef __typeof(sizeof(int)) size_t; -// CHECK: call void @_ZN1AdlEPvj(i8* %{{.*}}, i32 4) +namespace test1 { + struct A { void operator delete(void*,size_t); int x; }; + + // CHECK: define void @_ZN5test11aEPNS_1AE( + void a(A *x) { + // CHECK: load + // CHECK-NEXT: icmp eq {{.*}}, null + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN5test11AdlEPvj(i8* %{{.*}}, i32 4) + delete x; + } +} + +// Check that we make cookies for the two-arg delete even when using +// the global allocator and deallocator. +namespace test2 { + struct A { + int x; + void *operator new[](size_t); + void operator delete[](void *, size_t); + }; + + // CHECK: define [[A:%.*]]* @_ZN5test24testEv() + A *test() { + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znaj(i32 44) + // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[NEW]] to i32* + // CHECK-NEXT: store i32 10, i32* [[T0]] + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[NEW]], i64 4 + // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[A]]* + // CHECK-NEXT: ret [[A]]* [[T2]] + return ::new A[10]; + } + + // CHECK: define void @_ZN5test24testEPNS_1AE( + void test(A *p) { + // CHECK: [[P:%.*]] = alloca [[A]]*, align 4 + // CHECK-NEXT: store [[A]]* {{%.*}}, [[A]]** [[P]], align 4 + // CHECK-NEXT: [[T0:%.*]] = load [[A]]** [[P]], align 4 + // CHECK-NEXT: [[T1:%.*]] = icmp eq [[A]]* [[T0]], null + // CHECK-NEXT: br i1 [[T1]], + // CHECK: [[T2:%.*]] = bitcast [[A]]* [[T0]] to i8* + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 -4 + // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i32* + // CHECK-NEXT: [[T5:%.*]] = load i32* [[T4]] + // CHECK-NEXT: call void @_ZdaPv(i8* [[T3]]) + // CHECK-NEXT: br label + ::delete[] p; + } +} + +// rdar://problem/8913519 +namespace test3 { + struct A { + int x; + void operator delete[](void *, size_t); + }; + struct B : A {}; + + // CHECK: define void @_ZN5test34testEv() + void test() { + // CHECK: call noalias i8* @_Znaj(i32 24) + // CHECK-NEXT: bitcast + // CHECK-NEXT: store i32 5 + (void) new B[5]; + } +} From Axel.Naumann at cern.ch Thu Jan 27 02:55:51 2011 From: Axel.Naumann at cern.ch (Axel Naumann) Date: Thu, 27 Jan 2011 10:55:51 -0000 Subject: [cfe-commits] r124374 - in /cfe/trunk: lib/Basic/FileManager.cpp lib/Frontend/TextDiagnosticPrinter.cpp lib/Serialization/ASTReader.cpp test/PCH/missing-file.cpp Message-ID: <20110127105551.D0D272A6C12C@llvm.org> Author: axel Date: Thu Jan 27 04:55:51 2011 New Revision: 124374 URL: http://llvm.org/viewvc/llvm-project?rev=124374&view=rev Log: TextDiagnosticPrinter.cpp: Show diagnostics as far as possible even with invalid PresomedLoc, instead of just silencing it. FileManager.cpp: Allow virtual files in nonexistent directories. FileManager.cpp: Close FileDescriptor for virtual files that correspond to actual files. FileManager.cpp: Enable virtual files to be created even for files that were flagged as NON_EXISTENT_FILE, e.g. by a prior (unsuccessful) addFile(). ASTReader.cpp: Read a PCH even if the original source files cannot be found. Add a test for reading a PCH of a file that has been removed and diagnostics referencing that file. Added: cfe/trunk/test/PCH/missing-file.cpp Modified: cfe/trunk/lib/Basic/FileManager.cpp cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp cfe/trunk/lib/Serialization/ASTReader.cpp Modified: cfe/trunk/lib/Basic/FileManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=124374&r1=124373&r2=124374&view=diff ============================================================================== --- cfe/trunk/lib/Basic/FileManager.cpp (original) +++ cfe/trunk/lib/Basic/FileManager.cpp Thu Jan 27 04:55:51 2011 @@ -350,18 +350,17 @@ FileEntries.GetOrCreateValue(Filename); // See if there is already an entry in the map. - if (NamedFileEnt.getValue()) - return NamedFileEnt.getValue() == NON_EXISTENT_FILE - ? 0 : NamedFileEnt.getValue(); + if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE) + return NamedFileEnt.getValue(); ++NumFileCacheMisses; // By default, initialize it to invalid. NamedFileEnt.setValue(NON_EXISTENT_FILE); + // We allow the directory to not exist. If it does exist we store it. + // const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); - if (DirInfo == 0) // Directory doesn't exist, file can't exist. - return 0; FileEntry *UFE = new FileEntry(); VirtualFileEntries.push_back(UFE); @@ -381,8 +380,13 @@ // newly-created file entry. int FileDescriptor = -1; struct stat StatBuf; - if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) + if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) { + // If the stat process opened the file, close it to avoid a FD leak. + if (FileDescriptor != -1) + close(FileDescriptor); + return UFE; + } UFE->FD = FileDescriptor; llvm::SmallString<128> FilePath(UFE->Name); Modified: cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp?rev=124374&r1=124373&r2=124374&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp (original) +++ cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp Thu Jan 27 04:55:51 2011 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" @@ -139,8 +140,9 @@ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; - // If the start/end passed each other, then we are trying to highlight a range - // that just exists in whitespace, which must be some sort of other bug. + // If the start/end passed each other, then we are trying to highlight a + // range that just exists in whitespace, which must be some sort of other + // bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } @@ -781,78 +783,94 @@ if (Info.getLocation().isValid()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); - if (PLoc.isInvalid()) - return; - - unsigned LineNo = PLoc.getLine(); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - if (LastWarningLoc != PLoc.getIncludeLoc()) { - LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(LastWarningLoc, SM); - StartOfLocationInfo = OS.tell(); - } - - // Compute the column number. - if (DiagOpts->ShowLocation && PLoc.isValid()) { - if (DiagOpts->ShowColors) - OS.changeColor(savedColor, true); + if (PLoc.isInvalid()) { + // At least print the file name if available: + FileID FID = SM.getFileID(Info.getLocation()); + if (!FID.isInvalid()) { + const FileEntry* FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) { + OS << FE->getName(); + if (FE->getDevice() == 0 && FE->getInode() == 0 + && FE->getFileMode() == 0) { + // in PCH is a guess, but a good one: + OS << " (in PCH)"; + } + OS << ": "; + } + } + } else { + unsigned LineNo = PLoc.getLine(); - // Emit a Visual Studio compatible line number syntax. - if (LangOpts && LangOpts->Microsoft) { - OS << PLoc.getFilename() << '(' << LineNo << ')'; - OS << " : "; - } else { - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + StartOfLocationInfo = OS.tell(); } - if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { - FileID CaretFileID = - SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); - bool PrintedRange = false; - - for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { - // Ignore invalid ranges. - if (!Info.getRange(i).isValid()) continue; - - SourceLocation B = Info.getRange(i).getBegin(); - SourceLocation E = Info.getRange(i).getEnd(); - B = SM.getInstantiationLoc(B); - E = SM.getInstantiationLoc(E); - - // If the End location and the start location are the same and are a - // macro location, then the range was something that came from a macro - // expansion or _Pragma. If this is an object-like macro, the best we - // can do is to highlight the range. If this is a function-like - // macro, we'd also like to highlight the arguments. - if (B == E && Info.getRange(i).getEnd().isMacroID()) - E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; - - std::pair BInfo = SM.getDecomposedLoc(B); - std::pair EInfo = SM.getDecomposedLoc(E); - - // If the start or end of the range is in another file, just discard - // it. - if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) - continue; - - // Add in the length of the token, so that we cover multi-char tokens. - unsigned TokSize = 0; - if (Info.getRange(i).isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); - - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; - PrintedRange = true; + + // Compute the column number. + if (DiagOpts->ShowLocation && PLoc.isValid()) { + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; } + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { + FileID CaretFileID = + SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); + bool PrintedRange = false; + + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { + // Ignore invalid ranges. + if (!Info.getRange(i).isValid()) continue; + + SourceLocation B = Info.getRange(i).getBegin(); + SourceLocation E = Info.getRange(i).getEnd(); + B = SM.getInstantiationLoc(B); + E = SM.getInstantiationLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a + // macro expansion or _Pragma. If this is an object-like macro, the + // best we can do is to highlight the range. If this is a + // function-like macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; + + std::pair BInfo = SM.getDecomposedLoc(B); + std::pair EInfo = SM.getDecomposedLoc(E); + + // If the start or end of the range is in another file, just discard + // it. + if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + continue; + + // Add in the length of the token, so that we cover multi-char + // tokens. + unsigned TokSize = 0; + if (Info.getRange(i).isTokenRange()) + TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); + + OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) + << '}'; + PrintedRange = true; + } - if (PrintedRange) - OS << ':'; + if (PrintedRange) + OS << ':'; + } } OS << ' '; if (DiagOpts->ShowColors) Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=124374&r1=124373&r2=124374&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jan 27 04:55:51 2011 @@ -1232,6 +1232,9 @@ std::string Filename(BlobStart, BlobStart + BlobLen); MaybeAddSystemRootToFilename(Filename); const FileEntry *File = FileMgr.getFile(Filename); + if (File == 0) + File = FileMgr.getVirtualFile(Filename, (off_t)Record[4], + (time_t)Record[5]); if (File == 0) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; Added: cfe/trunk/test/PCH/missing-file.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/missing-file.cpp?rev=124374&view=auto ============================================================================== --- cfe/trunk/test/PCH/missing-file.cpp (added) +++ cfe/trunk/test/PCH/missing-file.cpp Thu Jan 27 04:55:51 2011 @@ -0,0 +1,32 @@ +// Test reading of PCH without original input files. + +// Generate the PCH, removing the original file: +// RUN: echo 'struct S{char c; int i; }; void foo() {}' > %t.h +// RUN: echo 'template void tf() { T::foo(); }' >> %t.h +// RUN: echo '#define RETURN return &i' >> %t.h +// RUN: %clang_cc1 -x c++ -emit-pch -o %t.h.pch %t.h +// RUN: rm %t.h + +// Check diagnostic with location in original source: +// RUN: %clang_cc1 -include-pch %t.h.pch -Wpadded -emit-obj %s 2> %t.stderr +// RUN: grep 'bytes to align' %t.stderr + +// Check diagnostic with 2nd location in original source: +// RUN: not %clang_cc1 -DREDECL -include-pch %t.h.pch -emit-obj %s 2> %t.stderr +// RUN: grep 'previous definition is here' %t.stderr + +// Check diagnostic with instantiation location in original source: +// RUN: not %clang_cc1 -DINSTANTIATION -include-pch %t.h.pch -emit-obj %s 2> %t.stderr +// RUN: grep 'cannot be used prior to' %t.stderr + +void qq(S*) {} + +#ifdef REDECL +float foo() {return 0f;} +#endif + +#ifdef INSTANTIATION +void f() { + tf(); +} +#endif From akyrtzi at gmail.com Thu Jan 27 08:17:11 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Thu, 27 Jan 2011 16:17:11 -0000 Subject: [cfe-commits] r124376 - in /cfe/trunk: include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h lib/StaticAnalyzer/Checkers/ExprEngine.cpp test/Analysis/properties.m Message-ID: <20110127161711.5D9682A6C12C@llvm.org> Author: akirtzidis Date: Thu Jan 27 10:17:11 2011 New Revision: 124376 URL: http://llvm.org/viewvc/llvm-project?rev=124376&view=rev Log: [analyzer] Fix crash when handling dot syntax on 'super'. Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp cfe/trunk/test/Analysis/properties.m Modified: cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h?rev=124376&r1=124375&r2=124376&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h Thu Jan 27 10:17:11 2011 @@ -78,7 +78,10 @@ assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) return msgE->getInstanceReceiver(); - return cast(MsgOrPropE)->getBase(); + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (propE->isObjectReceiver()) + return propE->getBase(); + return 0; } bool isInstanceMessage() const { Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=124376&r1=124375&r2=124376&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Thu Jan 27 10:17:11 2011 @@ -2073,12 +2073,13 @@ void ExprEngine::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - - // Visit the base expression, which is needed for computing the lvalue - // of the ivar. ExplodedNodeSet dstBase; - const Expr *baseExpr = Ex->getBase(); - Visit(baseExpr, Pred, dstBase); + + // Visit the receiver (if any). + if (Ex->isObjectReceiver()) + Visit(Ex->getBase(), Pred, dstBase); + else + dstBase = Pred; ExplodedNodeSet dstPropRef; @@ -2087,7 +2088,6 @@ I!=E; ++I) { ExplodedNode *nodeBase = *I; const GRState *state = GetState(nodeBase); - SVal baseVal = state->getSVal(baseExpr); MakeNode(dstPropRef, Ex, *I, state->BindExpr(Ex, loc::ObjCPropRef(Ex))); } Modified: cfe/trunk/test/Analysis/properties.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/properties.m?rev=124376&r1=124375&r2=124376&view=diff ============================================================================== --- cfe/trunk/test/Analysis/properties.m (original) +++ cfe/trunk/test/Analysis/properties.m Thu Jan 27 10:17:11 2011 @@ -133,3 +133,13 @@ p.name = [[NSString string] retain]; // expected-warning {{leak}} p.name = [[NSString alloc] init]; // expected-warning {{leak}} } + + at interface SubPerson : Person +-(NSString *)foo; + at end + + at implementation SubPerson +-(NSString *)foo { + return super.name; +} + at end From dgregor at apple.com Thu Jan 27 08:27:11 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 16:27:11 -0000 Subject: [cfe-commits] r124377 - in /cfe/trunk: include/clang-c/Index.h test/Index/print-typekind.c tools/c-index-test/c-index-test.c tools/libclang/CXType.cpp tools/libclang/libclang.darwin.exports tools/libclang/libclang.exports Message-ID: <20110127162711.62E982A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 10:27:11 2011 New Revision: 124377 URL: http://llvm.org/viewvc/llvm-project?rev=124377&view=rev Log: Add libclang functions to determine the const/volatile/restrict qualifiers on a CXType. Patch from Stefan Seefeld, test by me. Modified: cfe/trunk/include/clang-c/Index.h cfe/trunk/test/Index/print-typekind.c cfe/trunk/tools/c-index-test/c-index-test.c cfe/trunk/tools/libclang/CXType.cpp cfe/trunk/tools/libclang/libclang.darwin.exports cfe/trunk/tools/libclang/libclang.exports Modified: cfe/trunk/include/clang-c/Index.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/include/clang-c/Index.h (original) +++ cfe/trunk/include/clang-c/Index.h Thu Jan 27 10:27:11 2011 @@ -1782,6 +1782,24 @@ CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T); /** + * \determine Determine whether a CXType has the "const" qualifier set, + * without looking through typedefs that may have added "const" at a different level. + */ +CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T); + +/** + * \determine Determine whether a CXType has the "volatile" qualifier set, + * without looking through typedefs that may have added "volatile" at a different level. + */ +CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T); + +/** + * \determine Determine whether a CXType has the "restrict" qualifier set, + * without looking through typedefs that may have added "restrict" at a different level. + */ +CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T); + +/** * \brief For pointer types, returns the type of the pointee. * */ Modified: cfe/trunk/test/Index/print-typekind.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/print-typekind.c?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/test/Index/print-typekind.c (original) +++ cfe/trunk/test/Index/print-typekind.c Thu Jan 27 10:27:11 2011 @@ -1,7 +1,7 @@ typedef int FooType; int *p; int *f(int *p, char *x, FooType z) { - FooType w = z; + const FooType w = z; return p + z; } typedef double OtherType; @@ -16,7 +16,7 @@ // CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1] // CHECK: UnexposedStmt= typekind=Invalid [isPOD=0] // CHECK: UnexposedStmt= typekind=Invalid [isPOD=0] -// CHECK: VarDecl=w:4:11 (Definition) typekind=Typedef [canonical=Int] [isPOD=1] +// CHECK: VarDecl=w:4:17 (Definition) typekind=Typedef const [canonical=Int] [isPOD=1] // CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1] // CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1] // CHECK: UnexposedStmt= typekind=Invalid [isPOD=0] Modified: cfe/trunk/tools/c-index-test/c-index-test.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/tools/c-index-test/c-index-test.c (original) +++ cfe/trunk/tools/c-index-test/c-index-test.c Thu Jan 27 10:27:11 2011 @@ -568,6 +568,12 @@ CXString S = clang_getTypeKindSpelling(T.kind); PrintCursor(cursor); printf(" typekind=%s", clang_getCString(S)); + if (clang_isConstQualifiedType(T)) + printf(" const"); + if (clang_isVolatileQualifiedType(T)) + printf(" volatile"); + if (clang_isRestrictQualifiedType(T)) + printf(" restrict"); clang_disposeString(S); /* Print the canonical type if it is different. */ { Modified: cfe/trunk/tools/libclang/CXType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CXType.cpp (original) +++ cfe/trunk/tools/libclang/CXType.cpp Thu Jan 27 10:27:11 2011 @@ -186,6 +186,21 @@ return MakeCXType(AU->getASTContext().getCanonicalType(T), TU); } +unsigned clang_isConstQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalConstQualified(); +} + +unsigned clang_isVolatileQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalVolatileQualified(); +} + +unsigned clang_isRestrictQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalRestrictQualified(); +} + CXType clang_getPointeeType(CXType CT) { QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); Modified: cfe/trunk/tools/libclang/libclang.darwin.exports URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.darwin.exports?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/tools/libclang/libclang.darwin.exports (original) +++ cfe/trunk/tools/libclang/libclang.darwin.exports Thu Jan 27 10:27:11 2011 @@ -109,16 +109,19 @@ _clang_getTypeKindSpelling _clang_hashCursor _clang_isCursorDefinition +_clang_isConstQualifiedType _clang_isDeclaration _clang_isExpression _clang_isInvalid _clang_isPODType _clang_isPreprocessing _clang_isReference +_clang_isRestrictQualifiedType _clang_isStatement _clang_isTranslationUnit _clang_isUnexposed _clang_isVirtualBase +_clang_isVolatileQualifiedType _clang_parseTranslationUnit _clang_reparseTranslationUnit _clang_saveTranslationUnit Modified: cfe/trunk/tools/libclang/libclang.exports URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=124377&r1=124376&r2=124377&view=diff ============================================================================== --- cfe/trunk/tools/libclang/libclang.exports (original) +++ cfe/trunk/tools/libclang/libclang.exports Thu Jan 27 10:27:11 2011 @@ -108,6 +108,7 @@ clang_getTypeDeclaration clang_getTypeKindSpelling clang_hashCursor +clang_isConstQualifiedType clang_isCursorDefinition clang_isDeclaration clang_isExpression @@ -115,10 +116,12 @@ clang_isPODType clang_isPreprocessing clang_isReference +clang_isRestrictQualifiedType clang_isStatement clang_isTranslationUnit clang_isUnexposed clang_isVirtualBase +clang_isVolatileQualifiedType clang_parseTranslationUnit clang_reparseTranslationUnit clang_saveTranslationUnit From dgregor at apple.com Thu Jan 27 10:02:58 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 18:02:58 -0000 Subject: [cfe-commits] r124382 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h lib/Frontend/ASTUnit.cpp tools/c-index-test/c-index-test.c Message-ID: <20110127180258.B72972A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 12:02:58 2011 New Revision: 124382 URL: http://llvm.org/viewvc/llvm-project?rev=124382&view=rev Log: Teach ASTUnit to save the specified target features, since TargetInfo::CreateTargetInfo() mangles the target options in a way that is not idempotent. Fixes . Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h cfe/trunk/lib/Frontend/ASTUnit.cpp cfe/trunk/tools/c-index-test/c-index-test.c Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=124382&r1=124381&r2=124382&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/ASTUnit.h (original) +++ cfe/trunk/include/clang/Frontend/ASTUnit.h Thu Jan 27 12:02:58 2011 @@ -84,6 +84,13 @@ /// LoadFromCommandLine available. llvm::OwningPtr Invocation; + /// \brief The set of target features. + /// + /// FIXME: each time we reparse, we need to restore the set of target + /// features from this vector, because TargetInfo::CreateTargetInfo() + /// mangles the target options in place. Yuck! + std::vector TargetFeatures; + // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=124382&r1=124381&r2=124382&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/ASTUnit.cpp (original) +++ cfe/trunk/lib/Frontend/ASTUnit.cpp Thu Jan 27 12:02:58 2011 @@ -740,6 +740,7 @@ Clang.setDiagnostics(&getDiagnostics()); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { @@ -1229,6 +1230,7 @@ Clang.setDiagnostics(&getDiagnostics()); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { @@ -1418,6 +1420,9 @@ Invocation->getFrontendOpts().DisableFree = false; ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); + // Save the target features. + TargetFeatures = Invocation->getTargetOpts().Features; + llvm::MemoryBuffer *OverrideMainBuffer = 0; if (PrecompilePreamble) { PreambleRebuildCounter = 2; @@ -1876,6 +1881,7 @@ StoredDiagnostics); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { Modified: cfe/trunk/tools/c-index-test/c-index-test.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=124382&r1=124381&r2=124382&view=diff ============================================================================== --- cfe/trunk/tools/c-index-test/c-index-test.c (original) +++ cfe/trunk/tools/c-index-test/c-index-test.c Thu Jan 27 12:02:58 2011 @@ -720,7 +720,7 @@ Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, - /* displayDiagnosics=*/1); + /* displayDiagnosics=*/0); if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { clang_disposeIndex(Idx); From hhinnant at apple.com Thu Jan 27 10:13:18 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 13:13:18 -0500 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <4C93F2F0.8070508@providere-consulting.com> References: <4C93F2F0.8070508@providere-consulting.com> Message-ID: On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: > AMDG > > The attached patch implements __is_base_of and __is_convertible_to. > These are the last intrinsics required to compile the header > that ships with MSVC 10.0. > > In Christ, > Steven Watanabe > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. -Howard From akyrtzi at gmail.com Thu Jan 27 10:16:48 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Thu, 27 Jan 2011 18:16:48 -0000 Subject: [cfe-commits] r124383 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaAttr.cpp test/Sema/pragma-unused.c Message-ID: <20110127181648.BD02E2A6C12C@llvm.org> Author: akirtzidis Date: Thu Jan 27 12:16:48 2011 New Revision: 124383 URL: http://llvm.org/viewvc/llvm-project?rev=124383&view=rev Log: Allow #pragma unused to be used on global variables like gcc. Fixes rdar://8793832. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaAttr.cpp cfe/trunk/test/Sema/pragma-unused.c Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124383&r1=124382&r2=124383&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 27 12:16:48 2011 @@ -279,8 +279,8 @@ def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">; -def warn_pragma_unused_expected_localvar : Warning< - "only local variables can be arguments to '#pragma unused'">; +def warn_pragma_unused_expected_var_arg : Warning< + "only variables can be arguments to '#pragma unused'">; def err_unsupported_pragma_weak : Error< "using '#pragma weak' to refer to an undeclared identifier is not yet supported">; Modified: cfe/trunk/lib/Sema/SemaAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAttr.cpp?rev=124383&r1=124382&r2=124383&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaAttr.cpp Thu Jan 27 12:16:48 2011 @@ -277,8 +277,8 @@ } VarDecl *VD = Lookup.getAsSingle(); - if (!VD || !(VD->hasLocalStorage() || VD->isStaticLocal())) { - Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar) + if (!VD) { + Diag(PragmaLoc, diag::warn_pragma_unused_expected_var_arg) << Name << SourceRange(IdTok.getLocation()); return; } Modified: cfe/trunk/test/Sema/pragma-unused.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pragma-unused.c?rev=124383&r1=124382&r2=124383&view=diff ============================================================================== --- cfe/trunk/test/Sema/pragma-unused.c (original) +++ cfe/trunk/test/Sema/pragma-unused.c Thu Jan 27 12:16:48 2011 @@ -1,16 +1,16 @@ -// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -Wused-but-marked-unused -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -Wused-but-marked-unused -Wunused -verify %s void f1(void) { int x, y, z; #pragma unused(x) #pragma unused(y, z) - int w; // FIXME: We should emit a warning that 'w' is unused. + int w; // expected-warning {{unused}} #pragma unused w // expected-warning{{missing '(' after '#pragma unused' - ignoring}} } void f2(void) { - int x, y; + int x, y; // expected-warning {{unused}} expected-warning {{unused}} #pragma unused(x,) // expected-warning{{expected '#pragma unused' argument to be a variable name}} #pragma unused() // expected-warning{{expected '#pragma unused' argument to be a variable name}} } @@ -20,15 +20,10 @@ } void f4(void) { - int w; // FIXME: We should emit a warning that 'w' is unused. + int w; // expected-warning {{unused}} #pragma unused((w)) // expected-warning{{expected '#pragma unused' argument to be a variable name}} } -int k; -void f5(void) { - #pragma unused(k) // expected-warning{{only local variables can be arguments to '#pragma unused'}} -} - void f6(void) { int z; // no-warning { @@ -64,3 +59,7 @@ #pragma unused(x) // expected-warning{{'x' was marked unused but was used}} return y; } + +// rdar://8793832 +static int glob_var = 0; +#pragma unused(glob_var) From zaffanella at cs.unipr.it Thu Jan 27 10:22:25 2011 From: zaffanella at cs.unipr.it (Enea Zaffanella) Date: Thu, 27 Jan 2011 19:22:25 +0100 Subject: [cfe-commits] Wrong parameter names? Message-ID: <4D41B7E1.9020306@cs.unipr.it> It seems to me that the ASTContext methods for creating array types are misnaming one of their parameters (see attached patch): they call EltTyQuals what actually should be the IndexTypeQuals. This seems just to be a naming issue, since afaict all of the callers of these methods are not misguided by the wrong parameter name and correctly pass in the index qualifiers. Anyway, I suggest to double-check this code for potential issues that I may have missed. Enea. -------------- next part -------------- A non-text attachment was scrubbed... Name: IndexQuals.patch Type: text/x-patch Size: 6059 bytes Desc: not available URL: From dgregor at apple.com Thu Jan 27 10:31:46 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 10:31:46 -0800 Subject: [cfe-commits] Wrong parameter names? In-Reply-To: <4D41B7E1.9020306@cs.unipr.it> References: <4D41B7E1.9020306@cs.unipr.it> Message-ID: <3A40D20F-16C0-4C07-A7E0-2BF0F9650E91@apple.com> On Jan 27, 2011, at 10:22 AM, Enea Zaffanella wrote: > It seems to me that the ASTContext methods for creating array types are > misnaming one of their parameters (see attached patch): they call > EltTyQuals what actually should be the IndexTypeQuals. > > This seems just to be a naming issue, since afaict all of the callers of > these methods are not misguided by the wrong parameter name and > correctly pass in the index qualifiers. Anyway, I suggest to > double-check this code for potential issues that I may have missed. Looks good, please go ahead and commit! - Doug From dgregor at apple.com Thu Jan 27 10:39:26 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 18:39:26 -0000 Subject: [cfe-commits] r124385 - /cfe/trunk/test/Index/retain-target-options.c Message-ID: <20110127183926.B44FD2A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 12:39:26 2011 New Revision: 124385 URL: http://llvm.org/viewvc/llvm-project?rev=124385&view=rev Log: Test for previous commit Added: cfe/trunk/test/Index/retain-target-options.c (with props) Added: cfe/trunk/test/Index/retain-target-options.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/retain-target-options.c?rev=124385&view=auto ============================================================================== --- cfe/trunk/test/Index/retain-target-options.c (added) +++ cfe/trunk/test/Index/retain-target-options.c Thu Jan 27 12:39:26 2011 @@ -0,0 +1,8 @@ +// RUN: c-index-test -test-load-source all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s +// RUN: c-index-test -test-load-source-reparse 1 all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s +// RUN: c-index-test -test-load-source-reparse 5 all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s + +// CHECK: error: #error SSE4_1 used +#if defined(__SSE4_1__) +#error SSE4_1 used +#endif Propchange: cfe/trunk/test/Index/retain-target-options.c ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/Index/retain-target-options.c ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/Index/retain-target-options.c ------------------------------------------------------------------------------ svn:mime-type = text/plain From kremenek at apple.com Thu Jan 27 10:43:03 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 18:43:03 -0000 Subject: [cfe-commits] r124386 - in /cfe/trunk: lib/Lex/PPMacroExpansion.cpp lib/StaticAnalyzer/CFRefCount.cpp test/Analysis/retain-release.m www/analyzer/annotations.html Message-ID: <20110127184303.D1FEE2A6C12C@llvm.org> Author: kremenek Date: Thu Jan 27 12:43:03 2011 New Revision: 124386 URL: http://llvm.org/viewvc/llvm-project?rev=124386&view=rev Log: Wire up attributes 'ns_consumed' and 'cf_consumed' in the static analyzer's ObjC retain/release checker. Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp cfe/trunk/test/Analysis/retain-release.m cfe/trunk/www/analyzer/annotations.html Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124386&r1=124385&r2=124386&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Thu Jan 27 12:43:03 2011 @@ -537,6 +537,8 @@ .Case("attribute_ns_returns_not_retained", true) .Case("attribute_ns_returns_retained", true) .Case("attribute_ns_consumes_self", true) + .Case("attribute_ns_consumed", true) + .Case("attribute_cf_consumed", true) .Case("attribute_objc_ivar_unused", true) .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124386&r1=124385&r2=124386&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Thu Jan 27 12:43:03 2011 @@ -451,6 +451,10 @@ return DefaultArgEffect; } + + void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { + Args = af.add(Args, idx, e); + } /// setDefaultArgEffect - Set the default argument effect. void setDefaultArgEffect(ArgEffect E) { @@ -1191,6 +1195,20 @@ if (!FD) return; + // Effects on the parameters. + unsigned parm_idx = 0; + for (FunctionDecl::param_const_iterator pi = FD->param_begin(), + pe = FD->param_end(); pi != pe; ++pi) { + const ParmVarDecl *pd = *pi; + if (pd->getAttr()) { + if (!GCEnabled) + Summ.addArg(AF, parm_idx, DecRef); + } + else if(pd->getAttr()) { + Summ.addArg(AF, parm_idx, DecRef); + } + } + QualType RetTy = FD->getResultType(); // Determine if there is a special return effect for this method. @@ -1225,7 +1243,22 @@ // Effects on the receiver. if (MD->getAttr()) { - Summ.setReceiverEffect(DecRefMsg); + if (!GCEnabled) + Summ.setReceiverEffect(DecRefMsg); + } + + // Effects on the parameters. + unsigned parm_idx = 0; + for (ObjCMethodDecl::param_iterator pi=MD->param_begin(), pe=MD->param_end(); + pi != pe; ++pi, ++parm_idx) { + const ParmVarDecl *pd = *pi; + if (pd->getAttr()) { + if (!GCEnabled) + Summ.addArg(AF, parm_idx, DecRef); + } + else if(pd->getAttr()) { + Summ.addArg(AF, parm_idx, DecRef); + } } // Determine if there is a special return effect for this method. Modified: cfe/trunk/test/Analysis/retain-release.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=124386&r1=124385&r2=124386&view=diff ============================================================================== --- cfe/trunk/test/Analysis/retain-release.m (original) +++ cfe/trunk/test/Analysis/retain-release.m Thu Jan 27 12:43:03 2011 @@ -16,6 +16,12 @@ #if __has_feature(attribute_ns_consumes_self) #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) #endif +#if __has_feature(attribute_ns_consumed) +#define NS_CONSUMED __attribute__((ns_consumed)) +#endif +#if __has_feature(attribute_cf_consumed) +#define CF_CONSUMED __attribute__((cf_consumed)) +#endif //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from Mac OS X headers: @@ -1215,6 +1221,8 @@ - (NSString*) newStringNoAttr; - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} - (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED; ++ (void) consume:(id) NS_CONSUMED x; ++ (void) consume2:(id) CF_CONSUMED x; @end static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} @@ -1245,6 +1253,24 @@ [x release]; } +void testattr3() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning + [TestOwnershipAttr consume:x]; + TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning + [TestOwnershipAttr consume2:y]; +} + +void consume_ns(id NS_CONSUMED x); +void consume_cf(id CF_CONSUMED x); + +void testattr4() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning + consume_ns(x); + TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning + consume_cf(y); +} + + @interface MyClassTestCFAttr : NSObject {} - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED; - (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED; @@ -1418,7 +1444,7 @@ while (error_to_dump != ((void*)0)) { CFDictionaryRef info; - info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1421 and stored into 'info'}} + info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1447 and stored into 'info'}} if (info != ((void*)0)) { } Modified: cfe/trunk/www/analyzer/annotations.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124386&r1=124385&r2=124386&view=diff ============================================================================== --- cfe/trunk/www/analyzer/annotations.html (original) +++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 12:43:03 2011 @@ -6,7 +6,6 @@ - @@ -38,7 +37,7 @@

    Specific Topics

    -
      +
      • Annotations to Enhance Generic Checks
      • @@ -295,15 +296,15 @@ @implementation MyClass - (NSDate*) returnsCFRetained { - return (NSDate*) returnsRetainedCFDate(); // No leak. + return (NSDate*) returnsRetainedCFDate(); // No leak. } - (NSDate*) alsoReturnsRetained { - return (NSDate*) returnsRetainedCFDate(); // Always report a leak. + return (NSDate*) returnsRetainedCFDate(); // Always report a leak. } - (NSDate*) returnsNSRetained { - return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC. + return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC. } @end @@ -351,6 +352,112 @@ #endif +

        Attribute 'ns_consumed' +(Clang-specific)

        + +

        The 'ns_consumed' attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method. + It indicates to the static analyzer that a release message is implicitly sent to the parameter upon + completion of the call to the given function or method. + +

        Important note when using Garbage Collection: Note that the analyzer +essentially ignores this attribute when code is compiled to use Objective-C +garbage collection. This is because the release message does nothing +when using GC. If the underlying function/method uses something like +CFRelease to decrement the reference count, consider using +the cf_consumed attribute instead.

        + +

        Example

        + +
        +$ cat test.m
        +#ifndef __has_feature      // Optional.
        +#define __has_feature(x) 0 // Compatibility with non-clang compilers.
        +#endif
        +
        +#ifndef NS_CONSUMED
        +#if __has_feature(attribute_ns_consumed)
        +#define NS_CONSUMED __attribute__((NS_CONSUMED))
        +#else
        +#define NS_CONSUMED
        +#endif
        +#endif
        +
        +void consume_ns(id NS_CONSUMED x);
        +
        +void test() {
        +  id x = [[NSObject alloc] init];
        +  consume_ns(x); // No leak!
        +}
        +
        + at interface Foo : NSObject
        ++ (void) releaseArg:(id) NS_CONSUMED x;
        ++ (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y;
        + at end
        +
        +void test_method() {
        +  id x = [[NSObject alloc] init];
        +  [Foo releaseArg:x]; // No leak!
        +}
        +
        +void test_method2() {
        +  id a = [[NSObject alloc] init];
        +  id b = [[NSObject alloc] init];
        +  [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released.
        +}
        +
        + +

        Attribute 'cf_consumed' +(Clang-specific)

        + +

        The 'cf_consumed' attribute is practically identical to ns_consumed. +The attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method. +It indicates to the static analyzer that the object reference is implicitly passed to a call to CFRelease upon +completion of the call to the given function or method.

        + +

        Operationally this attribute is nearly identical to ns_consumed +with the main difference that the reference count decrement still occurs when using Objective-C garbage +collection (which is import for Core Foundation types, which are not automatically garbage collected).

        + +

        Example

        + +
        +$ cat test.m
        +#ifndef __has_feature      // Optional.
        +#define __has_feature(x) 0 // Compatibility with non-clang compilers.
        +#endif
        +
        +#ifndef CF_CONSUMED
        +#if __has_feature(attribute_cf_consumed)
        +#define CF_CONSUMED __attribute__((CF_CONSUMED))
        +#else
        +#define CF_CONSUMED
        +#endif
        +#endif
        +
        +void consume_cf(id CF_CONSUMED x);
        +void consume_CFDate(CFDateRef CF_CONSUMED x);
        +
        +void test() {
        +  id x = [[NSObject alloc] init];
        +  consume_cf(x); // No leak!
        +}
        +
        +void test2() {
        +  CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
        +  consume_CFDate(date); // No leak, including under GC!
        +  
        +}
        +
        + at interface Foo : NSObject
        ++ (void) releaseArg:(CFDateRef) CF_CONSUMED x;
        + at end
        +
        +void test_method() {
        +  CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
        +  [Foo releaseArg:date]; // No leak!
        +}
        +
        +

        Attribute 'ns_consumes_self' (Clang-specific)

        @@ -360,7 +467,9 @@

        One use of this attribute is declare your own init-like methods that do not follow the - standard Cocoa naming conventions. For example:

        + standard Cocoa naming conventions.

        + +

        Example

         #ifndef __has_feature
        
        
        
        
        From dgregor at apple.com  Thu Jan 27 10:50:39 2011
        From: dgregor at apple.com (Douglas Gregor)
        Date: Thu, 27 Jan 2011 18:50:39 -0000
        Subject: [cfe-commits] r124393 -
        	/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
        Message-ID: <20110127185040.011A72A6C12C@llvm.org>
        
        Author: dgregor
        Date: Thu Jan 27 12:50:39 2011
        New Revision: 124393
        
        URL: http://llvm.org/viewvc/llvm-project?rev=124393&view=rev
        Log:
        Clean up the diagnostic text for delegating constructors
        
        Modified:
            cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
        
        Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
        URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124393&r1=124392&r2=124393&view=diff
        ==============================================================================
        --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
        +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 27 12:50:39 2011
        @@ -923,9 +923,9 @@
         
         // C++0x delegating constructors
         def err_delegation_0x_only : Error<
        -  "Delegating constructors are permitted only in C++0x.">;
        +  "delegating constructors are permitted only in C++0x">;
         def err_delegation_unimplemented : Error<
        -  "Delegating constructors are not fully implemented.">;
        +  "delegating constructors are not fully implemented">;
           
         // Objective-C++
         def err_objc_decls_may_only_appear_in_global_scope : Error<
        
        
        
        
        From kremenek at apple.com  Thu Jan 27 10:51:39 2011
        From: kremenek at apple.com (Ted Kremenek)
        Date: Thu, 27 Jan 2011 18:51:39 -0000
        Subject: [cfe-commits] r124394 - in /cfe/trunk:
         lib/Analysis/UninitializedValuesV2.cpp test/Sema/uninit-variables.c
        Message-ID: <20110127185140.02CA12A6C12C@llvm.org>
        
        Author: kremenek
        Date: Thu Jan 27 12:51:39 2011
        New Revision: 124394
        
        URL: http://llvm.org/viewvc/llvm-project?rev=124394&view=rev
        Log:
        Teach -Wuninitialized about indirect goto.  Fixes PR 9071.
        
        Modified:
            cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp
            cfe/trunk/test/Sema/uninit-variables.c
        
        Modified: cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp
        URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp?rev=124394&r1=124393&r2=124394&view=diff
        ==============================================================================
        --- cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp (original)
        +++ cfe/trunk/lib/Analysis/UninitializedValuesV2.cpp Thu Jan 27 12:51:39 2011
        @@ -158,8 +158,8 @@
         llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block,
                                                       const CFGBlock *dstBlock) {
           unsigned idx = block->getBlockID();
        -  if (dstBlock && block->succ_size() == 2 && block->pred_size() == 2) {
        -    assert(block->getTerminator());
        +  if (dstBlock && block->succ_size() == 2 && block->pred_size() == 2 &&
        +      block->getTerminator()) {
             if (getLogicalOperatorInChain(block)) {
               if (*block->succ_begin() == dstBlock)
                 return lazyCreate(vals[idx].first);
        
        Modified: cfe/trunk/test/Sema/uninit-variables.c
        URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/uninit-variables.c?rev=124394&r1=124393&r2=124394&view=diff
        ==============================================================================
        --- cfe/trunk/test/Sema/uninit-variables.c (original)
        +++ cfe/trunk/test/Sema/uninit-variables.c Thu Jan 27 12:51:39 2011
        @@ -229,3 +229,14 @@
           ^{ y = (x == 0); }();
         }
         
        +// Test handling of indirect goto.
        +void test36()
        +{
        +  void **pc; // expected-warning{{use of uninitialized variable 'pc'}} expected-note{{ add initialization to silence this warning}}
        +  void *dummy[] = { &&L1, &&L2 };
        + L1:
        +    goto *pc; // expected-note{{variable 'pc' is possibly uninitialized when used here}}
        + L2:
        +    goto *pc;
        +}
        +
        
        
        
        
        From jyasskin at google.com  Thu Jan 27 11:17:54 2011
        From: jyasskin at google.com (Jeffrey Yasskin)
        Date: Thu, 27 Jan 2011 19:17:54 -0000
        Subject: [cfe-commits] r124398 - 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
        Message-ID: <20110127191754.E2FDD2A6C12C@llvm.org>
        
        Author: jyasskin
        Date: Thu Jan 27 13:17:54 2011
        New Revision: 124398
        
        URL: http://llvm.org/viewvc/llvm-project?rev=124398&view=rev
        Log:
        Revert r124217 because it didn't catch the actual error case it was trying to
        catch:
        
          lock_guard(my_mutex);
        
        declares a variable instead of creating a temporary.
        
        Removed:
            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=124398&r1=124397&r2=124398&view=diff
        ==============================================================================
        --- cfe/trunk/docs/LanguageExtensions.html (original)
        +++ cfe/trunk/docs/LanguageExtensions.html Thu Jan 27 13:17:54 2011
        @@ -25,7 +25,6 @@
         
      • Vectors and Extended Vectors
      • Messages on deprecated and unavailable attributes
      • Attributes on enumerators
      • -
      • Attribute to forbid temporaries of a type
      • Checks for Standard Language Features
        • C++ exceptions
        • @@ -343,33 +342,6 @@

          Query for this feature with __has_feature(enumerator_attributes).

          -

          Attribute to forbid temporaries of a type

          - - -

          Clang provides a forbid_temporaries attribute to forbid -temporaries of a particular type.

          - -
          -
          class __attribute__((forbid_temporaries)) scoped_lock {
          -  ...
          -};
          -
          - -

          This prevents mistakes like

          - -
          -
          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.
          -};
          -
          - -

          Query for this feature with __has_attribute(forbid_temporaries). -Use -Wno-forbid-temporaries to disable the resulting warning.

          - -

          Checks for Standard Language Features

          Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Thu Jan 27 13:17:54 2011 @@ -232,11 +232,6 @@ 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=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 27 13:17:54 2011 @@ -861,9 +861,6 @@ "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>; // 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=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/AttributeList.h (original) +++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Jan 27 13:17:54 2011 @@ -104,7 +104,6 @@ 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=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/lib/Sema/AttributeList.cpp (original) +++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Jan 27 13:17:54 2011 @@ -85,7 +85,6 @@ .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=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jan 27 13:17:54 2011 @@ -885,24 +885,6 @@ 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(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(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) @@ -2692,8 +2674,6 @@ 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=124398&r1=124397&r2=124398&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 13:17:54 2011 @@ -3294,12 +3294,9 @@ } } - CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->getAttr()) - 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(RT->getDecl()); if (RD->isInvalidDecl() || RD->hasTrivialDestructor()) return Owned(E); Removed: cfe/trunk/test/SemaCXX/forbid-temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/forbid-temporaries.cpp?rev=124397&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/forbid-temporaries.cpp (original) +++ cfe/trunk/test/SemaCXX/forbid-temporaries.cpp (removed) @@ -1,50 +0,0 @@ -// 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 -class __attribute__((forbid_temporaries)) NotATemporaryTpl { -}; - -template -void bar_tpl(const NotATemporaryTpl&); - -void tpl_user() { - NotATemporaryTpl this_is_fine; - bar_tpl(NotATemporaryTpl()); // expected-warning {{must not create temporaries of type 'NotATemporaryTpl'}} - NotATemporaryTpl(); // expected-warning {{must not create temporaries of type 'NotATemporaryTpl'}} -} - - -// Test that a specialization can override the template's default. -struct TemporariesOk; -template<> class NotATemporaryTpl { -}; - -void specialization_user() { - NotATemporaryTpl this_is_fine; - bar_tpl(NotATemporaryTpl()); - NotATemporaryTpl(); -} From kremenek at apple.com Thu Jan 27 11:41:09 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 19:41:09 -0000 Subject: [cfe-commits] r124402 - in /cfe/trunk/www/analyzer: index.html latest_checker.html.incl release_notes.html Message-ID: <20110127194109.1D6772A6C12E@llvm.org> Author: kremenek Date: Thu Jan 27 13:41:08 2011 New Revision: 124402 URL: http://llvm.org/viewvc/llvm-project?rev=124402&view=rev Log: Update checker build and post release notes. Added: cfe/trunk/www/analyzer/release_notes.html Modified: cfe/trunk/www/analyzer/index.html cfe/trunk/www/analyzer/latest_checker.html.incl Modified: cfe/trunk/www/analyzer/index.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/index.html?rev=124402&r1=124401&r2=124402&view=diff ============================================================================== --- cfe/trunk/www/analyzer/index.html (original) +++ cfe/trunk/www/analyzer/index.html Thu Jan 27 13:41:08 2011 @@ -101,9 +101,9 @@
        • Latest build (Universal binary, 10.5+):
        • -
        • Can be used both from the command line and within Xcode
        • -
        • Installation and usage
        • +
        • Release notes
        • +
        • This build can be used both from the command line and from within Xcode
        • +
        • Installation and usage
        Modified: cfe/trunk/www/analyzer/latest_checker.html.incl URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/latest_checker.html.incl?rev=124402&r1=124401&r2=124402&view=diff ============================================================================== --- cfe/trunk/www/analyzer/latest_checker.html.incl (original) +++ cfe/trunk/www/analyzer/latest_checker.html.incl Thu Jan 27 13:41:08 2011 @@ -1 +1 @@ -checker-253.tar.bz2 (built December 16, 2010) +checker-254.tar.bz2 (built January 27, 2011) Added: cfe/trunk/www/analyzer/release_notes.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/release_notes.html?rev=124402&view=auto ============================================================================== --- cfe/trunk/www/analyzer/release_notes.html (added) +++ cfe/trunk/www/analyzer/release_notes.html Thu Jan 27 13:41:08 2011 @@ -0,0 +1,35 @@ + + + + Release notes for checker-XXX builds + + + + + + +
        + +
        + +

        Release notes for checker-XXX builds

        + +

        checker-254

        + +

        built: January 27, 2011
        +download: checker-254.tar.bz2

        +

        highlights:

        + +
          +
        • Introduces new -init method checker to check if a super class's init method is properly called.
        • +
        • Objective-C retain/release checker now reasons about calls to property accessor methods (setter/getter).
        • +
        • Introduces new attribute ns_consumes_self to educate the Objective-C retain/release checker about custom "init-like" methods that do not follow the standard Cocoa naming conventions.
        • +
        • Introduces new attributes ns_consumed and cf_consumed to educate the Objective-C retain/release checker about methods/functions that decrement the reference count of a parameter.
        • +
        + +
        +
        + + + From kremenek at apple.com Thu Jan 27 11:42:34 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 19:42:34 -0000 Subject: [cfe-commits] r124403 - /cfe/trunk/www/analyzer/index.html Message-ID: <20110127194234.E92CB2A6C12D@llvm.org> Author: kremenek Date: Thu Jan 27 13:42:34 2011 New Revision: 124403 URL: http://llvm.org/viewvc/llvm-project?rev=124403&view=rev Log: Add missing Modified: cfe/trunk/www/analyzer/index.html Modified: cfe/trunk/www/analyzer/index.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/index.html?rev=124403&r1=124402&r2=124403&view=diff ============================================================================== --- cfe/trunk/www/analyzer/index.html (original) +++ cfe/trunk/www/analyzer/index.html Thu Jan 27 13:42:34 2011 @@ -101,7 +101,7 @@
      • Latest build (Universal binary, 10.5+):
      • -
      • Release notes
      • +
      • Release notes
      • This build can be used both from the command line and from within Xcode
      • Installation and usage
      From kremenek at apple.com Thu Jan 27 11:49:07 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 19:49:07 -0000 Subject: [cfe-commits] r124405 - /cfe/trunk/www/analyzer/release_notes.html Message-ID: <20110127194907.D8B292A6C12D@llvm.org> Author: kremenek Date: Thu Jan 27 13:49:07 2011 New Revision: 124405 URL: http://llvm.org/viewvc/llvm-project?rev=124405&view=rev Log: Fix download link. Modified: cfe/trunk/www/analyzer/release_notes.html Modified: cfe/trunk/www/analyzer/release_notes.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/release_notes.html?rev=124405&r1=124404&r2=124405&view=diff ============================================================================== --- cfe/trunk/www/analyzer/release_notes.html (original) +++ cfe/trunk/www/analyzer/release_notes.html Thu Jan 27 13:49:07 2011 @@ -18,7 +18,7 @@

      checker-254

      built: January 27, 2011
      -download: checker-254.tar.bz2

      +download: checker-254.tar.bz2

      highlights:

        From abramo.bagnara at gmail.com Thu Jan 27 11:55:10 2011 From: abramo.bagnara at gmail.com (Abramo Bagnara) Date: Thu, 27 Jan 2011 19:55:10 -0000 Subject: [cfe-commits] r124408 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp lib/Sema/SemaInit.cpp Message-ID: <20110127195510.C1ECB2A6C12D@llvm.org> Author: abramo Date: Thu Jan 27 13:55:10 2011 New Revision: 124408 URL: http://llvm.org/viewvc/llvm-project?rev=124408&view=rev Log: Fixed parameter names. Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/Sema/SemaInit.cpp Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=124408&r1=124407&r2=124408&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Thu Jan 27 13:55:10 2011 @@ -570,7 +570,7 @@ /// variable array of the specified element type. QualType getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, + unsigned IndexTypeQuals, SourceRange Brackets) const; /// getDependentSizedArrayType - Returns a non-unique reference to @@ -579,20 +579,20 @@ /// comparable, at some point. QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, + unsigned IndexTypeQuals, SourceRange Brackets) const; /// getIncompleteArrayType - Returns a unique reference to the type for a /// incomplete array of the specified element type. QualType getIncompleteArrayType(QualType EltTy, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) const; + unsigned IndexTypeQuals) const; /// getConstantArrayType - Return the unique reference to the type for a /// constant array of the specified element type. QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) const; + unsigned IndexTypeQuals) const; /// getVariableArrayDecayedType - Returns a vla type where known sizes /// are replaced with [*]. Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=124408&r1=124407&r2=124408&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jan 27 13:55:10 2011 @@ -1440,7 +1440,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, const llvm::APInt &ArySizeIn, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) const { + unsigned IndexTypeQuals) const { assert((EltTy->isDependentType() || EltTy->isIncompleteType() || EltTy->isConstantSizeType()) && "Constant array of VLAs is illegal!"); @@ -1452,7 +1452,7 @@ ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); llvm::FoldingSetNodeID ID; - ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals); + ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals); void *InsertPos = 0; if (ConstantArrayType *ATP = @@ -1465,7 +1465,7 @@ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize, - ASM, EltTypeQuals); + ASM, IndexTypeQuals); Canon = getQualifiedType(Canon, canonSplit.second); // Get the new insert position for the node we care about. @@ -1475,7 +1475,7 @@ } ConstantArrayType *New = new(*this,TypeAlignment) - ConstantArrayType(EltTy, Canon, ArySize, ASM, EltTypeQuals); + ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1610,7 +1610,7 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, + unsigned IndexTypeQuals, SourceRange Brackets) const { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. @@ -1620,12 +1620,12 @@ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM, - EltTypeQuals, Brackets); + IndexTypeQuals, Brackets); Canon = getQualifiedType(Canon, canonSplit.second); } VariableArrayType *New = new(*this, TypeAlignment) - VariableArrayType(EltTy, Canon, NumElts, ASM, EltTypeQuals, Brackets); + VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=124408&r1=124407&r2=124408&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jan 27 13:55:10 2011 @@ -120,7 +120,7 @@ /// responsible for moving that Index forward as it consumes elements. /// /// Each Check* routine also has a StructuredList/StructuredIndex -/// arguments, which contains the current the "structured" (semantic) +/// arguments, which contains the current "structured" (semantic) /// initializer list and the index into that initializer list where we /// are copying initializers as we map them over to the semantic /// list. Once we have completed our recursive walk of the subobject @@ -3293,7 +3293,7 @@ /// /// \param S The Sema object used for type-checking. /// -/// \param T The type of the temporary object, which must either by +/// \param T The type of the temporary object, which must either be /// the type of the initializer expression or a superclass thereof. /// /// \param Enter The entity being initialized. From carl.norum at apple.com Thu Jan 27 12:02:07 2011 From: carl.norum at apple.com (Carl Norum) Date: Thu, 27 Jan 2011 12:02:07 -0800 Subject: [cfe-commits] Building EFI with Clang on Mac OS X Message-ID: <68DAF2F3-1F63-4ACC-BAA1-03B286E754A8@apple.com> Hi folks, I've attached a patch for review; these are the changes we use to build EFI for Mac boot ROMs using clang/llvm on Mac OS X. The simplest explanation is that it's a partial implementation of gcc's "-mms-bitfields" flag for clang. Let me know what you think! -- Carl -------------- next part -------------- A non-text attachment was scrubbed... Name: clang-efi.patch Type: application/octet-stream Size: 6162 bytes Desc: not available URL: -------------- next part -------------- From dgregor at apple.com Thu Jan 27 12:28:01 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 20:28:01 -0000 Subject: [cfe-commits] r124425 - in /cfe/trunk: include/clang/Basic/TokenKinds.def include/clang/Basic/TypeTraits.h lib/AST/StmtPrinter.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/type-traits.cpp Message-ID: <20110127202801.6A5B32A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 14:28:01 2011 New Revision: 124425 URL: http://llvm.org/viewvc/llvm-project?rev=124425&view=rev Log: Implement the Microsoft __is_convertible_to type trait, modeling the semantics after the C++0x is_convertible type trait. This implementation is not 100% complete, because it allows access errors to be hard errors (rather than just evaluating false). Original patch by Steven Watanabe! Modified: cfe/trunk/include/clang/Basic/TokenKinds.def cfe/trunk/include/clang/Basic/TypeTraits.h cfe/trunk/lib/AST/StmtPrinter.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/ParseTentative.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/SemaCXX/type-traits.cpp Modified: cfe/trunk/include/clang/Basic/TokenKinds.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TokenKinds.def (original) +++ cfe/trunk/include/clang/Basic/TokenKinds.def Thu Jan 27 14:28:01 2011 @@ -319,6 +319,7 @@ KEYWORD(__is_abstract , KEYCXX) KEYWORD(__is_base_of , KEYCXX) KEYWORD(__is_class , KEYCXX) +KEYWORD(__is_convertible_to , KEYCXX) KEYWORD(__is_empty , KEYCXX) KEYWORD(__is_enum , KEYCXX) KEYWORD(__is_pod , KEYCXX) @@ -326,7 +327,6 @@ KEYWORD(__is_union , KEYCXX) // Tentative name - there's no implementation of std::is_literal_type yet. KEYWORD(__is_literal , KEYCXX) -// FIXME: Add MS's traits, too. // Apple Extension. KEYWORD(__private_extern__ , KEYALL) Modified: cfe/trunk/include/clang/Basic/TypeTraits.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TypeTraits.h?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TypeTraits.h (original) +++ cfe/trunk/include/clang/Basic/TypeTraits.h Thu Jan 27 14:28:01 2011 @@ -39,7 +39,8 @@ /// BinaryTypeTrait - Names for the binary type traits. enum BinaryTypeTrait { BTT_IsBaseOf, - BTT_TypeCompatible + BTT_TypeCompatible, + BTT_IsConvertibleTo }; } Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Thu Jan 27 14:28:01 2011 @@ -1225,9 +1225,9 @@ static const char *getTypeTraitName(BinaryTypeTrait BTT) { switch (BTT) { - default: llvm_unreachable("Unknown binary type trait"); case BTT_IsBaseOf: return "__is_base_of"; case BTT_TypeCompatible: return "__builtin_types_compatible_p"; + case BTT_IsConvertibleTo: return "__is_convertible_to"; } return ""; } Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Jan 27 14:28:01 2011 @@ -537,8 +537,9 @@ /// '__is_polymorphic' /// '__is_union' /// -/// [GNU] binary-type-trait: -/// '__is_base_of' [TODO] +/// binary-type-trait: +/// [GNU] '__is_base_of' +/// [MS] '__is_convertible_to' /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, @@ -988,6 +989,7 @@ case tok::kw___builtin_types_compatible_p: case tok::kw___is_base_of: + case tok::kw___is_convertible_to: return ParseBinaryTypeTrait(); case tok::at: { Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Jan 27 14:28:01 2011 @@ -1828,6 +1828,7 @@ default: llvm_unreachable("Not a known binary type trait"); case tok::kw___is_base_of: return BTT_IsBaseOf; case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; + case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; } } Modified: cfe/trunk/lib/Parse/ParseTentative.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTentative.cpp (original) +++ cfe/trunk/lib/Parse/ParseTentative.cpp Thu Jan 27 14:28:01 2011 @@ -655,6 +655,7 @@ case tok::kw___is_abstract: case tok::kw___is_base_of: case tok::kw___is_class: + case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: case tok::kw___is_pod: Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 14:28:01 2011 @@ -2499,6 +2499,52 @@ case BTT_TypeCompatible: return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), RhsT.getUnqualifiedType()); + + case BTT_IsConvertibleTo: { + // C++0x [meta.rel]p4: + // Given the following function prototype: + // + // template + // typename add_rvalue_reference::type create(); + // + // the predicate condition for a template specialization + // is_convertible shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We model the initialization as a copy-initialization of a temporary + // of the appropriate type, which for this expression is identical to the + // return statement (since NRVO doesn't apply). + if (LhsT->isObjectType() || LhsT->isFunctionType()) + LhsT = Self.Context.getRValueReferenceType(LhsT); + + InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); + OpaqueValueExpr From(LhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(LhsT)); + Expr *FromPtr = &From; + InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, + SourceLocation())); + + // Perform the initialization within a SFINAE trap. + // FIXME: We don't implement the access-checking bits yet, because we don't + // handle access control as part of SFINAE. + Sema::SFINAETrap SFINAE(Self); + InitializationSequence Init(Self, To, Kind, &FromPtr, 1); + if (Init.getKind() == InitializationSequence::FailedSequence) + return false; + ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); + return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); + } } llvm_unreachable("Unknown type trait or not implemented"); } @@ -2538,9 +2584,9 @@ // Select trait result type. QualType ResultType; switch (BTT) { - default: llvm_unreachable("Unknown type trait or not implemented"); case BTT_IsBaseOf: ResultType = Context.BoolTy; break; case BTT_TypeCompatible: ResultType = Context.IntTy; break; + case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break; } return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo, Modified: cfe/trunk/test/SemaCXX/type-traits.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=124425&r1=124424&r2=124425&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) +++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jan 27 14:28:01 2011 @@ -497,3 +497,31 @@ isBaseOfT, DerivedB >(); isBaseOfF, BaseA >(); } + +struct FromInt { FromInt(int); }; +struct ToInt { operator int(); }; +typedef void Function(); + +void is_convertible_to() { + int t01[T(__is_convertible_to(Int, Int))]; + int t02[F(__is_convertible_to(Int, IntAr))]; + int t03[F(__is_convertible_to(IntAr, IntAr))]; + int t04[T(__is_convertible_to(void, void))]; + int t05[T(__is_convertible_to(cvoid, void))]; + int t06[T(__is_convertible_to(void, cvoid))]; + int t07[T(__is_convertible_to(cvoid, cvoid))]; + int t08[T(__is_convertible_to(int, FromInt))]; + int t09[T(__is_convertible_to(long, FromInt))]; + int t10[T(__is_convertible_to(double, FromInt))]; + int t11[T(__is_convertible_to(const int, FromInt))]; + int t12[T(__is_convertible_to(const int&, FromInt))]; + int t13[T(__is_convertible_to(ToInt, int))]; + int t14[T(__is_convertible_to(ToInt, const int&))]; + int t15[T(__is_convertible_to(ToInt, long))]; + int t16[F(__is_convertible_to(ToInt, int&))]; + int t17[F(__is_convertible_to(ToInt, FromInt))]; + int t18[T(__is_convertible_to(IntAr&, IntAr&))]; + int t19[T(__is_convertible_to(IntAr&, const IntAr&))]; + int t20[F(__is_convertible_to(const IntAr&, IntAr&))]; + int t21[F(__is_convertible_to(Function, Function))]; +} From dgregor at apple.com Thu Jan 27 12:31:25 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 12:31:25 -0800 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: References: <4C93F2F0.8070508@providere-consulting.com> Message-ID: <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: > On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: > >> AMDG >> >> The attached patch implements __is_base_of and __is_convertible_to. >> These are the last intrinsics required to compile the header >> that ships with MSVC 10.0. >> >> In Christ, >> Steven Watanabe >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > > Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. I've updated the patch and committed it as r124425. Thanks, Steven! - Doug From dgregor at apple.com Thu Jan 27 12:35:44 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 20:35:44 -0000 Subject: [cfe-commits] r124428 - /cfe/trunk/lib/Sema/SemaExprCXX.cpp Message-ID: <20110127203544.F05AB2A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 14:35:44 2011 New Revision: 124428 URL: http://llvm.org/viewvc/llvm-project?rev=124428&view=rev Log: Document some serious badness in our evaluation of the type traits: we need to be sure we have complete types in many cases Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124428&r1=124427&r2=124428&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 14:35:44 2011 @@ -2219,6 +2219,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, SourceLocation KeyLoc) { + // FIXME: For many of these traits, we need a complete type before we can + // check these properties. assert(!T->isDependentType() && "Cannot evaluate traits for dependent types."); ASTContext &C = Self.Context; From hhinnant at apple.com Thu Jan 27 12:45:09 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 15:45:09 -0500 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> Message-ID: On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: > > On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: > >> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >> >>> AMDG >>> >>> The attached patch implements __is_base_of and __is_convertible_to. >>> These are the last intrinsics required to compile the header >>> that ships with MSVC 10.0. >>> >>> In Christ, >>> Steven Watanabe >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >> >> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. > > I've updated the patch and committed it as r124425. Thanks, Steven! Excellent, thanks Doug! I believe that's going to fix about a hundred libc++/clang++0x test failures! -Howard From dgregor at apple.com Thu Jan 27 12:52:13 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 12:52:13 -0800 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> Message-ID: <5FEB07F7-FD89-4737-9F0C-2240D824FCD7@apple.com> On Jan 27, 2011, at 12:45 PM, Howard Hinnant wrote: > On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: > >> >> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: >> >>> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >>> >>>> AMDG >>>> >>>> The attached patch implements __is_base_of and __is_convertible_to. >>>> These are the last intrinsics required to compile the header >>>> that ships with MSVC 10.0. >>>> >>>> In Christ, >>>> Steven Watanabe >>>> >>>> _______________________________________________ >>>> cfe-commits mailing list >>>> cfe-commits at cs.uiuc.edu >>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>> >>> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. >> >> I've updated the patch and committed it as r124425. Thanks, Steven! > > Excellent, thanks Doug! I believe that's going to fix about a hundred libc++/clang++0x test failures! FWIW, I noticed that I needed one tweak to libc++/test/container/MoveOnly.h to really make switching to __is_convertible_to useful: instead of declaring the copy constructor and copy assignment operator as private, I declared them as deleted (when deleted functions are available, which they are in Clang). Or you could wait... I'm in the process of teaching __is_convertible_to to do the right thing when there are access control failures, which will make the MoveOnly.h tweak irrelevant. - Doug From hhinnant at apple.com Thu Jan 27 12:55:57 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 15:55:57 -0500 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <5FEB07F7-FD89-4737-9F0C-2240D824FCD7@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> <5FEB07F7-FD89-4737-9F0C-2240D824FCD7@apple.com> Message-ID: <30D59C12-60A4-4425-8BD5-02A0B506872C@apple.com> On Jan 27, 2011, at 3:52 PM, Douglas Gregor wrote: > > On Jan 27, 2011, at 12:45 PM, Howard Hinnant wrote: > >> On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: >> >>> >>> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: >>> >>>> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >>>> >>>>> AMDG >>>>> >>>>> The attached patch implements __is_base_of and __is_convertible_to. >>>>> These are the last intrinsics required to compile the header >>>>> that ships with MSVC 10.0. >>>>> >>>>> In Christ, >>>>> Steven Watanabe >>>>> >>>>> _______________________________________________ >>>>> cfe-commits mailing list >>>>> cfe-commits at cs.uiuc.edu >>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>>> >>>> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. >>> >>> I've updated the patch and committed it as r124425. Thanks, Steven! >> >> Excellent, thanks Doug! I believe that's going to fix about a hundred libc++/clang++0x test failures! > > FWIW, I noticed that I needed one tweak to libc++/test/container/MoveOnly.h to really make switching to __is_convertible_to useful: instead of declaring the copy constructor and copy assignment operator as private, I declared them as deleted (when deleted functions are available, which they are in Clang). > > Or you could wait... I'm in the process of teaching __is_convertible_to to do the right thing when there are access control failures, which will make the MoveOnly.h tweak irrelevant. Thanks for the warning. If you're working on it now, I'll just wait. Lot's of stuff on my to-do queue. I won't actually be waiting on you. :-) -Howard From hhinnant at apple.com Thu Jan 27 13:00:00 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 21:00:00 -0000 Subject: [cfe-commits] [libcxx] r124429 - /libcxx/trunk/include/type_traits Message-ID: <20110127210000.51C182A6C12E@llvm.org> Author: hhinnant Date: Thu Jan 27 15:00:00 2011 New Revision: 124429 URL: http://llvm.org/viewvc/llvm-project?rev=124429&view=rev Log: Reverted previous fix to is_convertible as it caused more problems than it fixed. But this reverted fix will only matter for non-clang compilers. Installed __is_convertible_to for clang. Modified: libcxx/trunk/include/type_traits Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124429&r1=124428&r2=124429&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Thu Jan 27 15:00:00 2011 @@ -598,9 +598,22 @@ // is_convertible +#ifdef __clang__ + +template struct _LIBCPP_VISIBLE is_convertible + : public integral_constant {}; +{ +}; + +#else // __clang__ + namespace __is_convertible_imp { +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +template char __test(const volatile typename remove_reference<_Tp>::type&&); +#else template char __test(_Tp); +#endif template __two __test(...); #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES template _Tp&& __source(); @@ -694,6 +707,8 @@ static const size_t __complete_check2 = __is_convertible_check<_T2>::__v; }; +#endif // __clang__ + // is_base_of // (C) Copyright Rani Sharoni 2003. From hhinnant at apple.com Thu Jan 27 13:00:35 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 21:00:35 -0000 Subject: [cfe-commits] [libcxx] r124430 - /libcxx/trunk/include/forward_list Message-ID: <20110127210035.5172E2A6C12D@llvm.org> Author: hhinnant Date: Thu Jan 27 15:00:35 2011 New Revision: 124430 URL: http://llvm.org/viewvc/llvm-project?rev=124430&view=rev Log: Make forward_list splice_after and merge work for lvalue lists Modified: libcxx/trunk/include/forward_list Modified: libcxx/trunk/include/forward_list URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/forward_list?rev=124430&r1=124429&r2=124430&view=diff ============================================================================== --- libcxx/trunk/include/forward_list (original) +++ libcxx/trunk/include/forward_list Thu Jan 27 15:00:35 2011 @@ -106,15 +106,21 @@ void resize(size_type n, const value_type& v); void clear(); + void splice_after(const_iterator p, forward_list& x); void splice_after(const_iterator p, forward_list&& x); + void splice_after(const_iterator p, forward_list& x, const_iterator i); void splice_after(const_iterator p, forward_list&& x, const_iterator i); + void splice_after(const_iterator p, forward_list& x, + const_iterator first, const_iterator last); void splice_after(const_iterator p, forward_list&& x, const_iterator first, const_iterator last); void remove(const value_type& v); template void remove_if(Predicate pred); void unique(); template void unique(BinaryPredicate binary_pred); + void merge(forward_list& x); void merge(forward_list&& x); + template void merge(forward_list& x, Compare comp); template void merge(forward_list&& x, Compare comp); void sort(); template void sort(Compare comp); @@ -632,16 +638,18 @@ void clear() {base::clear();} #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + _LIBCPP_INLINE_VISIBILITY void splice_after(const_iterator __p, forward_list&& __x); + _LIBCPP_INLINE_VISIBILITY void splice_after(const_iterator __p, forward_list&& __x, const_iterator __i); + _LIBCPP_INLINE_VISIBILITY void splice_after(const_iterator __p, forward_list&& __x, const_iterator __f, const_iterator __l); -#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES void splice_after(const_iterator __p, forward_list& __x); void splice_after(const_iterator __p, forward_list& __x, const_iterator __i); void splice_after(const_iterator __p, forward_list& __x, const_iterator __f, const_iterator __l); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES void remove(const value_type& __v); template void remove_if(_Predicate __pred); _LIBCPP_INLINE_VISIBILITY @@ -649,13 +657,15 @@ template void unique(_BinaryPredicate __binary_pred); #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY - void merge(forward_list&& __x) {merge(_STD::move(__x), __less());} - template void merge(forward_list&& __x, _Compare __comp); -#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES + void merge(forward_list&& __x) {merge(__x, __less());} + template + _LIBCPP_INLINE_VISIBILITY + void merge(forward_list&& __x, _Compare __comp) + {merge(__x, _STD::move(__comp));} +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY void merge(forward_list& __x) {merge(__x, __less());} template void merge(forward_list& __x, _Compare __comp); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY void sort() {sort(__less());} template void sort(_Compare __comp); @@ -1201,11 +1211,7 @@ template void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - forward_list&& __x) -#else forward_list& __x) -#endif { if (!__x.empty()) { @@ -1226,11 +1232,7 @@ template void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - forward_list&& __x, -#else forward_list& __x, -#endif const_iterator __i) { const_iterator __lm1 = next(__i); @@ -1248,11 +1250,7 @@ template void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - forward_list&& __x, -#else forward_list& __x, -#endif const_iterator __f, const_iterator __l) { if (__f != __l && __p != __f) @@ -1272,6 +1270,39 @@ } } +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + +template +inline _LIBCPP_INLINE_VISIBILITY +void +forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, + forward_list&& __x) +{ + splice_after(__p, __x); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void +forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, + forward_list&& __x, + const_iterator __i) +{ + splice_after(__p, __x, __i); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void +forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, + forward_list&& __x, + const_iterator __f, const_iterator __l) +{ + splice_after(__p, __x, __f, __l); +} + +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + template void forward_list<_Tp, _Alloc>::remove(const value_type& __v) @@ -1336,11 +1367,7 @@ template template void -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES -forward_list<_Tp, _Alloc>::merge(forward_list&& __x, _Compare __comp) -#else forward_list<_Tp, _Alloc>::merge(forward_list& __x, _Compare __comp) -#endif { if (this != &__x) { From hhinnant at apple.com Thu Jan 27 13:01:11 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 21:01:11 -0000 Subject: [cfe-commits] [libcxx] r124431 - /libcxx/trunk/src/strstream.cpp Message-ID: <20110127210111.717672A6C12C@llvm.org> Author: hhinnant Date: Thu Jan 27 15:01:11 2011 New Revision: 124431 URL: http://llvm.org/viewvc/llvm-project?rev=124431&view=rev Log: clang found a missing return statement. Modified: libcxx/trunk/src/strstream.cpp Modified: libcxx/trunk/src/strstream.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/strstream.cpp?rev=124431&r1=124430&r2=124431&view=diff ============================================================================== --- libcxx/trunk/src/strstream.cpp (original) +++ libcxx/trunk/src/strstream.cpp Thu Jan 27 15:01:11 2011 @@ -130,6 +130,7 @@ __pfree_ = __rhs.__pfree_; __rhs.setg(nullptr, nullptr, nullptr); __rhs.setp(nullptr, nullptr); + return *this; } #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES From hhinnant at apple.com Thu Jan 27 13:01:51 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 21:01:51 -0000 Subject: [cfe-commits] [libcxx] r124432 - /libcxx/trunk/lib/buildit Message-ID: <20110127210151.6E55F2A6C12C@llvm.org> Author: hhinnant Date: Thu Jan 27 15:01:51 2011 New Revision: 124432 URL: http://llvm.org/viewvc/llvm-project?rev=124432&view=rev Log: updated buildit to work with recent clang updates Modified: libcxx/trunk/lib/buildit Modified: libcxx/trunk/lib/buildit URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/lib/buildit?rev=124432&r1=124431&r2=124432&view=diff ============================================================================== --- libcxx/trunk/lib/buildit (original) +++ libcxx/trunk/lib/buildit Thu Jan 27 15:01:51 2011 @@ -36,6 +36,7 @@ SOEXT=dylib if [ "$MACOSX_DEPLOYMENT_TARGET" == "10.6" ] then + EXTRA_FLAGS="-std=c++0x -U__STRICT_ANSI__" LDSHARED_FLAGS="-o libc++.1.dylib \ -dynamiclib -nodefaultlibs -current_version 1 \ -compatibility_version 1 \ @@ -44,6 +45,7 @@ -Wl,-unexported_symbols_list,libc++unexp.exp \ /usr/lib/libSystem.B.dylib" else + EXTRA_FLAGS="-std=c++0x" LDSHARED_FLAGS="-o libc++.1.dylib \ -dynamiclib -nodefaultlibs \ -current_version ${RC_ProjectSourceVersion} -compatibility_version 1 \ @@ -72,7 +74,7 @@ set -x for FILE in ../src/*.cpp; do - $CXX -c -g -Os $RC_CFLAGS -nostdinc++ -I../include $FILE + $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -nostdinc++ -I../include $FILE done From kyrtzidis at apple.com Thu Jan 27 13:06:33 2011 From: kyrtzidis at apple.com (Argyrios Kyrtzidis) Date: Thu, 27 Jan 2011 13:06:33 -0800 Subject: [cfe-commits] r124402 - in /cfe/trunk/www/analyzer: index.html latest_checker.html.incl release_notes.html In-Reply-To: <20110127194109.1D6772A6C12E@llvm.org> References: <20110127194109.1D6772A6C12E@llvm.org> Message-ID: <44B17A9C-B617-43E6-8FCE-543CEAA69BA7@apple.com> On Jan 27, 2011, at 11:41 AM, Ted Kremenek wrote: > Author: kremenek > Date: Thu Jan 27 13:41:08 2011 > New Revision: 124402 > > URL: http://llvm.org/viewvc/llvm-project?rev=124402&view=rev > Log: > Update checker build and post release notes. > > + > +
          > +
        • Introduces new -init method checker to check if a super class's init method is properly called.
        • > +
        • Objective-C retain/release checker now reasons about calls to property accessor methods (setter/getter).
        • Actually all checkers can reason about property accesses (e.g. nil receiver checker) -Argiris > +
        • Introduces new attribute ns_consumes_self to educate the Objective-C retain/release checker about custom "init-like" methods that do not follow the standard Cocoa naming conventions.
        • > +
        • Introduces new attributes ns_consumed and cf_consumed to educate the Objective-C retain/release checker about methods/functions that decrement the reference count of a parameter.
        • > +
        > + > + > + > + > + > + > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From dgregor at apple.com Thu Jan 27 13:06:28 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 21:06:28 -0000 Subject: [cfe-commits] r124441 - in /cfe/trunk: include/clang/AST/ASTDiagnostic.h include/clang/Analysis/AnalysisDiagnostic.h include/clang/Basic/Diagnostic.td include/clang/Basic/DiagnosticIDs.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Driver/DriverDiagnostic.h include/clang/Frontend/FrontendDiagnostic.h include/clang/Lex/LexDiagnostic.h include/clang/Parse/ParseDiagnostic.h include/clang/Sema/SemaDiagnostic.h lib/Basic/DiagnosticIDs.cpp lib/Sema/Sema.cpp Message-ID: <20110127210628.734182A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 15:06:28 2011 New Revision: 124441 URL: http://llvm.org/viewvc/llvm-project?rev=124441&view=rev Log: Separate the access-control diagnostics from other diagnostics that do not have SFINAE behavior. Modified: cfe/trunk/include/clang/AST/ASTDiagnostic.h cfe/trunk/include/clang/Analysis/AnalysisDiagnostic.h cfe/trunk/include/clang/Basic/Diagnostic.td cfe/trunk/include/clang/Basic/DiagnosticIDs.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Driver/DriverDiagnostic.h cfe/trunk/include/clang/Frontend/FrontendDiagnostic.h cfe/trunk/include/clang/Lex/LexDiagnostic.h cfe/trunk/include/clang/Parse/ParseDiagnostic.h cfe/trunk/include/clang/Sema/SemaDiagnostic.h cfe/trunk/lib/Basic/DiagnosticIDs.cpp cfe/trunk/lib/Sema/Sema.cpp Modified: cfe/trunk/include/clang/AST/ASTDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTDiagnostic.h (original) +++ cfe/trunk/include/clang/AST/ASTDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define ASTSTART #include "clang/Basic/DiagnosticASTKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Analysis/AnalysisDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/AnalysisDiagnostic.h (original) +++ cfe/trunk/include/clang/Analysis/AnalysisDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define ANALYSISSTART #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Basic/Diagnostic.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.td?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Diagnostic.td (original) +++ cfe/trunk/include/clang/Basic/Diagnostic.td Thu Jan 27 15:06:28 2011 @@ -56,6 +56,7 @@ string Text = text; DiagClass Class = DC; bit SFINAE = 1; + bit AccessControl = 0; DiagMapping DefaultMapping = defaultmapping; DiagGroup Group; string CategoryName = ""; @@ -74,6 +75,7 @@ class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; } class NoSFINAE { bit SFINAE = 0; } +class AccessControl { bit AccessControl = 1; } // Definitions for Diagnostics. include "DiagnosticASTKinds.td" Modified: cfe/trunk/include/clang/Basic/DiagnosticIDs.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticIDs.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticIDs.h (original) +++ cfe/trunk/include/clang/Basic/DiagnosticIDs.h Thu Jan 27 15:06:28 2011 @@ -42,7 +42,7 @@ // Get typedefs for common diagnostics. enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #include "clang/Basic/DiagnosticCommonKinds.inc" NUM_BUILTIN_COMMON_DIAGNOSTICS #undef DIAG @@ -157,7 +157,11 @@ /// /// The diagnostic should be reported. Various fatal errors (e.g., /// template instantiation depth exceeded) fall into this category. - SFINAE_Report + SFINAE_Report, + + /// \brief The diagnostic is an access-control diagnostic, which will be + /// substitution failures in some contexts and reported in others. + SFINAE_AccessControl }; /// \brief Determines whether the given built-in diagnostic ID is Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 27 15:06:28 2011 @@ -541,65 +541,67 @@ def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; def err_access : Error< - "%1 is a %select{private|protected}0 member of %3">, NoSFINAE; + "%1 is a %select{private|protected}0 member of %3">, AccessControl; def err_access_ctor : Error< - "calling a %select{private|protected}0 constructor of class %2">, NoSFINAE; + "calling a %select{private|protected}0 constructor of class %2">, + AccessControl; def ext_rvalue_to_reference_access_ctor : ExtWarn< "C++98 requires an accessible copy constructor for class %2 when binding " "a reference to a temporary; was %select{private|protected}0">, - NoSFINAE, InGroup; + AccessControl, InGroup; def err_access_base : Error< "%select{base class|inherited virtual base class}0 %1 has %select{private|" "protected}3 %select{constructor|copy constructor|copy assignment operator|" - "destructor}2">, NoSFINAE; + "destructor}2">, AccessControl; def err_access_field: Error< "field of type %0 has %select{private|protected}2 %select{constructor|copy " - "constructor|copy assignment operator|destructor}1">, NoSFINAE; + "constructor|copy assignment operator|destructor}1">, AccessControl; def err_access_ctor_field : Error<"field of type %1 has %select{private|protected}2 constructor">, - NoSFINAE; + AccessControl; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_vbase : Error<"inherited virtual base class %0 has " "%select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_temp : Error<"temporary of type %0 has %select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_exception : Error<"exception object of type %0 has %select{private|protected}1 " - "destructor">, NoSFINAE; + "destructor">, AccessControl; def err_access_dtor_field : Error<"field of type %1 has %select{private|protected}2 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_var : Error<"variable of type %1 has %select{private|protected}2 destructor">, - NoSFINAE; + AccessControl; def err_access_assign_field : Error<"field of type %1 has %select{private|protected}2 copy assignment" " operator">, - NoSFINAE; + AccessControl; def err_access_assign_base : Error<"base class %0 has %select{private|protected}1 copy assignment" " operator">, - NoSFINAE; + AccessControl; def err_access_copy_field : Error<"field of type %1 has %select{private|protected}2 copy constructor">, - NoSFINAE; + AccessControl; def err_access_copy_base : Error<"base class %0 has %select{private|protected}1 copy constructor">, - NoSFINAE; + AccessControl; def err_access_dtor_ivar : Error<"instance variable of type %0 has %select{private|protected}1 " "destructor">, - NoSFINAE; + AccessControl; def note_previous_access_declaration : Note< "previously declared '%1' here">; def err_access_outside_class : Error< - "access to %select{private|protected}0 member outside any class context">; + "access to %select{private|protected}0 member outside any class context">, + AccessControl; def note_access_natural : Note< "%select{|implicitly }1declared %select{private|protected}0 here">; def note_access_constrained_by_path : Note< @@ -707,7 +709,7 @@ def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " - "%select{private|protected}2 base class of %0">, NoSFINAE; + "%select{private|protected}2 base class of %0">, AccessControl; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " @@ -3197,7 +3199,7 @@ // C++ access control def err_conv_to_inaccessible_base : Error< - "conversion from %0 to inaccessible base class %1">, NoSFINAE; + "conversion from %0 to inaccessible base class %1">, AccessControl; def note_inheritance_specifier_here : Note< "'%0' inheritance specifier here">; def note_inheritance_implicitly_private_here : Note< @@ -3566,9 +3568,9 @@ def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; def error_private_ivar_access : Error<"instance variable %0 is private">, - NoSFINAE; + AccessControl; def error_protected_ivar_access : Error<"instance variable %0 is protected">, - NoSFINAE; + AccessControl; def warn_maynot_respond : Warning<"%0 may not respond to %1">; def warn_attribute_method_def : Warning< "method attribute can only be specified on method declarations">; Modified: cfe/trunk/include/clang/Driver/DriverDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/DriverDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/DriverDiagnostic.h (original) +++ cfe/trunk/include/clang/Driver/DriverDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define DRIVERSTART #include "clang/Basic/DiagnosticDriverKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Frontend/FrontendDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/FrontendDiagnostic.h (original) +++ cfe/trunk/include/clang/Frontend/FrontendDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define FRONTENDSTART #include "clang/Basic/DiagnosticFrontendKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Lex/LexDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/LexDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Lex/LexDiagnostic.h (original) +++ cfe/trunk/include/clang/Lex/LexDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define LEXSTART #include "clang/Basic/DiagnosticLexKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Parse/ParseDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/ParseDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/ParseDiagnostic.h (original) +++ cfe/trunk/include/clang/Parse/ParseDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define PARSESTART #include "clang/Basic/DiagnosticParseKinds.inc" #undef DIAG Modified: cfe/trunk/include/clang/Sema/SemaDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaDiagnostic.h?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/SemaDiagnostic.h (original) +++ cfe/trunk/include/clang/Sema/SemaDiagnostic.h Thu Jan 27 15:06:28 2011 @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define SEMASTART #include "clang/Basic/DiagnosticSemaKinds.inc" #undef DIAG Modified: cfe/trunk/lib/Basic/DiagnosticIDs.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticIDs.cpp?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/lib/Basic/DiagnosticIDs.cpp (original) +++ cfe/trunk/lib/Basic/DiagnosticIDs.cpp Thu Jan 27 15:06:28 2011 @@ -42,7 +42,8 @@ unsigned short DiagID; unsigned Mapping : 3; unsigned Class : 3; - bool SFINAE : 1; + unsigned SFINAE : 1; + unsigned AccessControl : 1; unsigned Category : 5; const char *Description; @@ -56,8 +57,8 @@ } static const StaticDiagInfoRec StaticDiagInfo[] = { -#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE, CATEGORY) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, CATEGORY, DESC, GROUP }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -66,7 +67,7 @@ #include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" - { 0, 0, 0, 0, 0, 0, 0} + { 0, 0, 0, 0, 0, 0, 0, 0} }; #undef DIAG @@ -92,7 +93,7 @@ #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 }; const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); @@ -150,6 +151,9 @@ DiagnosticIDs::SFINAEResponse DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) { + if (Info->AccessControl) + return SFINAE_AccessControl; + if (!Info->SFINAE) return SFINAE_Report; Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=124441&r1=124440&r2=124441&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Jan 27 15:06:28 2011 @@ -452,10 +452,12 @@ if (TemplateDeductionInfo *Info = SemaRef.isSFINAEContext()) { switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) { + case DiagnosticIDs::SFINAE_AccessControl: case DiagnosticIDs::SFINAE_Report: // Fall through; we'll report the diagnostic below. break; + case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. From kremenek at apple.com Thu Jan 27 14:00:03 2011 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 27 Jan 2011 22:00:03 -0000 Subject: [cfe-commits] r124445 - /cfe/trunk/www/analyzer/annotations.html Message-ID: <20110127220003.2618A2A6C12C@llvm.org> Author: kremenek Date: Thu Jan 27 16:00:02 2011 New Revision: 124445 URL: http://llvm.org/viewvc/llvm-project?rev=124445&view=rev Log: Adjust casing of attributes in examples. Modified: cfe/trunk/www/analyzer/annotations.html Modified: cfe/trunk/www/analyzer/annotations.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124445&r1=124444&r2=124445&view=diff ============================================================================== --- cfe/trunk/www/analyzer/annotations.html (original) +++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 16:00:02 2011 @@ -376,7 +376,7 @@ #ifndef NS_CONSUMED #if __has_feature(attribute_ns_consumed) -#define NS_CONSUMED __attribute__((NS_CONSUMED)) +#define NS_CONSUMED __attribute__((ns_consumed)) #else #define NS_CONSUMED #endif @@ -428,7 +428,7 @@ #ifndef CF_CONSUMED #if __has_feature(attribute_cf_consumed) -#define CF_CONSUMED __attribute__((CF_CONSUMED)) +#define CF_CONSUMED __attribute__((cf_consumed)) #else #define CF_CONSUMED #endif From dgregor at apple.com Thu Jan 27 14:31:44 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 22:31:44 -0000 Subject: [cfe-commits] r124446 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/Sema.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaCXX/type-traits.cpp Message-ID: <20110127223144.4D17D2A6C12D@llvm.org> Author: dgregor Date: Thu Jan 27 16:31:44 2011 New Revision: 124446 URL: http://llvm.org/viewvc/llvm-project?rev=124446&view=rev Log: Teach the evaluation of the __is_convertible_to trait to translate access control errors into SFINAE errors, so that the trait provides enough support to implement the C++0x std::is_convertible type trait. To get there, the SFINAETrap now knows how to set up a SFINAE context independent of any template instantiations or template argument deduction steps, and (separately) can set a Sema flag to translate access control errors into SFINAE errors. The latter can also be useful if we decide that access control errors during template argument deduction should cause substitution failure (rather than a hard error) as has been proposed for C++0x. Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/test/SemaCXX/type-traits.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124446&r1=124445&r2=124446&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 27 16:31:44 2011 @@ -234,17 +234,23 @@ private: Sema &S; DeclContext *SavedContext; - + unsigned SavedParsingDeclDepth; + public: - ContextRAII(Sema &S, DeclContext *ContextToPush) - : S(S), SavedContext(S.CurContext) { + ContextRAII(Sema &S, DeclContext *ContextToPush, + unsigned ParsingDeclDepth = 0) + : S(S), SavedContext(S.CurContext), + SavedParsingDeclDepth(S.ParsingDeclDepth) + { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; + S.ParsingDeclDepth = 0; } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; + S.ParsingDeclDepth = SavedParsingDeclDepth; SavedContext = 0; } @@ -2803,6 +2809,10 @@ /// A flag to suppress access checking. bool SuppressAccessChecking; + /// \brief When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + void ActOnStartSuppressingAccessChecks(); void ActOnStopSuppressingAccessChecks(); @@ -3708,6 +3718,13 @@ llvm::SmallVector ActiveTemplateInstantiations; + /// \brief Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + /// \brief The number of ActiveTemplateInstantiation entries in /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. @@ -3729,7 +3746,7 @@ /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; - + /// \brief RAII object used to change the argument pack substitution index /// within a \c Sema object. /// @@ -3855,6 +3872,7 @@ private: Sema &SemaRef; bool Invalid; + bool SavedInNonInstantiationSFINAEContext; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); @@ -3870,23 +3888,39 @@ /// template argument substitution failures are not considered /// errors. /// - /// \returns The nearest template-deduction context object, if we are in a - /// SFINAE context, which can be used to capture diagnostics that will be - /// suppressed. Otherwise, returns NULL to indicate that we are not within a - /// SFINAE context. - sema::TemplateDeductionInfo *isSFINAEContext() const; + /// \returns An empty \c llvm::Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + llvm::Optional isSFINAEContext() const; /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument - /// deduction. + /// deduction.` class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + public: - explicit SFINAETrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { } + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } - ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + } /// \brief Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=124446&r1=124445&r2=124446&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Jan 27 16:31:44 2011 @@ -139,7 +139,8 @@ IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), - NumSFINAEErrors(0), SuppressAccessChecking(false), + NumSFINAEErrors(0), SuppressAccessChecking(false), + AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(0), TyposCorrected(0), AnalysisWarnings(*this) @@ -450,14 +451,18 @@ if (!isActive()) return; - if (TemplateDeductionInfo *Info = SemaRef.isSFINAEContext()) { + if (llvm::Optional Info = SemaRef.isSFINAEContext()) { switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) { - case DiagnosticIDs::SFINAE_AccessControl: case DiagnosticIDs::SFINAE_Report: // Fall through; we'll report the diagnostic below. break; - + case DiagnosticIDs::SFINAE_AccessControl: + // Unless access checking is specifically called out as a SFINAE + // error, report this diagnostic. + if (!SemaRef.AccessCheckingSFINAE) + break; + case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. @@ -473,7 +478,8 @@ FlushCounts(); DiagnosticInfo DiagInfo(&SemaRef.Diags); - Info->addSuppressedDiagnostic(DiagInfo.getLocation(), + if (*Info) + (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, SemaRef.Context.getDiagAllocator())); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124446&r1=124445&r2=124446&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 16:31:44 2011 @@ -2537,13 +2537,14 @@ InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); - // Perform the initialization within a SFINAE trap. - // FIXME: We don't implement the access-checking bits yet, because we don't - // handle access control as part of SFINAE. - Sema::SFINAETrap SFINAE(Self); + // Perform the initialization within a SFINAE trap at translation unit + // scope. + Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, &FromPtr, 1); if (Init.getKind() == InitializationSequence::FailedSequence) return false; + ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=124446&r1=124445&r2=124446&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Jan 27 16:31:44 2011 @@ -147,7 +147,10 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange) - : SemaRef(SemaRef) { + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -158,6 +161,7 @@ Inst.TemplateArgs = 0; Inst.NumTemplateArgs = 0; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -168,8 +172,10 @@ const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -181,6 +187,7 @@ Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -193,8 +200,10 @@ ActiveTemplateInstantiation::InstantiationKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -206,6 +215,7 @@ Inst.NumTemplateArgs = NumTemplateArgs; Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); if (!Inst.isInstantiationRecord()) @@ -220,8 +230,10 @@ unsigned NumTemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -232,6 +244,7 @@ Inst.NumTemplateArgs = NumTemplateArgs; Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -244,8 +257,10 @@ const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -257,6 +272,7 @@ Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -267,7 +283,11 @@ NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -278,6 +298,7 @@ Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -290,7 +311,11 @@ TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; @@ -300,6 +325,7 @@ Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -312,7 +338,11 @@ NamedDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -323,6 +353,7 @@ Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -335,7 +366,8 @@ assert(SemaRef.NonInstantiationEntries > 0); --SemaRef.NonInstantiationEntries; } - + SemaRef.InNonInstantiationSFINAEContext + = SavedInNonInstantiationSFINAEContext; SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -530,8 +562,11 @@ } } -TemplateDeductionInfo *Sema::isSFINAEContext() const { +llvm::Optional Sema::isSFINAEContext() const { using llvm::SmallVector; + if (InNonInstantiationSFINAEContext) + return llvm::Optional(0); + for (SmallVector::const_reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); @@ -539,10 +574,10 @@ ++Active) { switch(Active->Kind) { - case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: + case ActiveTemplateInstantiation::TemplateInstantiation: // This is a template instantiation, so there is no SFINAE. - return 0; + return llvm::Optional(); case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: @@ -561,7 +596,7 @@ } } - return 0; + return llvm::Optional(); } /// \brief Retrieve the depth and index of a parameter pack. Modified: cfe/trunk/test/SemaCXX/type-traits.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=124446&r1=124445&r2=124446&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) +++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jan 27 16:31:44 2011 @@ -502,6 +502,12 @@ struct ToInt { operator int(); }; typedef void Function(); +void is_convertible_to(); +class PrivateCopy { + PrivateCopy(const PrivateCopy&); + friend void is_convertible_to(); +}; + void is_convertible_to() { int t01[T(__is_convertible_to(Int, Int))]; int t02[F(__is_convertible_to(Int, IntAr))]; @@ -524,4 +530,5 @@ int t19[T(__is_convertible_to(IntAr&, const IntAr&))]; int t20[F(__is_convertible_to(const IntAr&, IntAr&))]; int t21[F(__is_convertible_to(Function, Function))]; + int t22[F(__is_convertible_to(PrivateCopy, PrivateCopy))]; } From dgregor at apple.com Thu Jan 27 14:36:00 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 14:36:00 -0800 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <30D59C12-60A4-4425-8BD5-02A0B506872C@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> <5FEB07F7-FD89-4737-9F0C-2240D824FCD7@apple.com> <30D59C12-60A4-4425-8BD5-02A0B506872C@apple.com> Message-ID: <431BD947-E19C-4A77-81E0-15F4F279917D@apple.com> On Jan 27, 2011, at 12:55 PM, Howard Hinnant wrote: > On Jan 27, 2011, at 3:52 PM, Douglas Gregor wrote: > >> >> On Jan 27, 2011, at 12:45 PM, Howard Hinnant wrote: >> >>> On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: >>> >>>> >>>> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: >>>> >>>>> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >>>>> >>>>>> AMDG >>>>>> >>>>>> The attached patch implements __is_base_of and __is_convertible_to. >>>>>> These are the last intrinsics required to compile the header >>>>>> that ships with MSVC 10.0. >>>>>> >>>>>> In Christ, >>>>>> Steven Watanabe >>>>>> >>>>>> _______________________________________________ >>>>>> cfe-commits mailing list >>>>>> cfe-commits at cs.uiuc.edu >>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>>>> >>>>> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. >>>> >>>> I've updated the patch and committed it as r124425. Thanks, Steven! >>> >>> Excellent, thanks Doug! I believe that's going to fix about a hundred libc++/clang++0x test failures! >> >> FWIW, I noticed that I needed one tweak to libc++/test/container/MoveOnly.h to really make switching to __is_convertible_to useful: instead of declaring the copy constructor and copy assignment operator as private, I declared them as deleted (when deleted functions are available, which they are in Clang). >> >> Or you could wait... I'm in the process of teaching __is_convertible_to to do the right thing when there are access control failures, which will make the MoveOnly.h tweak irrelevant. > > Thanks for the warning. If you're working on it now, I'll just wait. Lot's of stuff on my to-do queue. I won't actually be waiting on you. :-) FWIW, __is_convertible_to should be reliable in Clang r124446. I was able to compile some move-related tests in libc++ that used to fail because of the private MoveOnly copy constructor. - Doug From fjahanian at apple.com Thu Jan 27 15:18:16 2011 From: fjahanian at apple.com (Fariborz Jahanian) Date: Thu, 27 Jan 2011 23:18:16 -0000 Subject: [cfe-commits] r124451 - in /cfe/trunk: lib/Rewrite/RewriteObjC.cpp test/Rewriter/blockstruct.m Message-ID: <20110127231816.2C3A62A6C12C@llvm.org> Author: fjahanian Date: Thu Jan 27 17:18:15 2011 New Revision: 124451 URL: http://llvm.org/viewvc/llvm-project?rev=124451&view=rev Log: Fix an objective-c rewriter bug rewriting a __block variable declaration of a struct declared type. // rdar://8918702 Added: cfe/trunk/test/Rewriter/blockstruct.m Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=124451&r1=124450&r2=124451&view=diff ============================================================================== --- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Thu Jan 27 17:18:15 2011 @@ -252,7 +252,7 @@ void RewriteTypeIntoString(QualType T, std::string &ResultStr, const FunctionType *&FPRetType); void RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD); + ValueDecl *VD, bool def=false); void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl); @@ -4118,10 +4118,12 @@ void RewriteObjC::RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD) { + ValueDecl *VD, bool def) { assert(BlockByRefDeclNo.count(VD) && "RewriteByRefString: ByRef decl missing"); - ResultStr += "struct __Block_byref_" + Name + + if (def) + ResultStr += "struct "; + ResultStr += "__Block_byref_" + Name + "_" + utostr(BlockByRefDeclNo[VD]) ; } @@ -5112,7 +5114,7 @@ const char *endBuf = SM->getCharacterData(X); std::string Name(ND->getNameAsString()); std::string ByrefType; - RewriteByRefString(ByrefType, Name, ND); + RewriteByRefString(ByrefType, Name, ND, true); ByrefType += " {\n"; ByrefType += " void *__isa;\n"; RewriteByRefString(ByrefType, Name, ND); @@ -5405,7 +5407,7 @@ ValueDecl *ND = (*I); std::string Name(ND->getNameAsString()); std::string RecName; - RewriteByRefString(RecName, Name, ND); + RewriteByRefString(RecName, Name, ND, true); IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + sizeof("struct")); RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, Added: cfe/trunk/test/Rewriter/blockstruct.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/blockstruct.m?rev=124451&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/blockstruct.m (added) +++ cfe/trunk/test/Rewriter/blockstruct.m Thu Jan 27 17:18:15 2011 @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// rdar://8918702 + +typedef void (^b_t)(void); +void a(b_t work) { } +struct _s { + int a; +}; +struct _s *r(); + +void f() { + __block struct _s *s = 0; + a(^{ + s = (struct _s *)r(); + }); +} From hhinnant at apple.com Thu Jan 27 15:18:19 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Thu, 27 Jan 2011 23:18:19 -0000 Subject: [cfe-commits] [libcxx] r124452 - /libcxx/trunk/www/index.html Message-ID: <20110127231819.61FB52A6C12D@llvm.org> Author: hhinnant Date: Thu Jan 27 17:18:19 2011 New Revision: 124452 URL: http://llvm.org/viewvc/llvm-project?rev=124452&view=rev Log: Updated getting started directions. Modified: libcxx/trunk/www/index.html Modified: libcxx/trunk/www/index.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/index.html?rev=124452&r1=124451&r2=124452&view=diff ============================================================================== --- libcxx/trunk/www/index.html (original) +++ libcxx/trunk/www/index.html Thu Jan 27 17:18:19 2011 @@ -121,11 +121,6 @@ support is as well. The only major missing piece of C++'0x support is <atomic>.

        -

        libc++ is currently dependent upon a separate library for the low-level - ABI compatibility with gcc. As a workaround it can be linked against - gcc's libstdc++, or on Mac OS X - this library.

        -

        Here is a by-chapter breakdown of what is passing tests and what isn't. This chart is currently based on testing against g++-4.4.0 with -std=c++0x.

        @@ -138,8 +133,42 @@
        • svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
        • -
        • cd libcxx/lib
        • -
        • ./buildit
        • +
        + +

        To build on Mac OS X 10.6, you need a helper library and header + found here. + cp cxxabi.h to /usr/include, and cp libc++abi.dylib to /usr/lib. +

        + +

        + Next: +

        + +
          +
        • cd libcxx/lib
        • +
        • export TRIPLE=-apple-
        • +
        • ./buildit
        • +
        + +

        + That should result in a libc++.1.dylib. To install it I like to use links + instead of copying, but either should work: +

        + +
          +
        • cd /usr/lib
        • +
        • sudo ln -sf path-to-libcxx/lib/libc++.1.dylib libc++.dylib
        • +
        • cd /usr/include/c++
        • +
        • sudo ln -sf path-to-libcxx/include v1
        • +
        + +

        + To use with clang you can: +

        + +
          +
        • clang++ -stdlib=libc++ test.cpp
        • +
        • clang++ -std=c++0x -stdlib=libc++ test.cpp

        To run the libc++ test suit (recommended):

        From dgregor at apple.com Thu Jan 27 15:22:05 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 23:22:05 -0000 Subject: [cfe-commits] r124453 - in /cfe/trunk: lib/CodeGen/CGExpr.cpp test/CodeGenCXX/rvalue-references.cpp Message-ID: <20110127232205.930C22A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 17:22:05 2011 New Revision: 124453 URL: http://llvm.org/viewvc/llvm-project?rev=124453&view=rev Log: When producing IR for a lvalue-to-rvalue cast *as an lvalue*, only non-class prvalues actually require the realization of a temporary. For everything else, we already have an lvalue (or class prvalue) in the subexpression. Note: we're missing some move elision in this case. I'll tackle that next. Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=124453&r1=124452&r2=124453&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Jan 27 17:22:05 2011 @@ -1772,11 +1772,12 @@ } case CK_NoOp: - if (!E->getSubExpr()->isRValue() || E->getType()->isRecordType()) + case CK_LValueToRValue: + if (!E->getSubExpr()->Classify(getContext()).isPRValue() + || E->getType()->isRecordType()) return EmitLValue(E->getSubExpr()); // Fall through to synthesize a temporary. - case CK_LValueToRValue: case CK_BitCast: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: Modified: cfe/trunk/test/CodeGenCXX/rvalue-references.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rvalue-references.cpp?rev=124453&r1=124452&r2=124453&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rvalue-references.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Thu Jan 27 17:22:05 2011 @@ -34,3 +34,55 @@ // CHECK-NEXT: store i32 {{.*}}, i32* // CHECK-NEXT: ret i32* int &&f2() { return static_cast(getIntPRValue()); } + +bool ok; + +class C +{ + int* state_; + + C(const C&) = delete; + C& operator=(const C&) = delete; +public: + C(int state) : state_(new int(state)) { } + + C(C&& a) { + state_ = a.state_; + a.state_ = 0; + } + + ~C() { + delete state_; + state_ = 0; + } +}; + +C test(); + +// CHECK: define void @_Z15elide_copy_initv +void elide_copy_init() { + ok = false; + // FIXME: We're doing an extra move here, when we shouldn't be! + // CHECK: call void @_Z4testv(%class.C* sret %ref.tmp) + // CHECK: call void @_ZN1CC1EOS_(%class.C* %a, %class.C* %ref.tmp) + // CHECK: call void @_ZN1CD1Ev(%class.C* %ref.tmp) + C a = test(); + // CHECK: call void @_ZN1CD1Ev(%class.C* %a) + // CHECK: ret void +} + +// CHECK: define void @_Z16test_move_returnv +C test_move_return() { + // CHECK: call void @_ZN1CC1Ei + C a1(3); + // CHECK: call void @_ZN1CC1Ei + C a2(4); + if (ok) + // CHECK: call void @_ZN1CC1EOS_ + return a1; + // CHECK: call void @_ZN1CC1EOS_ + return a2; + // CHECK: call void @_ZN1CD1Ev + // CHECK: call void @_ZN1CD1Ev + //CHECK: ret void +} From dgregor at apple.com Thu Jan 27 15:24:55 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 23:24:55 -0000 Subject: [cfe-commits] r124455 - in /cfe/trunk: lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/rvalue-references.cpp Message-ID: <20110127232455.3978F2A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 17:24:55 2011 New Revision: 124455 URL: http://llvm.org/viewvc/llvm-project?rev=124455&view=rev Log: Allow elision of invocations of move constructors from temporary objects. Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124455&r1=124454&r2=124455&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jan 27 17:24:55 2011 @@ -5551,7 +5551,7 @@ // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && - Constructor->isCopyConstructor() && ExprArgs.size() >= 1) { + Constructor->isCopyOrMoveConstructor() && ExprArgs.size() >= 1) { Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); } Modified: cfe/trunk/test/CodeGenCXX/rvalue-references.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rvalue-references.cpp?rev=124455&r1=124454&r2=124455&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rvalue-references.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rvalue-references.cpp Thu Jan 27 17:24:55 2011 @@ -62,13 +62,10 @@ // CHECK: define void @_Z15elide_copy_initv void elide_copy_init() { ok = false; - // FIXME: We're doing an extra move here, when we shouldn't be! - // CHECK: call void @_Z4testv(%class.C* sret %ref.tmp) - // CHECK: call void @_ZN1CC1EOS_(%class.C* %a, %class.C* %ref.tmp) - // CHECK: call void @_ZN1CD1Ev(%class.C* %ref.tmp) + // CHECK: call void @_Z4testv C a = test(); - // CHECK: call void @_ZN1CD1Ev(%class.C* %a) - // CHECK: ret void + // CHECK-NEXT: call void @_ZN1CD1Ev + // CHECK-NEXT: ret void } // CHECK: define void @_Z16test_move_returnv From dgregor at apple.com Thu Jan 27 15:36:08 2011 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 27 Jan 2011 23:36:08 -0000 Subject: [cfe-commits] [libcxx] r124456 - /libcxx/trunk/include/type_traits Message-ID: <20110127233608.9619C2A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 17:36:08 2011 New Revision: 124456 URL: http://llvm.org/viewvc/llvm-project?rev=124456&view=rev Log: Eliminate extraneous {}; Modified: libcxx/trunk/include/type_traits Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124456&r1=124455&r2=124456&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Thu Jan 27 17:36:08 2011 @@ -602,8 +602,6 @@ template struct _LIBCPP_VISIBLE is_convertible : public integral_constant {}; -{ -}; #else // __clang__ From dgregor at apple.com Thu Jan 27 18:26:04 2011 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 28 Jan 2011 02:26:04 -0000 Subject: [cfe-commits] r124465 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Sema/Sema.h lib/AST/Expr.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaObjCProperty.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/SemaCXX/type-traits.cpp Message-ID: <20110128022604.BB68A2A6C12C@llvm.org> Author: dgregor Date: Thu Jan 27 20:26:04 2011 New Revision: 124465 URL: http://llvm.org/viewvc/llvm-project?rev=124465&view=rev Log: Give OpaqueValueExpr a source location, because its source location might be queried in places where we absolutely require a valid location (e.g., for template instantiation). Fixes some major brokenness in the use of __is_convertible_to. Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/Expr.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaObjCProperty.cpp cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriterStmt.cpp cfe/trunk/test/SemaCXX/type-traits.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Thu Jan 27 20:26:04 2011 @@ -3625,15 +3625,22 @@ /// context. class OpaqueValueExpr : public Expr { friend class ASTStmtReader; + SourceLocation Loc; + public: - OpaqueValueExpr(QualType T, ExprValueKind VK, ExprObjectKind OK = OK_Ordinary) + OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, + ExprObjectKind OK = OK_Ordinary) : Expr(OpaqueValueExprClass, T, VK, OK, - T->isDependentType(), T->isDependentType(), false) { + T->isDependentType(), T->isDependentType(), false), + Loc(Loc) { } explicit OpaqueValueExpr(EmptyShell Empty) : Expr(OpaqueValueExprClass, Empty) { } + /// \brief Retrieve the location of this expression. + SourceLocation getLocation() const { return Loc; } + virtual SourceRange getSourceRange() const; virtual child_iterator child_begin(); virtual child_iterator child_end(); Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 27 20:26:04 2011 @@ -4551,7 +4551,8 @@ /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. - AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); + AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, + QualType lhs, QualType rhs); /// Check assignment constraints and prepare for a conversion of the /// RHS to the LHS type. Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Thu Jan 27 20:26:04 2011 @@ -2981,7 +2981,7 @@ Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); } // OpaqueValueExpr -SourceRange OpaqueValueExpr::getSourceRange() const { return SourceRange(); } +SourceRange OpaqueValueExpr::getSourceRange() const { return Loc; } Stmt::child_iterator OpaqueValueExpr::child_begin() { return child_iterator(); } Stmt::child_iterator OpaqueValueExpr::child_end() { return child_iterator(); } Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jan 27 20:26:04 2011 @@ -1472,7 +1472,8 @@ // If this ever proves to be a problem it should be easy to fix. QualType Ty = S.Context.getPointerType(VD->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); - if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) { + if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), + ParamTy, Ty) != Sema::Compatible) { S.Diag(Attr.getParameterLoc(), diag::err_attribute_cleanup_func_arg_incompatible_type) << Attr.getParameterName() << ParamTy << Ty; Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jan 27 20:26:04 2011 @@ -5507,12 +5507,13 @@ } Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { +Sema::CheckAssignmentConstraints(SourceLocation Loc, + QualType lhsType, QualType rhsType) { // Fake up an opaque expression. We don't actually care about what // cast operations are required, so if CheckAssignmentConstraints // adds casts to this they'll be wasted, but fortunately that doesn't // usually happen on valid code. - OpaqueValueExpr rhs(rhsType, VK_RValue); + OpaqueValueExpr rhs(Loc, rhsType, VK_RValue); Expr *rhsPtr = &rhs; CastKind K = CK_Invalid; @@ -6952,7 +6953,7 @@ } } else { // Compound assignment "x += y" - ConvTy = CheckAssignmentConstraints(LHSType, RHSType); + ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType); } if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 20:26:04 2011 @@ -2531,7 +2531,7 @@ LhsT = Self.Context.getRValueReferenceType(LhsT); InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); - OpaqueValueExpr From(LhsT.getNonLValueExprType(Self.Context), + OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original) +++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Thu Jan 27 20:26:04 2011 @@ -440,9 +440,13 @@ Context.canAssignObjCInterfaces( PropType->getAs(), IvarType->getAs()); - else - compat = (CheckAssignmentConstraints(PropType, IvarType) + else { + SourceLocation Loc = PropertyIvarLoc; + if (Loc.isInvalid()) + Loc = PropertyLoc; + compat = (CheckAssignmentConstraints(Loc, PropType, IvarType) == Compatible); + } if (!compat) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << PropType @@ -663,7 +667,7 @@ GetterMethod->getResultType() != property->getType()) { AssignConvertType result = Incompatible; if (property->getType()->isObjCObjectPointerType()) - result = CheckAssignmentConstraints(GetterMethod->getResultType(), + result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(), property->getType()); if (result != Compatible) { Diag(Loc, diag::warn_accessor_property_type_mismatch) Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Thu Jan 27 20:26:04 2011 @@ -1327,6 +1327,7 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); + E->Loc = ReadSourceLocation(Record, Idx); } Stmt *ASTReader::ReadStmt(PerFileData &F) { Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Thu Jan 27 20:26:04 2011 @@ -1332,6 +1332,7 @@ void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); Code = serialization::EXPR_OPAQUE_VALUE; } Modified: cfe/trunk/test/SemaCXX/type-traits.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=124465&r1=124464&r2=124465&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) +++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jan 27 20:26:04 2011 @@ -508,6 +508,11 @@ friend void is_convertible_to(); }; +template +struct X0 { + template X0(const X0&); +}; + void is_convertible_to() { int t01[T(__is_convertible_to(Int, Int))]; int t02[F(__is_convertible_to(Int, IntAr))]; @@ -531,4 +536,5 @@ int t20[F(__is_convertible_to(const IntAr&, IntAr&))]; int t21[F(__is_convertible_to(Function, Function))]; int t22[F(__is_convertible_to(PrivateCopy, PrivateCopy))]; + int t23[T(__is_convertible_to(X0, X0))]; } From echristo at apple.com Thu Jan 27 21:13:18 2011 From: echristo at apple.com (Eric Christopher) Date: Fri, 28 Jan 2011 05:13:18 -0000 Subject: [cfe-commits] r124474 - /cfe/trunk/test/CodeGenObjC/exceptions.m Message-ID: <20110128051318.CDD7B2A6C12D@llvm.org> Author: echristo Date: Thu Jan 27 23:13:18 2011 New Revision: 124474 URL: http://llvm.org/viewvc/llvm-project?rev=124474&view=rev Log: Update exceptions.m for r124462. Modified: cfe/trunk/test/CodeGenObjC/exceptions.m Modified: cfe/trunk/test/CodeGenObjC/exceptions.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/exceptions.m?rev=124474&r1=124473&r2=124474&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjC/exceptions.m (original) +++ cfe/trunk/test/CodeGenObjC/exceptions.m Thu Jan 27 23:13:18 2011 @@ -29,10 +29,10 @@ // CHECK-NEXT: call void @foo() foo(); // CHECK-NEXT: call void @objc_exception_try_exit - // CHECK-NEXT: ret void + // CHECK-NEXT: br label %finally.no_call_exit // CHECK: call void asm sideeffect "", "=*m" - // CHECK-NEXT: ret void + // CHECK-NEXT: br label %finally.no_call_exit } @finally { break; } @@ -65,8 +65,11 @@ // CHECK-NEXT: call void @foo() // CHECK-NEXT: call void @objc_exception_try_exit // CHECK-NEXT: [[T:%.*]] = load i32* [[X]] - // CHECK-NEXT: ret i32 [[T]] + // CHECK-NEXT: br label %finally.no_call_exit foo(); + + // CHECK: %tmp4 = phi i32 + // CHECK-NEXT: ret i32 %tmp4 } @catch (id) { // Landing pad. Note that we elide the re-enter. // CHECK: call void asm sideeffect "", "=*m,=*m"(i32* [[X]] @@ -77,7 +80,7 @@ // This store is dead. // CHECK-NEXT: store i32 [[T2]], i32* [[X]] - // CHECK-NEXT: ret i32 [[T2]] + // CHECK-NEXT: br label %finally.no_call_exit x--; } return x; From rjmccall at apple.com Thu Jan 27 22:05:16 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 06:05:16 -0000 Subject: [cfe-commits] r124476 - /cfe/trunk/test/CodeGenObjC/exceptions.m Message-ID: <20110128060516.53AE22A6C12C@llvm.org> Author: rjmccall Date: Fri Jan 28 00:05:16 2011 New Revision: 124476 URL: http://llvm.org/viewvc/llvm-project?rev=124476&view=rev Log: Not really any point to testing control flow in this test without ret duplication. Modified: cfe/trunk/test/CodeGenObjC/exceptions.m Modified: cfe/trunk/test/CodeGenObjC/exceptions.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/exceptions.m?rev=124476&r1=124475&r2=124476&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjC/exceptions.m (original) +++ cfe/trunk/test/CodeGenObjC/exceptions.m Fri Jan 28 00:05:16 2011 @@ -29,10 +29,8 @@ // CHECK-NEXT: call void @foo() foo(); // CHECK-NEXT: call void @objc_exception_try_exit - // CHECK-NEXT: br label %finally.no_call_exit // CHECK: call void asm sideeffect "", "=*m" - // CHECK-NEXT: br label %finally.no_call_exit } @finally { break; } @@ -65,11 +63,7 @@ // CHECK-NEXT: call void @foo() // CHECK-NEXT: call void @objc_exception_try_exit // CHECK-NEXT: [[T:%.*]] = load i32* [[X]] - // CHECK-NEXT: br label %finally.no_call_exit foo(); - - // CHECK: %tmp4 = phi i32 - // CHECK-NEXT: ret i32 %tmp4 } @catch (id) { // Landing pad. Note that we elide the re-enter. // CHECK: call void asm sideeffect "", "=*m,=*m"(i32* [[X]] @@ -79,10 +73,9 @@ // This store is dead. // CHECK-NEXT: store i32 [[T2]], i32* [[X]] - - // CHECK-NEXT: br label %finally.no_call_exit x--; } + return x; } From nicolasweber at gmx.de Thu Jan 27 22:07:34 2011 From: nicolasweber at gmx.de (Nico Weber) Date: Fri, 28 Jan 2011 06:07:34 -0000 Subject: [cfe-commits] r124477 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDeclCXX.cpp test/CXX/class/class.mem/p8-0x-pedantic.cpp test/CXX/class/class.mem/p8-0x.cpp Message-ID: <20110128060734.B33E32A6C12C@llvm.org> Author: nico Date: Fri Jan 28 00:07:34 2011 New Revision: 124477 URL: http://llvm.org/viewvc/llvm-project?rev=124477&view=rev Log: PR9037: Allow override, final, and new as an extension on inline members. Added: cfe/trunk/test/CXX/class/class.mem/p8-0x-pedantic.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/DeclSpec.h cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/test/CXX/class/class.mem/p8-0x.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Fri Jan 28 00:07:34 2011 @@ -394,6 +394,8 @@ // C++0x override control def ext_override_control_keyword : Extension< "'%0' keyword accepted as a C++0x extension">, InGroup; +def ext_override_inline: Extension< + "'%0' keyword only allowed in declarations, allowed as an extension">; def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Fri Jan 28 00:07:34 2011 @@ -910,7 +910,8 @@ void PopParsingClass(); Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, - const ParsedTemplateInfo &TemplateInfo); + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS); void ParseLexedMethodDeclarations(ParsingClass &Class); void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); void ParseLexedMethodDefs(ParsingClass &Class); Modified: cfe/trunk/include/clang/Sema/DeclSpec.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) +++ cfe/trunk/include/clang/Sema/DeclSpec.h Fri Jan 28 00:07:34 2011 @@ -1513,6 +1513,8 @@ bool isNewSpecified() const { return Specifiers & VS_New; } SourceLocation getNewLoc() const { return VS_newLoc; } + void clear() { Specifiers = 0; } + static const char *getSpecifierName(Specifier VS); private: Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original) +++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Fri Jan 28 00:07:34 2011 @@ -21,7 +21,8 @@ /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Current token not a '{', ':' or 'try'!"); @@ -35,11 +36,18 @@ // FIXME: Friend templates FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, move(TemplateParams)); - else // FIXME: pass template information through + else { // FIXME: pass template information through + if (VS.isOverrideSpecified()) + Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override"; + if (VS.isFinalSpecified()) + Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final"; + if (VS.isNewSpecified()) + Diag(VS.getNewLoc(), diag::ext_override_inline) << "new"; + FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VirtSpecifiers(), 0, - /*IsDefinition*/true); + VS, 0, /*IsDefinition*/true); + } HandleMemberFunctionDefaultArgs(D, FnD); Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri Jan 28 00:07:34 2011 @@ -1531,6 +1531,7 @@ } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); + VirtSpecifiers VS; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -1547,6 +1548,8 @@ return; } + ParseOptionalCXX0XVirtSpecifierSeq(VS); + // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo); @@ -1579,7 +1582,7 @@ return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo); + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS); // Consume the optional ';' if (Tok.is(tok::semi)) ConsumeToken(); @@ -1609,7 +1612,6 @@ SkipUntil(tok::comma, true, true); } - VirtSpecifiers VS; ParseOptionalCXX0XVirtSpecifierSeq(VS); // pure-specifier: @@ -1689,6 +1691,7 @@ // Parse the next declarator. DeclaratorInfo.clear(); + VS.clear(); BitfieldSize = 0; Init = 0; Deleted = false; Added: cfe/trunk/test/CXX/class/class.mem/p8-0x-pedantic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.mem/p8-0x-pedantic.cpp?rev=124477&view=auto ============================================================================== --- cfe/trunk/test/CXX/class/class.mem/p8-0x-pedantic.cpp (added) +++ cfe/trunk/test/CXX/class/class.mem/p8-0x-pedantic.cpp Fri Jan 28 00:07:34 2011 @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++0x -pedantic -verify %s + +namespace inline_extension { + struct Base1 { + virtual void f() {} + }; + + struct B : Base1 { + virtual void f() override {} // expected-warning {{'override' keyword only allowed in declarations, allowed as an extension}} + virtual void g() final {} // expected-warning {{'final' keyword only allowed in declarations, allowed as an extension}} + virtual void h() new {} // expected-warning {{'new' keyword only allowed in declarations, allowed as an extension}} + }; +} + Modified: cfe/trunk/test/CXX/class/class.mem/p8-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.mem/p8-0x.cpp?rev=124477&r1=124476&r2=124477&view=diff ============================================================================== --- cfe/trunk/test/CXX/class/class.mem/p8-0x.cpp (original) +++ cfe/trunk/test/CXX/class/class.mem/p8-0x.cpp Fri Jan 28 00:07:34 2011 @@ -11,10 +11,12 @@ }; struct Base2 { + virtual void e1(), e2(); virtual void f(); }; struct B : Base2 { + virtual void e1() override, e2(int); // No error. virtual void f() override; void g() override; // expected-error {{only virtual member functions can be marked 'override'}} int h override; // expected-error {{only virtual member functions can be marked 'override'}} @@ -25,3 +27,29 @@ void g() final; // expected-error {{only virtual member functions can be marked 'final'}} int h final; // expected-error {{only virtual member functions can be marked 'final'}} }; + +namespace inline_extension { + struct Base1 { + virtual void g() {} + }; + + struct A : Base1 { + virtual void f() new new {} // expected-error {{class member already marked 'new'}} + virtual void g() override override {} // expected-error {{class member already marked 'override'}} + virtual void h() final final {} // expected-error {{class member already marked 'final'}} + }; + + struct Base2 { + virtual void f(); + }; + + struct B : Base2 { + virtual void f() override {} + void g() override {} // expected-error {{only virtual member functions can be marked 'override'}} + }; + + struct C { + virtual void f() final {} + void g() final {} // expected-error {{only virtual member functions can be marked 'final'}} + }; +} From rjmccall at apple.com Fri Jan 28 00:37:24 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 08:37:24 -0000 Subject: [cfe-commits] r124481 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGException.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/eh.cpp Message-ID: <20110128083724.7ECC82A6C12D@llvm.org> Author: rjmccall Date: Fri Jan 28 02:37:24 2011 New Revision: 124481 URL: http://llvm.org/viewvc/llvm-project?rev=124481&view=rev Log: Convert the exception-freeing cleanup over to the conditional cleanups code, fixing a crash which probably nobody was ever going to see. In doing so, fix a horrendous number of problems with the conditional-cleanups code. Also, make conditional cleanups re-use the cleanup's activation variable, which avoids some unfortunate repetitiveness. Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CGException.cpp cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h cfe/trunk/test/CodeGenCXX/eh.cpp Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=124481&r1=124480&r2=124481&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Jan 28 02:37:24 2011 @@ -697,6 +697,7 @@ DidCallStackSave = true; // Push a cleanup block and restore the stack there. + // FIXME: in general circumstances, this should be an EH cleanup. EHStack.pushCleanup(NormalCleanup, Stack); } Modified: cfe/trunk/lib/CodeGen/CGException.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124481&r1=124480&r2=124481&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGException.cpp (original) +++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Jan 28 02:37:24 2011 @@ -172,19 +172,26 @@ BranchFixups.pop_back(); } -llvm::Value *CodeGenFunction::initFullExprCleanup() { +void CodeGenFunction::initFullExprCleanup() { // Create a variable to decide whether the cleanup needs to be run. - llvm::AllocaInst *run = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond"); + llvm::AllocaInst *active + = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond"); // Initialize it to false at a site that's guaranteed to be run // before each evaluation. llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); - new llvm::StoreInst(Builder.getFalse(), run, &block->back()); + new llvm::StoreInst(Builder.getFalse(), active, &block->back()); // Initialize it to true at the current location. - Builder.CreateStore(Builder.getTrue(), run); + Builder.CreateStore(Builder.getTrue(), active); - return run; + // Set that as the active flag in the cleanup. + EHCleanupScope &cleanup = cast(*EHStack.begin()); + assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?"); + cleanup.setActiveFlag(active); + + if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup(); + if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup(); } static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { @@ -483,26 +490,11 @@ namespace { /// A cleanup to free the exception object if its initialization /// throws. - struct FreeExceptionCleanup : EHScopeStack::Cleanup { - FreeExceptionCleanup(llvm::Value *ShouldFreeVar, - llvm::Value *ExnLocVar) - : ShouldFreeVar(ShouldFreeVar), ExnLocVar(ExnLocVar) {} - - llvm::Value *ShouldFreeVar; - llvm::Value *ExnLocVar; - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj"); - llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done"); - - llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar, - "should-free-exnobj"); - CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB); - CGF.EmitBlock(FreeBB); - llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj"); - CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal) + struct FreeException { + static void Emit(CodeGenFunction &CGF, bool forEH, + llvm::Value *exn) { + CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn) ->setDoesNotThrow(); - CGF.EmitBlock(DoneBB); } }; } @@ -511,41 +503,17 @@ // differs from EmitAnyExprToMem only in that, if a final copy-ctor // call is required, an exception within that copy ctor causes // std::terminate to be invoked. -static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, - llvm::Value *ExnLoc) { - // We want to release the allocated exception object if this - // expression throws. We do this by pushing an EH-only cleanup - // block which, furthermore, deactivates itself after the expression - // is complete. - llvm::AllocaInst *ShouldFreeVar = - CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), - "should-free-exnobj.var"); - CGF.InitTempAlloca(ShouldFreeVar, - llvm::ConstantInt::getFalse(CGF.getLLVMContext())); - - // A variable holding the exception pointer. This is necessary - // because the throw expression does not necessarily dominate the - // cleanup, for example if it appears in a conditional expression. - llvm::AllocaInst *ExnLocVar = - CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var"); - +static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e, + llvm::Value *addr) { // Make sure the exception object is cleaned up if there's an // exception during initialization. - // FIXME: stmt expressions might require this to be a normal - // cleanup, too. - CGF.EHStack.pushCleanup(EHCleanup, - ShouldFreeVar, - ExnLocVar); - EHScopeStack::stable_iterator Cleanup = CGF.EHStack.stable_begin(); - - CGF.Builder.CreateStore(ExnLoc, ExnLocVar); - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), - ShouldFreeVar); + CGF.pushFullExprCleanup(EHCleanup, addr); + EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin(); // __cxa_allocate_exception returns a void*; we need to cast this // to the appropriate type for the object. - const llvm::Type *Ty = CGF.ConvertTypeForMem(E->getType())->getPointerTo(); - llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty); + const llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo(); + llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty); // FIXME: this isn't quite right! If there's a final unelided call // to a copy constructor, then according to [except.terminate]p1 we @@ -554,22 +522,10 @@ // evaluated but before the exception is caught. But the best way // to handle that is to teach EmitAggExpr to do the final copy // differently if it can't be elided. - CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false, /*IsInit*/ true); + CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true); - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), - ShouldFreeVar); - - // Technically, the exception object is like a temporary; it has to - // be cleaned up when its full-expression is complete. - // Unfortunately, the AST represents full-expressions by creating a - // ExprWithCleanups, which it only does when there are actually - // temporaries. - // - // If any cleanups have been added since we pushed ours, they must - // be from temporaries; this will get popped at the same time. - // Otherwise we need to pop ours off. FIXME: this is very brittle. - if (Cleanup == CGF.EHStack.stable_begin()) - CGF.PopCleanupBlock(); + // Deactivate the cleanup block. + CGF.DeactivateCleanupBlock(cleanup); } llvm::Value *CodeGenFunction::getExceptionSlot() { @@ -1671,23 +1627,3 @@ EHScopeStack::Cleanup::~Cleanup() { llvm_unreachable("Cleanup is indestructable"); } - -void EHScopeStack::ConditionalCleanup::Emit(CodeGenFunction &CGF, - bool IsForEHCleanup) { - // Determine whether we should run the cleanup. - llvm::Value *condVal = CGF.Builder.CreateLoad(cond, "cond.should-run"); - - llvm::BasicBlock *cleanup = CGF.createBasicBlock("cond-cleanup.run"); - llvm::BasicBlock *cont = CGF.createBasicBlock("cond-cleanup.cont"); - - // If we shouldn't run the cleanup, jump directly to the continuation block. - CGF.Builder.CreateCondBr(condVal, cleanup, cont); - CGF.EmitBlock(cleanup); - - // Emit the core of the cleanup. - EmitImpl(CGF, IsForEHCleanup); - assert(CGF.HaveInsertPoint() && "cleanup didn't end with valid IP!"); - - // Fall into the continuation block. - CGF.EmitBlock(cont); -} Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124481&r1=124480&r2=124481&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 02:37:24 2011 @@ -1197,6 +1197,8 @@ } // Make sure that we call delete even if the dtor throws. + // This doesn't have to a conditional cleanup because we're going + // to pop it off in a second. CGF.EHStack.pushCleanup(NormalAndEHCleanup, Ptr, OperatorDelete, ElementType); @@ -1361,7 +1363,7 @@ EmitBlock(DeleteEnd); } -llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { +llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { QualType Ty = E->getType(); const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124481&r1=124480&r2=124481&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jan 28 02:37:24 2011 @@ -103,9 +103,12 @@ template >::value - && !llvm::is_base_of >::value - && !llvm::is_base_of >::value> + llvm::is_base_of::type>::value + && !llvm::is_base_of::type>::value + && !llvm::is_base_of::type>::value> struct SavedValueInCond { typedef T type; typedef T saved_type; @@ -193,24 +196,18 @@ virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0; }; - /// A helper class for cleanups that execute conditionally. - class ConditionalCleanup : public Cleanup { - /// Either an i1 which directly indicates whether the cleanup - /// should be run or an i1* from which that should be loaded. - llvm::Value *cond; - + /// UnconditionalCleanupN stores its N parameters and just passes + /// them to the real cleanup function. + template + class UnconditionalCleanup1 : public Cleanup { + A0 a0; public: - virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup); - - protected: - ConditionalCleanup(llvm::Value *cond) : cond(cond) {} - - /// Emit the non-conditional code for the cleanup. - virtual void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) = 0; + UnconditionalCleanup1(A0 a0) : a0(a0) {} + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + T::Emit(CGF, IsForEHCleanup, a0); + } }; - /// UnconditionalCleanupN stores its N parameters and just passes - /// them to the real cleanup function. template class UnconditionalCleanup2 : public Cleanup { A0 a0; A1 a1; @@ -223,22 +220,37 @@ /// ConditionalCleanupN stores the saved form of its N parameters, /// then restores them and performs the cleanup. + template + class ConditionalCleanup1 : public Cleanup { + typedef typename SavedValueInCond::saved_type A0_saved; + A0_saved a0_saved; + + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + A0 a0 = SavedValueInCond::restore(CGF, a0_saved); + T::Emit(CGF, IsForEHCleanup, a0); + } + + public: + ConditionalCleanup1(A0_saved a0) + : a0_saved(a0) {} + }; + template - class ConditionalCleanup2 : public ConditionalCleanup { + class ConditionalCleanup2 : public Cleanup { typedef typename SavedValueInCond::saved_type A0_saved; typedef typename SavedValueInCond::saved_type A1_saved; A0_saved a0_saved; A1_saved a1_saved; - void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) { + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { A0 a0 = SavedValueInCond::restore(CGF, a0_saved); A1 a1 = SavedValueInCond::restore(CGF, a1_saved); T::Emit(CGF, IsForEHCleanup, a0, a1); } public: - ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1) - : ConditionalCleanup(cond), a0_saved(a0), a1_saved(a1) {} + ConditionalCleanup2(A0_saved a0, A1_saved a1) + : a0_saved(a0), a1_saved(a1) {} }; private: @@ -602,8 +614,9 @@ llvm::BasicBlock *getInvokeDestImpl(); - /// Sets up a condition for a full-expression cleanup. - llvm::Value *initFullExprCleanup(); + /// Set up the last cleaup that was pushed as a conditional + /// full-expression cleanup. + void initFullExprCleanup(); template typename SavedValueInCond::saved_type saveValueInCond(T value) { @@ -629,23 +642,40 @@ /// pushFullExprCleanup - Push a cleanup to be run at the end of the /// current full-expression. Safe against the possibility that /// we're currently inside a conditionally-evaluated expression. + template + void pushFullExprCleanup(CleanupKind kind, A0 a0) { + // If we're not in a conditional branch, or if none of the + // arguments requires saving, then use the unconditional cleanup. + if (!isInConditionalBranch()) { + typedef EHScopeStack::UnconditionalCleanup1 CleanupType; + return EHStack.pushCleanup(kind, a0); + } + + typename SavedValueInCond::saved_type a0_saved = saveValueInCond(a0); + + typedef EHScopeStack::ConditionalCleanup1 CleanupType; + EHStack.pushCleanup(kind, a0_saved); + initFullExprCleanup(); + } + + /// pushFullExprCleanup - Push a cleanup to be run at the end of the + /// current full-expression. Safe against the possibility that + /// we're currently inside a conditionally-evaluated expression. template void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) { // If we're not in a conditional branch, or if none of the // arguments requires saving, then use the unconditional cleanup. - if (!(isInConditionalBranch() || - SavedValueInCond::needsSaving(a0) || - SavedValueInCond::needsSaving(a1))) { + if (!isInConditionalBranch()) { typedef EHScopeStack::UnconditionalCleanup2 CleanupType; return EHStack.pushCleanup(kind, a0, a1); } - llvm::Value *condVar = initFullExprCleanup(); typename SavedValueInCond::saved_type a0_saved = saveValueInCond(a0); typename SavedValueInCond::saved_type a1_saved = saveValueInCond(a1); typedef EHScopeStack::ConditionalCleanup2 CleanupType; - EHStack.pushCleanup(kind, condVar, a0_saved, a1_saved); + EHStack.pushCleanup(kind, a0_saved, a1_saved); + initFullExprCleanup(); } /// PushDestructorCleanup - Push a cleanup to call the Modified: cfe/trunk/test/CodeGenCXX/eh.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=124481&r1=124480&r2=124481&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/eh.cpp (original) +++ cfe/trunk/test/CodeGenCXX/eh.cpp Fri Jan 28 02:37:24 2011 @@ -10,16 +10,10 @@ } // CHECK: define void @_Z5test1v() -// CHECK: [[FREEVAR:%.*]] = alloca i1 -// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8* -// CHECK-NEXT: store i1 false, i1* [[FREEVAR]] -// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) -// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]] -// CHECK-NEXT: store i1 true, i1* [[FREEVAR]] +// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] // CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8* // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false) -// CHECK-NEXT: store i1 false, i1* [[FREEVAR]] // CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -36,20 +30,14 @@ } // CHECK: define void @_Z5test2v() -// CHECK: [[FREEVAR:%.*]] = alloca i1 -// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8* -// CHECK-NEXT: [[EXNSLOTVAR:%.*]] = alloca i8* +// CHECK: [[EXNSLOTVAR:%.*]] = alloca i8* // CHECK-NEXT: [[CLEANUPDESTVAR:%.*]] = alloca i32 -// CHECK-NEXT: store i1 false, i1* [[FREEVAR]] // CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16) -// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]] -// CHECK-NEXT: store i1 true, i1* [[FREEVAR]] // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] // CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2) // CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}} // : [[CONT]]: (can't check this in Release-Asserts builds) -// CHECK: store i1 false, i1* [[FREEVAR]] -// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn +// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -64,15 +52,9 @@ } // CHECK: define void @_Z5test3v() -// CHECK: [[FREEVAR:%.*]] = alloca i1 -// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8* -// CHECK-NEXT: store i1 false, i1* [[FREEVAR]] -// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) -// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]] -// CHECK-NEXT: store i1 true, i1* [[FREEVAR]] -// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSS:%[^*]*\*]]* -// CHECK-NEXT: store [[DSS]] null, [[DSS]]* [[EXN]] -// CHECK-NEXT: store i1 false, i1* [[FREEVAR]] +// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) +// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]** +// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]] // CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -121,20 +103,14 @@ namespace test7 { // CHECK: define i32 @_ZN5test73fooEv() int foo() { -// CHECK: [[FREEEXNOBJ:%.*]] = alloca i1 -// CHECK-NEXT: [[EXNALLOCVAR:%.*]] = alloca i8* -// CHECK-NEXT: [[CAUGHTEXNVAR:%.*]] = alloca i8* +// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8* // CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32 // CHECK-NEXT: [[EHCLEANUPDESTVAR:%.*]] = alloca i32 -// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]] try { try { // CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception -// CHECK-NEXT: store i8* [[EXNALLOC]], i8** [[EXNALLOCVAR]] -// CHECK-NEXT: store i1 true, i1* [[FREEEXNOBJ]] // CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32* // CHECK-NEXT: store i32 1, i32* -// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]] // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null throw 1; } @@ -414,3 +390,49 @@ // CHECK: call void @_ZN6test151AD1Ev } } + +namespace test16 { + struct A { A(); ~A(); }; + struct B { int x; B(const A &); ~B(); }; + void foo(); + bool cond(); + + // CHECK: define void @_ZN6test163barEv() + void bar() { + // CHECK: [[EXN_SAVE:%.*]] = alloca i8* + // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]], + // CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8* + // CHECK-NEXT: [[EHDEST:%.*]] = alloca i32 + // CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1 + + cond() ? throw B(A()) : foo(); + + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN6test164condEv() + // CHECK-NEXT: store i1 false, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: store i1 false, i1* [[TEMP_ACTIVE]] + // CHECK-NEXT: br i1 [[COND]], + + // CHECK: [[EXN:%.*]] = call i8* @__cxa_allocate_exception(i64 4) + // CHECK-NEXT: store i8* [[EXN]], i8** [[EXN_SAVE]] + // CHECK-NEXT: store i1 true, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[EXN]] to [[B:%.*]]* + // CHECK-NEXT: invoke void @_ZN6test161AC1Ev([[A]]* [[TEMP]]) + // CHECK: store i1 true, i1* [[TEMP_ACTIVE]] + // CHECK-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE([[B]]* [[T0]], [[A]]* [[TEMP]]) + // CHECK: store i1 false, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXN]], + + // CHECK: invoke void @_ZN6test163fooEv() + // CHECK: br label + + // CHECK: invoke void @_ZN6test161AD1Ev([[A]]* [[TEMP]]) + // CHECK: ret void + + // CHECK: [[T0:%.*]] = load i1* [[EXN_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[T1:%.*]] = load i8** [[EXN_SAVE]] + // CHECK-NEXT: call void @__cxa_free_exception(i8* [[T1]]) + // CHECK-NEXT: br label + } +} From rjmccall at apple.com Fri Jan 28 02:53:53 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 10:53:53 -0000 Subject: [cfe-commits] r124483 - in /cfe/trunk/lib/CodeGen: CGExprCXX.cpp CodeGenFunction.h Message-ID: <20110128105353.A49872A6C12C@llvm.org> Author: rjmccall Date: Fri Jan 28 04:53:53 2011 New Revision: 124483 URL: http://llvm.org/viewvc/llvm-project?rev=124483&view=rev Log: Reorganize the value-dominance metaprogram and introduce a specialization for CodeGen's RValue type. Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124483&r1=124482&r2=124483&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 04:53:53 2011 @@ -721,101 +721,65 @@ StoreAnyExprIntoOneUnit(CGF, E, NewPtr); } -namespace { -/// A utility class for saving an rvalue. -class SavedRValue { -public: - enum Kind { ScalarLiteral, ScalarAddress, - AggregateLiteral, AggregateAddress, - Complex }; - -private: - llvm::Value *Value; - Kind K; - - SavedRValue(llvm::Value *V, Kind K) : Value(V), K(K) {} - -public: - SavedRValue() {} - - static SavedRValue forScalarLiteral(llvm::Value *V) { - return SavedRValue(V, ScalarLiteral); - } - - static SavedRValue forScalarAddress(llvm::Value *Addr) { - return SavedRValue(Addr, ScalarAddress); - } - - static SavedRValue forAggregateLiteral(llvm::Value *V) { - return SavedRValue(V, AggregateLiteral); - } - - static SavedRValue forAggregateAddress(llvm::Value *Addr) { - return SavedRValue(Addr, AggregateAddress); - } - - static SavedRValue forComplexAddress(llvm::Value *Addr) { - return SavedRValue(Addr, Complex); - } - - Kind getKind() const { return K; } - llvm::Value *getValue() const { return Value; } -}; -} // end anonymous namespace +bool DominatingValue::saved_type::needsSaving(RValue rv) { + if (rv.isScalar()) + return DominatingLLVMValue::needsSaving(rv.getScalarVal()); + if (rv.isAggregate()) + return DominatingLLVMValue::needsSaving(rv.getAggregateAddr()); + return true; +} -/// Given an r-value, perform the code necessary to make sure that a -/// future RestoreRValue will be able to load the value without -/// domination concerns. -static SavedRValue SaveRValue(CodeGenFunction &CGF, RValue RV) { - if (RV.isScalar()) { - llvm::Value *V = RV.getScalarVal(); +DominatingValue::saved_type +DominatingValue::saved_type::save(CodeGenFunction &CGF, RValue rv) { + if (rv.isScalar()) { + llvm::Value *V = rv.getScalarVal(); // These automatically dominate and don't need to be saved. - if (isa(V) || isa(V)) - return SavedRValue::forScalarLiteral(V); + if (!DominatingLLVMValue::needsSaving(V)) + return saved_type(V, ScalarLiteral); // Everything else needs an alloca. - llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, Addr); - return SavedRValue::forScalarAddress(Addr); + llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); + CGF.Builder.CreateStore(V, addr); + return saved_type(addr, ScalarAddress); } - if (RV.isComplex()) { - CodeGenFunction::ComplexPairTy V = RV.getComplexVal(); + if (rv.isComplex()) { + CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); const llvm::Type *ComplexTy = llvm::StructType::get(CGF.getLLVMContext(), V.first->getType(), V.second->getType(), (void*) 0); - llvm::Value *Addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex"); - CGF.StoreComplexToAddr(V, Addr, /*volatile*/ false); - return SavedRValue::forComplexAddress(Addr); + llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex"); + CGF.StoreComplexToAddr(V, addr, /*volatile*/ false); + return saved_type(addr, ComplexAddress); } - assert(RV.isAggregate()); - llvm::Value *V = RV.getAggregateAddr(); // TODO: volatile? - if (isa(V) || isa(V)) - return SavedRValue::forAggregateLiteral(V); - - llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, Addr); - return SavedRValue::forAggregateAddress(Addr); + assert(rv.isAggregate()); + llvm::Value *V = rv.getAggregateAddr(); // TODO: volatile? + if (!DominatingLLVMValue::needsSaving(V)) + return saved_type(V, AggregateLiteral); + + llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); + CGF.Builder.CreateStore(V, addr); + return saved_type(addr, AggregateAddress); } /// Given a saved r-value produced by SaveRValue, perform the code /// necessary to restore it to usability at the current insertion /// point. -static RValue RestoreRValue(CodeGenFunction &CGF, SavedRValue RV) { - switch (RV.getKind()) { - case SavedRValue::ScalarLiteral: - return RValue::get(RV.getValue()); - case SavedRValue::ScalarAddress: - return RValue::get(CGF.Builder.CreateLoad(RV.getValue())); - case SavedRValue::AggregateLiteral: - return RValue::getAggregate(RV.getValue()); - case SavedRValue::AggregateAddress: - return RValue::getAggregate(CGF.Builder.CreateLoad(RV.getValue())); - case SavedRValue::Complex: - return RValue::getComplex(CGF.LoadComplexFromAddr(RV.getValue(), false)); +RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { + switch (K) { + case ScalarLiteral: + return RValue::get(Value); + case ScalarAddress: + return RValue::get(CGF.Builder.CreateLoad(Value)); + case AggregateLiteral: + return RValue::getAggregate(Value); + case AggregateAddress: + return RValue::getAggregate(CGF.Builder.CreateLoad(Value)); + case ComplexAddress: + return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false)); } llvm_unreachable("bad saved r-value kind"); @@ -883,26 +847,26 @@ class CallDeleteDuringConditionalNew : public EHScopeStack::Cleanup { size_t NumPlacementArgs; const FunctionDecl *OperatorDelete; - SavedRValue Ptr; - SavedRValue AllocSize; + DominatingValue::saved_type Ptr; + DominatingValue::saved_type AllocSize; - SavedRValue *getPlacementArgs() { - return reinterpret_cast(this+1); + DominatingValue::saved_type *getPlacementArgs() { + return reinterpret_cast::saved_type*>(this+1); } public: static size_t getExtraSize(size_t NumPlacementArgs) { - return NumPlacementArgs * sizeof(SavedRValue); + return NumPlacementArgs * sizeof(DominatingValue::saved_type); } CallDeleteDuringConditionalNew(size_t NumPlacementArgs, const FunctionDecl *OperatorDelete, - SavedRValue Ptr, - SavedRValue AllocSize) + DominatingValue::saved_type Ptr, + DominatingValue::saved_type AllocSize) : NumPlacementArgs(NumPlacementArgs), OperatorDelete(OperatorDelete), Ptr(Ptr), AllocSize(AllocSize) {} - void setPlacementArg(unsigned I, SavedRValue Arg) { + void setPlacementArg(unsigned I, DominatingValue::saved_type Arg) { assert(I < NumPlacementArgs && "index out of range"); getPlacementArgs()[I] = Arg; } @@ -917,17 +881,17 @@ // The first argument is always a void*. FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin(); - DeleteArgs.push_back(std::make_pair(RestoreRValue(CGF, Ptr), *AI++)); + DeleteArgs.push_back(std::make_pair(Ptr.restore(CGF), *AI++)); // A member 'operator delete' can take an extra 'size_t' argument. if (FPT->getNumArgs() == NumPlacementArgs + 2) { - RValue RV = RestoreRValue(CGF, AllocSize); + RValue RV = AllocSize.restore(CGF); DeleteArgs.push_back(std::make_pair(RV, *AI++)); } // Pass the rest of the arguments, which must match exactly. for (unsigned I = 0; I != NumPlacementArgs; ++I) { - RValue RV = RestoreRValue(CGF, getPlacementArgs()[I]); + RValue RV = getPlacementArgs()[I].restore(CGF); DeleteArgs.push_back(std::make_pair(RV, *AI++)); } @@ -961,8 +925,10 @@ } // Otherwise, we need to save all this stuff. - SavedRValue SavedNewPtr = SaveRValue(CGF, RValue::get(NewPtr)); - SavedRValue SavedAllocSize = SaveRValue(CGF, RValue::get(AllocSize)); + DominatingValue::saved_type SavedNewPtr = + DominatingValue::save(CGF, RValue::get(NewPtr)); + DominatingValue::saved_type SavedAllocSize = + DominatingValue::save(CGF, RValue::get(AllocSize)); CallDeleteDuringConditionalNew *Cleanup = CGF.EHStack .pushCleanupWithExtra(InactiveEHCleanup, @@ -971,7 +937,8 @@ SavedNewPtr, SavedAllocSize); for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) - Cleanup->setPlacementArg(I, SaveRValue(CGF, NewArgs[I+1].first)); + Cleanup->setPlacementArg(I, + DominatingValue::save(CGF, NewArgs[I+1].first)); CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin()); } Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124483&r1=124482&r2=124483&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jan 28 04:53:53 2011 @@ -97,26 +97,27 @@ llvm::BranchInst *InitialBranch; }; -/// A metaprogramming class which decides whether a type is a subclass -/// of llvm::Value that needs to be saved if it's used in a -/// conditional cleanup. -template - ::type>::value - && !llvm::is_base_of::type>::value - && !llvm::is_base_of::type>::value> -struct SavedValueInCond { +template struct InvariantValue { typedef T type; typedef T saved_type; static bool needsSaving(type value) { return false; } static saved_type save(CodeGenFunction &CGF, type value) { return value; } static type restore(CodeGenFunction &CGF, saved_type value) { return value; } }; -// Partial specialization for true arguments at end of file. + +/// A metaprogramming class for ensuring that a value will dominate an +/// arbitrary position in a function. +template struct DominatingValue : InvariantValue {}; + +template ::value && + !llvm::is_base_of::value && + !llvm::is_base_of::value> +struct DominatingPointer; +template struct DominatingPointer : InvariantValue {}; +// template struct DominatingPointer at end of file + +template struct DominatingValue : DominatingPointer {}; enum CleanupKind { EHCleanup = 0x1, @@ -222,11 +223,11 @@ /// then restores them and performs the cleanup. template class ConditionalCleanup1 : public Cleanup { - typedef typename SavedValueInCond::saved_type A0_saved; + typedef typename DominatingValue::saved_type A0_saved; A0_saved a0_saved; void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { - A0 a0 = SavedValueInCond::restore(CGF, a0_saved); + A0 a0 = DominatingValue::restore(CGF, a0_saved); T::Emit(CGF, IsForEHCleanup, a0); } @@ -237,14 +238,14 @@ template class ConditionalCleanup2 : public Cleanup { - typedef typename SavedValueInCond::saved_type A0_saved; - typedef typename SavedValueInCond::saved_type A1_saved; + typedef typename DominatingValue::saved_type A0_saved; + typedef typename DominatingValue::saved_type A1_saved; A0_saved a0_saved; A1_saved a1_saved; void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { - A0 a0 = SavedValueInCond::restore(CGF, a0_saved); - A1 a1 = SavedValueInCond::restore(CGF, a1_saved); + A0 a0 = DominatingValue::restore(CGF, a0_saved); + A1 a1 = DominatingValue::restore(CGF, a1_saved); T::Emit(CGF, IsForEHCleanup, a0, a1); } @@ -619,8 +620,8 @@ void initFullExprCleanup(); template - typename SavedValueInCond::saved_type saveValueInCond(T value) { - return SavedValueInCond::save(*this, value); + typename DominatingValue::saved_type saveValueInCond(T value) { + return DominatingValue::save(*this, value); } public: @@ -651,7 +652,7 @@ return EHStack.pushCleanup(kind, a0); } - typename SavedValueInCond::saved_type a0_saved = saveValueInCond(a0); + typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); typedef EHScopeStack::ConditionalCleanup1 CleanupType; EHStack.pushCleanup(kind, a0_saved); @@ -670,8 +671,8 @@ return EHStack.pushCleanup(kind, a0, a1); } - typename SavedValueInCond::saved_type a0_saved = saveValueInCond(a0); - typename SavedValueInCond::saved_type a1_saved = saveValueInCond(a1); + typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); + typename DominatingValue::saved_type a1_saved = saveValueInCond(a1); typedef EHScopeStack::ConditionalCleanup2 CleanupType; EHStack.pushCleanup(kind, a0_saved, a1_saved); @@ -1946,7 +1947,7 @@ /// Helper class with most of the code for saving a value for a /// conditional expression cleanup. -struct SavedValueInCondImpl { +struct DominatingLLVMValue { typedef llvm::PointerIntPair saved_type; /// Answer whether the given value needs extra work to be saved. @@ -1977,12 +1978,42 @@ } }; -/// Partial specialization of SavedValueInCond for when a value really -/// requires saving. -template struct SavedValueInCond : SavedValueInCondImpl { - typedef T type; +/// A partial specialization of DominatingValue for llvm::Values that +/// might be llvm::Instructions. +template struct DominatingPointer : DominatingLLVMValue { + typedef T *type; + static type restore(CodeGenFunction &CGF, saved_type value) { + return static_cast(DominatingLLVMValue::restore(CGF, value)); + } +}; + +/// A specialization of DominatingValue for RValue. +template <> struct DominatingValue { + typedef RValue type; + class saved_type { + enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, + AggregateAddress, ComplexAddress }; + + llvm::Value *Value; + Kind K; + saved_type(llvm::Value *v, Kind k) : Value(v), K(k) {} + + public: + static bool needsSaving(RValue value); + static saved_type save(CodeGenFunction &CGF, RValue value); + RValue restore(CodeGenFunction &CGF); + + // implementations in CGExprCXX.cpp + }; + + static bool needsSaving(type value) { + return saved_type::needsSaving(value); + } + static saved_type save(CodeGenFunction &CGF, type value) { + return saved_type::save(CGF, value); + } static type restore(CodeGenFunction &CGF, saved_type value) { - return static_cast(SavedValueInCondImpl::restore(CGF, value)); + return value.restore(CGF); } }; From rjmccall at apple.com Fri Jan 28 03:13:47 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 11:13:47 -0000 Subject: [cfe-commits] r124484 - in /cfe/trunk/lib/CodeGen: CGCleanup.cpp CGCleanup.h CGException.cpp CGException.h CGExprCXX.cpp CGObjCGNU.cpp CGObjCMac.cpp CodeGenFunction.cpp Message-ID: <20110128111347.5E95D2A6C12C@llvm.org> Author: rjmccall Date: Fri Jan 28 05:13:47 2011 New Revision: 124484 URL: http://llvm.org/viewvc/llvm-project?rev=124484&view=rev Log: Move all the cleanups framework code into a single file. Pure motion. Added: cfe/trunk/lib/CodeGen/CGCleanup.cpp cfe/trunk/lib/CodeGen/CGCleanup.h Modified: cfe/trunk/lib/CodeGen/CGException.cpp cfe/trunk/lib/CodeGen/CGException.h cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/CGObjCGNU.cpp cfe/trunk/lib/CodeGen/CGObjCMac.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Added: cfe/trunk/lib/CodeGen/CGCleanup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=124484&view=auto ============================================================================== --- cfe/trunk/lib/CodeGen/CGCleanup.cpp (added) +++ cfe/trunk/lib/CodeGen/CGCleanup.cpp Fri Jan 28 05:13:47 2011 @@ -0,0 +1,1144 @@ +//===--- CGCleanup.cpp - Bookkeeping and code emission for cleanups -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code dealing with the IR generation for cleanups +// and related information. +// +// A "cleanup" is a piece of code which needs to be executed whenever +// control transfers out of a particular scope. This can be +// conditionalized to occur only on exceptional control flow, only on +// normal control flow, or both. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CGCleanup.h" + +using namespace clang; +using namespace CodeGen; + +bool DominatingValue::saved_type::needsSaving(RValue rv) { + if (rv.isScalar()) + return DominatingLLVMValue::needsSaving(rv.getScalarVal()); + if (rv.isAggregate()) + return DominatingLLVMValue::needsSaving(rv.getAggregateAddr()); + return true; +} + +DominatingValue::saved_type +DominatingValue::saved_type::save(CodeGenFunction &CGF, RValue rv) { + if (rv.isScalar()) { + llvm::Value *V = rv.getScalarVal(); + + // These automatically dominate and don't need to be saved. + if (!DominatingLLVMValue::needsSaving(V)) + return saved_type(V, ScalarLiteral); + + // Everything else needs an alloca. + llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); + CGF.Builder.CreateStore(V, addr); + return saved_type(addr, ScalarAddress); + } + + if (rv.isComplex()) { + CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); + const llvm::Type *ComplexTy = + llvm::StructType::get(CGF.getLLVMContext(), + V.first->getType(), V.second->getType(), + (void*) 0); + llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex"); + CGF.StoreComplexToAddr(V, addr, /*volatile*/ false); + return saved_type(addr, ComplexAddress); + } + + assert(rv.isAggregate()); + llvm::Value *V = rv.getAggregateAddr(); // TODO: volatile? + if (!DominatingLLVMValue::needsSaving(V)) + return saved_type(V, AggregateLiteral); + + llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); + CGF.Builder.CreateStore(V, addr); + return saved_type(addr, AggregateAddress); +} + +/// Given a saved r-value produced by SaveRValue, perform the code +/// necessary to restore it to usability at the current insertion +/// point. +RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { + switch (K) { + case ScalarLiteral: + return RValue::get(Value); + case ScalarAddress: + return RValue::get(CGF.Builder.CreateLoad(Value)); + case AggregateLiteral: + return RValue::getAggregate(Value); + case AggregateAddress: + return RValue::getAggregate(CGF.Builder.CreateLoad(Value)); + case ComplexAddress: + return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false)); + } + + llvm_unreachable("bad saved r-value kind"); + return RValue(); +} + +/// Push an entry of the given size onto this protected-scope stack. +char *EHScopeStack::allocate(size_t Size) { + if (!StartOfBuffer) { + unsigned Capacity = 1024; + while (Capacity < Size) Capacity *= 2; + StartOfBuffer = new char[Capacity]; + StartOfData = EndOfBuffer = StartOfBuffer + Capacity; + } else if (static_cast(StartOfData - StartOfBuffer) < Size) { + unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer; + unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer); + + unsigned NewCapacity = CurrentCapacity; + do { + NewCapacity *= 2; + } while (NewCapacity < UsedCapacity + Size); + + char *NewStartOfBuffer = new char[NewCapacity]; + char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity; + char *NewStartOfData = NewEndOfBuffer - UsedCapacity; + memcpy(NewStartOfData, StartOfData, UsedCapacity); + delete [] StartOfBuffer; + StartOfBuffer = NewStartOfBuffer; + EndOfBuffer = NewEndOfBuffer; + StartOfData = NewStartOfData; + } + + assert(StartOfBuffer + Size <= StartOfData); + StartOfData -= Size; + return StartOfData; +} + +EHScopeStack::stable_iterator +EHScopeStack::getEnclosingEHCleanup(iterator it) const { + assert(it != end()); + do { + if (isa(*it)) { + if (cast(*it).isEHCleanup()) + return stabilize(it); + return cast(*it).getEnclosingEHCleanup(); + } + ++it; + } while (it != end()); + return stable_end(); +} + + +void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { + assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); + char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); + bool IsNormalCleanup = Kind & NormalCleanup; + bool IsEHCleanup = Kind & EHCleanup; + bool IsActive = !(Kind & InactiveCleanup); + EHCleanupScope *Scope = + new (Buffer) EHCleanupScope(IsNormalCleanup, + IsEHCleanup, + IsActive, + Size, + BranchFixups.size(), + InnermostNormalCleanup, + InnermostEHCleanup); + if (IsNormalCleanup) + InnermostNormalCleanup = stable_begin(); + if (IsEHCleanup) + InnermostEHCleanup = stable_begin(); + + return Scope->getCleanupBuffer(); +} + +void EHScopeStack::popCleanup() { + assert(!empty() && "popping exception stack when not empty"); + + assert(isa(*begin())); + EHCleanupScope &Cleanup = cast(*begin()); + InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); + InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); + StartOfData += Cleanup.getAllocatedSize(); + + if (empty()) NextEHDestIndex = FirstEHDestIndex; + + // Destroy the cleanup. + Cleanup.~EHCleanupScope(); + + // Check whether we can shrink the branch-fixups stack. + if (!BranchFixups.empty()) { + // If we no longer have any normal cleanups, all the fixups are + // complete. + if (!hasNormalCleanups()) + BranchFixups.clear(); + + // Otherwise we can still trim out unnecessary nulls. + else + popNullFixups(); + } +} + +EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) { + char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters)); + CatchDepth++; + return new (Buffer) EHFilterScope(NumFilters); +} + +void EHScopeStack::popFilter() { + assert(!empty() && "popping exception stack when not empty"); + + EHFilterScope &Filter = cast(*begin()); + StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters()); + + if (empty()) NextEHDestIndex = FirstEHDestIndex; + + assert(CatchDepth > 0 && "mismatched filter push/pop"); + CatchDepth--; +} + +EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) { + char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers)); + CatchDepth++; + EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers); + for (unsigned I = 0; I != NumHandlers; ++I) + Scope->getHandlers()[I].Index = getNextEHDestIndex(); + return Scope; +} + +void EHScopeStack::pushTerminate() { + char *Buffer = allocate(EHTerminateScope::getSize()); + CatchDepth++; + new (Buffer) EHTerminateScope(getNextEHDestIndex()); +} + +/// Remove any 'null' fixups on the stack. However, we can't pop more +/// fixups than the fixup depth on the innermost normal cleanup, or +/// else fixups that we try to add to that cleanup will end up in the +/// wrong place. We *could* try to shrink fixup depths, but that's +/// actually a lot of work for little benefit. +void EHScopeStack::popNullFixups() { + // We expect this to only be called when there's still an innermost + // normal cleanup; otherwise there really shouldn't be any fixups. + assert(hasNormalCleanups()); + + EHScopeStack::iterator it = find(InnermostNormalCleanup); + unsigned MinSize = cast(*it).getFixupDepth(); + assert(BranchFixups.size() >= MinSize && "fixup stack out of order"); + + while (BranchFixups.size() > MinSize && + BranchFixups.back().Destination == 0) + BranchFixups.pop_back(); +} + +void CodeGenFunction::initFullExprCleanup() { + // Create a variable to decide whether the cleanup needs to be run. + llvm::AllocaInst *active + = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond"); + + // Initialize it to false at a site that's guaranteed to be run + // before each evaluation. + llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); + new llvm::StoreInst(Builder.getFalse(), active, &block->back()); + + // Initialize it to true at the current location. + Builder.CreateStore(Builder.getTrue(), active); + + // Set that as the active flag in the cleanup. + EHCleanupScope &cleanup = cast(*EHStack.begin()); + assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?"); + cleanup.setActiveFlag(active); + + if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup(); + if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup(); +} + +EHScopeStack::Cleanup::~Cleanup() { + llvm_unreachable("Cleanup is indestructable"); +} + +/// All the branch fixups on the EH stack have propagated out past the +/// outermost normal cleanup; resolve them all by adding cases to the +/// given switch instruction. +static void ResolveAllBranchFixups(CodeGenFunction &CGF, + llvm::SwitchInst *Switch, + llvm::BasicBlock *CleanupEntry) { + llvm::SmallPtrSet CasesAdded; + + for (unsigned I = 0, E = CGF.EHStack.getNumBranchFixups(); I != E; ++I) { + // Skip this fixup if its destination isn't set. + BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I); + if (Fixup.Destination == 0) continue; + + // If there isn't an OptimisticBranchBlock, then InitialBranch is + // still pointing directly to its destination; forward it to the + // appropriate cleanup entry. This is required in the specific + // case of + // { std::string s; goto lbl; } + // lbl: + // i.e. where there's an unresolved fixup inside a single cleanup + // entry which we're currently popping. + if (Fixup.OptimisticBranchBlock == 0) { + new llvm::StoreInst(CGF.Builder.getInt32(Fixup.DestinationIndex), + CGF.getNormalCleanupDestSlot(), + Fixup.InitialBranch); + Fixup.InitialBranch->setSuccessor(0, CleanupEntry); + } + + // Don't add this case to the switch statement twice. + if (!CasesAdded.insert(Fixup.Destination)) continue; + + Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex), + Fixup.Destination); + } + + CGF.EHStack.clearFixups(); +} + +/// Transitions the terminator of the given exit-block of a cleanup to +/// be a cleanup switch. +static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF, + llvm::BasicBlock *Block) { + // If it's a branch, turn it into a switch whose default + // destination is its original target. + llvm::TerminatorInst *Term = Block->getTerminator(); + assert(Term && "can't transition block without terminator"); + + if (llvm::BranchInst *Br = dyn_cast(Term)) { + assert(Br->isUnconditional()); + llvm::LoadInst *Load = + new llvm::LoadInst(CGF.getNormalCleanupDestSlot(), "cleanup.dest", Term); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block); + Br->eraseFromParent(); + return Switch; + } else { + return cast(Term); + } +} + +void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { + assert(Block && "resolving a null target block"); + if (!EHStack.getNumBranchFixups()) return; + + assert(EHStack.hasNormalCleanups() && + "branch fixups exist with no normal cleanups on stack"); + + llvm::SmallPtrSet ModifiedOptimisticBlocks; + bool ResolvedAny = false; + + for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) { + // Skip this fixup if its destination doesn't match. + BranchFixup &Fixup = EHStack.getBranchFixup(I); + if (Fixup.Destination != Block) continue; + + Fixup.Destination = 0; + ResolvedAny = true; + + // If it doesn't have an optimistic branch block, LatestBranch is + // already pointing to the right place. + llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock; + if (!BranchBB) + continue; + + // Don't process the same optimistic branch block twice. + if (!ModifiedOptimisticBlocks.insert(BranchBB)) + continue; + + llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB); + + // Add a case to the switch. + Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), Block); + } + + if (ResolvedAny) + EHStack.popNullFixups(); +} + +/// Pops cleanup blocks until the given savepoint is reached. +void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { + assert(Old.isValid()); + + while (EHStack.stable_begin() != Old) { + EHCleanupScope &Scope = cast(*EHStack.begin()); + + // As long as Old strictly encloses the scope's enclosing normal + // cleanup, we're going to emit another normal cleanup which + // fallthrough can propagate through. + bool FallThroughIsBranchThrough = + Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); + + PopCleanupBlock(FallThroughIsBranchThrough); + } +} + +static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, + EHCleanupScope &Scope) { + assert(Scope.isNormalCleanup()); + llvm::BasicBlock *Entry = Scope.getNormalBlock(); + if (!Entry) { + Entry = CGF.createBasicBlock("cleanup"); + Scope.setNormalBlock(Entry); + } + return Entry; +} + +static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF, + EHCleanupScope &Scope) { + assert(Scope.isEHCleanup()); + llvm::BasicBlock *Entry = Scope.getEHBlock(); + if (!Entry) { + Entry = CGF.createBasicBlock("eh.cleanup"); + Scope.setEHBlock(Entry); + } + return Entry; +} + +/// Attempts to reduce a cleanup's entry block to a fallthrough. This +/// is basically llvm::MergeBlockIntoPredecessor, except +/// simplified/optimized for the tighter constraints on cleanup blocks. +/// +/// Returns the new block, whatever it is. +static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF, + llvm::BasicBlock *Entry) { + llvm::BasicBlock *Pred = Entry->getSinglePredecessor(); + if (!Pred) return Entry; + + llvm::BranchInst *Br = dyn_cast(Pred->getTerminator()); + if (!Br || Br->isConditional()) return Entry; + assert(Br->getSuccessor(0) == Entry); + + // If we were previously inserting at the end of the cleanup entry + // block, we'll need to continue inserting at the end of the + // predecessor. + bool WasInsertBlock = CGF.Builder.GetInsertBlock() == Entry; + assert(!WasInsertBlock || CGF.Builder.GetInsertPoint() == Entry->end()); + + // Kill the branch. + Br->eraseFromParent(); + + // Merge the blocks. + Pred->getInstList().splice(Pred->end(), Entry->getInstList()); + + // Replace all uses of the entry with the predecessor, in case there + // are phis in the cleanup. + Entry->replaceAllUsesWith(Pred); + + // Kill the entry block. + Entry->eraseFromParent(); + + if (WasInsertBlock) + CGF.Builder.SetInsertPoint(Pred); + + return Pred; +} + +static void EmitCleanup(CodeGenFunction &CGF, + EHScopeStack::Cleanup *Fn, + bool ForEH, + llvm::Value *ActiveFlag) { + // EH cleanups always occur within a terminate scope. + if (ForEH) CGF.EHStack.pushTerminate(); + + // If there's an active flag, load it and skip the cleanup if it's + // false. + llvm::BasicBlock *ContBB = 0; + if (ActiveFlag) { + ContBB = CGF.createBasicBlock("cleanup.done"); + llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action"); + llvm::Value *IsActive + = CGF.Builder.CreateLoad(ActiveFlag, "cleanup.is_active"); + CGF.Builder.CreateCondBr(IsActive, CleanupBB, ContBB); + CGF.EmitBlock(CleanupBB); + } + + // Ask the cleanup to emit itself. + Fn->Emit(CGF, ForEH); + assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?"); + + // Emit the continuation block if there was an active flag. + if (ActiveFlag) + CGF.EmitBlock(ContBB); + + // Leave the terminate scope. + if (ForEH) CGF.EHStack.popTerminate(); +} + +static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit, + llvm::BasicBlock *From, + llvm::BasicBlock *To) { + // Exit is the exit block of a cleanup, so it always terminates in + // an unconditional branch or a switch. + llvm::TerminatorInst *Term = Exit->getTerminator(); + + if (llvm::BranchInst *Br = dyn_cast(Term)) { + assert(Br->isUnconditional() && Br->getSuccessor(0) == From); + Br->setSuccessor(0, To); + } else { + llvm::SwitchInst *Switch = cast(Term); + for (unsigned I = 0, E = Switch->getNumSuccessors(); I != E; ++I) + if (Switch->getSuccessor(I) == From) + Switch->setSuccessor(I, To); + } +} + +/// Pops a cleanup block. If the block includes a normal cleanup, the +/// current insertion point is threaded through the cleanup, as are +/// any branch fixups on the cleanup. +void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { + assert(!EHStack.empty() && "cleanup stack is empty!"); + assert(isa(*EHStack.begin()) && "top not a cleanup!"); + EHCleanupScope &Scope = cast(*EHStack.begin()); + assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); + + // Remember activation information. + bool IsActive = Scope.isActive(); + llvm::Value *NormalActiveFlag = + Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : 0; + llvm::Value *EHActiveFlag = + Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : 0; + + // Check whether we need an EH cleanup. This is only true if we've + // generated a lazy EH cleanup block. + bool RequiresEHCleanup = Scope.hasEHBranches(); + + // Check the three conditions which might require a normal cleanup: + + // - whether there are branch fix-ups through this cleanup + unsigned FixupDepth = Scope.getFixupDepth(); + bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth; + + // - whether there are branch-throughs or branch-afters + bool HasExistingBranches = Scope.hasBranches(); + + // - whether there's a fallthrough + llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); + bool HasFallthrough = (FallthroughSource != 0 && IsActive); + + // Branch-through fall-throughs leave the insertion point set to the + // end of the last cleanup, which points to the current scope. The + // rest of IR gen doesn't need to worry about this; it only happens + // during the execution of PopCleanupBlocks(). + bool HasPrebranchedFallthrough = + (FallthroughSource && FallthroughSource->getTerminator()); + + // If this is a normal cleanup, then having a prebranched + // fallthrough implies that the fallthrough source unconditionally + // jumps here. + assert(!Scope.isNormalCleanup() || !HasPrebranchedFallthrough || + (Scope.getNormalBlock() && + FallthroughSource->getTerminator()->getSuccessor(0) + == Scope.getNormalBlock())); + + bool RequiresNormalCleanup = false; + if (Scope.isNormalCleanup() && + (HasFixups || HasExistingBranches || HasFallthrough)) { + RequiresNormalCleanup = true; + } + + // Even if we don't need the normal cleanup, we might still have + // prebranched fallthrough to worry about. + if (Scope.isNormalCleanup() && !RequiresNormalCleanup && + HasPrebranchedFallthrough) { + assert(!IsActive); + + llvm::BasicBlock *NormalEntry = Scope.getNormalBlock(); + + // If we're branching through this cleanup, just forward the + // prebranched fallthrough to the next cleanup, leaving the insert + // point in the old block. + if (FallthroughIsBranchThrough) { + EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); + llvm::BasicBlock *EnclosingEntry = + CreateNormalEntry(*this, cast(S)); + + ForwardPrebranchedFallthrough(FallthroughSource, + NormalEntry, EnclosingEntry); + assert(NormalEntry->use_empty() && + "uses of entry remain after forwarding?"); + delete NormalEntry; + + // Otherwise, we're branching out; just emit the next block. + } else { + EmitBlock(NormalEntry); + SimplifyCleanupEntry(*this, NormalEntry); + } + } + + // If we don't need the cleanup at all, we're done. + if (!RequiresNormalCleanup && !RequiresEHCleanup) { + EHStack.popCleanup(); // safe because there are no fixups + assert(EHStack.getNumBranchFixups() == 0 || + EHStack.hasNormalCleanups()); + return; + } + + // Copy the cleanup emission data out. Note that SmallVector + // guarantees maximal alignment for its buffer regardless of its + // type parameter. + llvm::SmallVector CleanupBuffer; + CleanupBuffer.reserve(Scope.getCleanupSize()); + memcpy(CleanupBuffer.data(), + Scope.getCleanupBuffer(), Scope.getCleanupSize()); + CleanupBuffer.set_size(Scope.getCleanupSize()); + EHScopeStack::Cleanup *Fn = + reinterpret_cast(CleanupBuffer.data()); + + // We want to emit the EH cleanup after the normal cleanup, but go + // ahead and do the setup for the EH cleanup while the scope is still + // alive. + llvm::BasicBlock *EHEntry = 0; + llvm::SmallVector EHInstsToAppend; + if (RequiresEHCleanup) { + EHEntry = CreateEHEntry(*this, Scope); + + // Figure out the branch-through dest if necessary. + llvm::BasicBlock *EHBranchThroughDest = 0; + if (Scope.hasEHBranchThroughs()) { + assert(Scope.getEnclosingEHCleanup() != EHStack.stable_end()); + EHScope &S = *EHStack.find(Scope.getEnclosingEHCleanup()); + EHBranchThroughDest = CreateEHEntry(*this, cast(S)); + } + + // If we have exactly one branch-after and no branch-throughs, we + // can dispatch it without a switch. + if (!Scope.hasEHBranchThroughs() && + Scope.getNumEHBranchAfters() == 1) { + assert(!EHBranchThroughDest); + + // TODO: remove the spurious eh.cleanup.dest stores if this edge + // never went through any switches. + llvm::BasicBlock *BranchAfterDest = Scope.getEHBranchAfterBlock(0); + EHInstsToAppend.push_back(llvm::BranchInst::Create(BranchAfterDest)); + + // Otherwise, if we have any branch-afters, we need a switch. + } else if (Scope.getNumEHBranchAfters()) { + // The default of the switch belongs to the branch-throughs if + // they exist. + llvm::BasicBlock *Default = + (EHBranchThroughDest ? EHBranchThroughDest : getUnreachableBlock()); + + const unsigned SwitchCapacity = Scope.getNumEHBranchAfters(); + + llvm::LoadInst *Load = + new llvm::LoadInst(getEHCleanupDestSlot(), "cleanup.dest"); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Default, SwitchCapacity); + + EHInstsToAppend.push_back(Load); + EHInstsToAppend.push_back(Switch); + + for (unsigned I = 0, E = Scope.getNumEHBranchAfters(); I != E; ++I) + Switch->addCase(Scope.getEHBranchAfterIndex(I), + Scope.getEHBranchAfterBlock(I)); + + // Otherwise, we have only branch-throughs; jump to the next EH + // cleanup. + } else { + assert(EHBranchThroughDest); + EHInstsToAppend.push_back(llvm::BranchInst::Create(EHBranchThroughDest)); + } + } + + if (!RequiresNormalCleanup) { + EHStack.popCleanup(); + } else { + // If we have a fallthrough and no other need for the cleanup, + // emit it directly. + if (HasFallthrough && !HasPrebranchedFallthrough && + !HasFixups && !HasExistingBranches) { + + // Fixups can cause us to optimistically create a normal block, + // only to later have no real uses for it. Just delete it in + // this case. + // TODO: we can potentially simplify all the uses after this. + if (Scope.getNormalBlock()) { + Scope.getNormalBlock()->replaceAllUsesWith(getUnreachableBlock()); + delete Scope.getNormalBlock(); + } + + EHStack.popCleanup(); + + EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag); + + // Otherwise, the best approach is to thread everything through + // the cleanup block and then try to clean up after ourselves. + } else { + // Force the entry block to exist. + llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope); + + // I. Set up the fallthrough edge in. + + // If there's a fallthrough, we need to store the cleanup + // destination index. For fall-throughs this is always zero. + if (HasFallthrough) { + if (!HasPrebranchedFallthrough) + Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot()); + + // Otherwise, clear the IP if we don't have fallthrough because + // the cleanup is inactive. We don't need to save it because + // it's still just FallthroughSource. + } else if (FallthroughSource) { + assert(!IsActive && "source without fallthrough for active cleanup"); + Builder.ClearInsertionPoint(); + } + + // II. Emit the entry block. This implicitly branches to it if + // we have fallthrough. All the fixups and existing branches + // should already be branched to it. + EmitBlock(NormalEntry); + + // III. Figure out where we're going and build the cleanup + // epilogue. + + bool HasEnclosingCleanups = + (Scope.getEnclosingNormalCleanup() != EHStack.stable_end()); + + // Compute the branch-through dest if we need it: + // - if there are branch-throughs threaded through the scope + // - if fall-through is a branch-through + // - if there are fixups that will be optimistically forwarded + // to the enclosing cleanup + llvm::BasicBlock *BranchThroughDest = 0; + if (Scope.hasBranchThroughs() || + (FallthroughSource && FallthroughIsBranchThrough) || + (HasFixups && HasEnclosingCleanups)) { + assert(HasEnclosingCleanups); + EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); + BranchThroughDest = CreateNormalEntry(*this, cast(S)); + } + + llvm::BasicBlock *FallthroughDest = 0; + llvm::SmallVector InstsToAppend; + + // If there's exactly one branch-after and no other threads, + // we can route it without a switch. + if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough && + Scope.getNumBranchAfters() == 1) { + assert(!BranchThroughDest || !IsActive); + + // TODO: clean up the possibly dead stores to the cleanup dest slot. + llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); + InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter)); + + // Build a switch-out if we need it: + // - if there are branch-afters threaded through the scope + // - if fall-through is a branch-after + // - if there are fixups that have nowhere left to go and + // so must be immediately resolved + } else if (Scope.getNumBranchAfters() || + (HasFallthrough && !FallthroughIsBranchThrough) || + (HasFixups && !HasEnclosingCleanups)) { + + llvm::BasicBlock *Default = + (BranchThroughDest ? BranchThroughDest : getUnreachableBlock()); + + // TODO: base this on the number of branch-afters and fixups + const unsigned SwitchCapacity = 10; + + llvm::LoadInst *Load = + new llvm::LoadInst(getNormalCleanupDestSlot(), "cleanup.dest"); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Default, SwitchCapacity); + + InstsToAppend.push_back(Load); + InstsToAppend.push_back(Switch); + + // Branch-after fallthrough. + if (FallthroughSource && !FallthroughIsBranchThrough) { + FallthroughDest = createBasicBlock("cleanup.cont"); + if (HasFallthrough) + Switch->addCase(Builder.getInt32(0), FallthroughDest); + } + + for (unsigned I = 0, E = Scope.getNumBranchAfters(); I != E; ++I) { + Switch->addCase(Scope.getBranchAfterIndex(I), + Scope.getBranchAfterBlock(I)); + } + + // If there aren't any enclosing cleanups, we can resolve all + // the fixups now. + if (HasFixups && !HasEnclosingCleanups) + ResolveAllBranchFixups(*this, Switch, NormalEntry); + } else { + // We should always have a branch-through destination in this case. + assert(BranchThroughDest); + InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest)); + } + + // IV. Pop the cleanup and emit it. + EHStack.popCleanup(); + assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); + + EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag); + + // Append the prepared cleanup prologue from above. + llvm::BasicBlock *NormalExit = Builder.GetInsertBlock(); + for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I) + NormalExit->getInstList().push_back(InstsToAppend[I]); + + // Optimistically hope that any fixups will continue falling through. + for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); + I < E; ++I) { + BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I); + if (!Fixup.Destination) continue; + if (!Fixup.OptimisticBranchBlock) { + new llvm::StoreInst(Builder.getInt32(Fixup.DestinationIndex), + getNormalCleanupDestSlot(), + Fixup.InitialBranch); + Fixup.InitialBranch->setSuccessor(0, NormalEntry); + } + Fixup.OptimisticBranchBlock = NormalExit; + } + + // V. Set up the fallthrough edge out. + + // Case 1: a fallthrough source exists but shouldn't branch to + // the cleanup because the cleanup is inactive. + if (!HasFallthrough && FallthroughSource) { + assert(!IsActive); + + // If we have a prebranched fallthrough, that needs to be + // forwarded to the right block. + if (HasPrebranchedFallthrough) { + llvm::BasicBlock *Next; + if (FallthroughIsBranchThrough) { + Next = BranchThroughDest; + assert(!FallthroughDest); + } else { + Next = FallthroughDest; + } + + ForwardPrebranchedFallthrough(FallthroughSource, NormalEntry, Next); + } + Builder.SetInsertPoint(FallthroughSource); + + // Case 2: a fallthrough source exists and should branch to the + // cleanup, but we're not supposed to branch through to the next + // cleanup. + } else if (HasFallthrough && FallthroughDest) { + assert(!FallthroughIsBranchThrough); + EmitBlock(FallthroughDest); + + // Case 3: a fallthrough source exists and should branch to the + // cleanup and then through to the next. + } else if (HasFallthrough) { + // Everything is already set up for this. + + // Case 4: no fallthrough source exists. + } else { + Builder.ClearInsertionPoint(); + } + + // VI. Assorted cleaning. + + // Check whether we can merge NormalEntry into a single predecessor. + // This might invalidate (non-IR) pointers to NormalEntry. + llvm::BasicBlock *NewNormalEntry = + SimplifyCleanupEntry(*this, NormalEntry); + + // If it did invalidate those pointers, and NormalEntry was the same + // as NormalExit, go back and patch up the fixups. + if (NewNormalEntry != NormalEntry && NormalEntry == NormalExit) + for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); + I < E; ++I) + CGF.EHStack.getBranchFixup(I).OptimisticBranchBlock = NewNormalEntry; + } + } + + assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0); + + // Emit the EH cleanup if required. + if (RequiresEHCleanup) { + CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); + + EmitBlock(EHEntry); + EmitCleanup(*this, Fn, /*ForEH*/ true, EHActiveFlag); + + // Append the prepared cleanup prologue from above. + llvm::BasicBlock *EHExit = Builder.GetInsertBlock(); + for (unsigned I = 0, E = EHInstsToAppend.size(); I != E; ++I) + EHExit->getInstList().push_back(EHInstsToAppend[I]); + + Builder.restoreIP(SavedIP); + + SimplifyCleanupEntry(*this, EHEntry); + } +} + +/// Terminate the current block by emitting a branch which might leave +/// the current cleanup-protected scope. The target scope may not yet +/// be known, in which case this will require a fixup. +/// +/// As a side-effect, this method clears the insertion point. +void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { + assert(Dest.getScopeDepth().encloses(EHStack.getInnermostNormalCleanup()) + && "stale jump destination"); + + if (!HaveInsertPoint()) + return; + + // Create the branch. + llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); + + // Calculate the innermost active normal cleanup. + EHScopeStack::stable_iterator + TopCleanup = EHStack.getInnermostActiveNormalCleanup(); + + // If we're not in an active normal cleanup scope, or if the + // destination scope is within the innermost active normal cleanup + // scope, we don't need to worry about fixups. + if (TopCleanup == EHStack.stable_end() || + TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid + Builder.ClearInsertionPoint(); + return; + } + + // If we can't resolve the destination cleanup scope, just add this + // to the current cleanup scope as a branch fixup. + if (!Dest.getScopeDepth().isValid()) { + BranchFixup &Fixup = EHStack.addBranchFixup(); + Fixup.Destination = Dest.getBlock(); + Fixup.DestinationIndex = Dest.getDestIndex(); + Fixup.InitialBranch = BI; + Fixup.OptimisticBranchBlock = 0; + + Builder.ClearInsertionPoint(); + return; + } + + // Otherwise, thread through all the normal cleanups in scope. + + // Store the index at the start. + llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); + new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI); + + // Adjust BI to point to the first cleanup block. + { + EHCleanupScope &Scope = + cast(*EHStack.find(TopCleanup)); + BI->setSuccessor(0, CreateNormalEntry(*this, Scope)); + } + + // Add this destination to all the scopes involved. + EHScopeStack::stable_iterator I = TopCleanup; + EHScopeStack::stable_iterator E = Dest.getScopeDepth(); + if (E.strictlyEncloses(I)) { + while (true) { + EHCleanupScope &Scope = cast(*EHStack.find(I)); + assert(Scope.isNormalCleanup()); + I = Scope.getEnclosingNormalCleanup(); + + // If this is the last cleanup we're propagating through, tell it + // that there's a resolved jump moving through it. + if (!E.strictlyEncloses(I)) { + Scope.addBranchAfter(Index, Dest.getBlock()); + break; + } + + // Otherwise, tell the scope that there's a jump propoagating + // through it. If this isn't new information, all the rest of + // the work has been done before. + if (!Scope.addBranchThrough(Dest.getBlock())) + break; + } + } + + Builder.ClearInsertionPoint(); +} + +void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) { + // We should never get invalid scope depths for an UnwindDest; that + // implies that the destination wasn't set up correctly. + assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?"); + + if (!HaveInsertPoint()) + return; + + // Create the branch. + llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); + + // Calculate the innermost active cleanup. + EHScopeStack::stable_iterator + InnermostCleanup = EHStack.getInnermostActiveEHCleanup(); + + // If the destination is in the same EH cleanup scope as us, we + // don't need to thread through anything. + if (InnermostCleanup.encloses(Dest.getScopeDepth())) { + Builder.ClearInsertionPoint(); + return; + } + assert(InnermostCleanup != EHStack.stable_end()); + + // Store the index at the start. + llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); + new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI); + + // Adjust BI to point to the first cleanup block. + { + EHCleanupScope &Scope = + cast(*EHStack.find(InnermostCleanup)); + BI->setSuccessor(0, CreateEHEntry(*this, Scope)); + } + + // Add this destination to all the scopes involved. + for (EHScopeStack::stable_iterator + I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) { + assert(E.strictlyEncloses(I)); + EHCleanupScope &Scope = cast(*EHStack.find(I)); + assert(Scope.isEHCleanup()); + I = Scope.getEnclosingEHCleanup(); + + // If this is the last cleanup we're propagating through, add this + // as a branch-after. + if (I == E) { + Scope.addEHBranchAfter(Index, Dest.getBlock()); + break; + } + + // Otherwise, add it as a branch-through. If this isn't new + // information, all the rest of the work has been done before. + if (!Scope.addEHBranchThrough(Dest.getBlock())) + break; + } + + Builder.ClearInsertionPoint(); +} + +static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, + EHScopeStack::stable_iterator C) { + // If we needed a normal block for any reason, that counts. + if (cast(*EHStack.find(C)).getNormalBlock()) + return true; + + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostNormalCleanup(); + I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast(*EHStack.find(I)); + if (S.getNormalBlock()) return true; + I = S.getEnclosingNormalCleanup(); + } + + return false; +} + +static bool IsUsedAsEHCleanup(EHScopeStack &EHStack, + EHScopeStack::stable_iterator C) { + // If we needed an EH block for any reason, that counts. + if (cast(*EHStack.find(C)).getEHBlock()) + return true; + + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostEHCleanup(); I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast(*EHStack.find(I)); + if (S.getEHBlock()) return true; + I = S.getEnclosingEHCleanup(); + } + + return false; +} + +enum ForActivation_t { + ForActivation, + ForDeactivation +}; + +/// The given cleanup block is changing activation state. Configure a +/// cleanup variable if necessary. +/// +/// It would be good if we had some way of determining if there were +/// extra uses *after* the change-over point. +static void SetupCleanupBlockActivation(CodeGenFunction &CGF, + EHScopeStack::stable_iterator C, + ForActivation_t Kind) { + EHCleanupScope &Scope = cast(*CGF.EHStack.find(C)); + + // We always need the flag if we're activating the cleanup, because + // we have to assume that the current location doesn't necessarily + // dominate all future uses of the cleanup. + bool NeedFlag = (Kind == ForActivation); + + // Calculate whether the cleanup was used: + + // - as a normal cleanup + if (Scope.isNormalCleanup() && IsUsedAsNormalCleanup(CGF.EHStack, C)) { + Scope.setTestFlagInNormalCleanup(); + NeedFlag = true; + } + + // - as an EH cleanup + if (Scope.isEHCleanup() && IsUsedAsEHCleanup(CGF.EHStack, C)) { + Scope.setTestFlagInEHCleanup(); + NeedFlag = true; + } + + // If it hasn't yet been used as either, we're done. + if (!NeedFlag) return; + + llvm::AllocaInst *Var = Scope.getActiveFlag(); + if (!Var) { + Var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive"); + Scope.setActiveFlag(Var); + + // Initialize to true or false depending on whether it was + // active up to this point. + CGF.InitTempAlloca(Var, CGF.Builder.getInt1(Kind == ForDeactivation)); + } + + CGF.Builder.CreateStore(CGF.Builder.getInt1(Kind == ForActivation), Var); +} + +/// Activate a cleanup that was created in an inactivated state. +void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C) { + assert(C != EHStack.stable_end() && "activating bottom of stack?"); + EHCleanupScope &Scope = cast(*EHStack.find(C)); + assert(!Scope.isActive() && "double activation"); + + SetupCleanupBlockActivation(*this, C, ForActivation); + + Scope.setActive(true); +} + +/// Deactive a cleanup that was created in an active state. +void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C) { + assert(C != EHStack.stable_end() && "deactivating bottom of stack?"); + EHCleanupScope &Scope = cast(*EHStack.find(C)); + assert(Scope.isActive() && "double deactivation"); + + // If it's the top of the stack, just pop it. + if (C == EHStack.stable_begin()) { + // If it's a normal cleanup, we need to pretend that the + // fallthrough is unreachable. + CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); + PopCleanupBlock(); + Builder.restoreIP(SavedIP); + return; + } + + // Otherwise, follow the general case. + SetupCleanupBlockActivation(*this, C, ForDeactivation); + + Scope.setActive(false); +} + +llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() { + if (!NormalCleanupDest) + NormalCleanupDest = + CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); + return NormalCleanupDest; +} + +llvm::Value *CodeGenFunction::getEHCleanupDestSlot() { + if (!EHCleanupDest) + EHCleanupDest = + CreateTempAlloca(Builder.getInt32Ty(), "eh.cleanup.dest.slot"); + return EHCleanupDest; +} Added: cfe/trunk/lib/CodeGen/CGCleanup.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.h?rev=124484&view=auto ============================================================================== --- cfe/trunk/lib/CodeGen/CGCleanup.h (added) +++ cfe/trunk/lib/CodeGen/CGCleanup.h Fri Jan 28 05:13:47 2011 @@ -0,0 +1,560 @@ +//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These classes support the generation of LLVM IR for cleanups. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGCLEANUP_H +#define CLANG_CODEGEN_CGCLEANUP_H + +/// EHScopeStack is defined in CodeGenFunction.h, but its +/// implementation is in this file and in CGCleanup.cpp. +#include "CodeGenFunction.h" + +namespace llvm { + class Value; + class BasicBlock; +} + +namespace clang { +namespace CodeGen { + +/// A protected scope for zero-cost EH handling. +class EHScope { + llvm::BasicBlock *CachedLandingPad; + + unsigned K : 2; + +protected: + enum { BitsRemaining = 30 }; + +public: + enum Kind { Cleanup, Catch, Terminate, Filter }; + + EHScope(Kind K) : CachedLandingPad(0), K(K) {} + + Kind getKind() const { return static_cast(K); } + + llvm::BasicBlock *getCachedLandingPad() const { + return CachedLandingPad; + } + + void setCachedLandingPad(llvm::BasicBlock *Block) { + CachedLandingPad = Block; + } +}; + +/// A scope which attempts to handle some, possibly all, types of +/// exceptions. +/// +/// Objective C @finally blocks are represented using a cleanup scope +/// after the catch scope. +class EHCatchScope : public EHScope { + unsigned NumHandlers : BitsRemaining; + + // In effect, we have a flexible array member + // Handler Handlers[0]; + // But that's only standard in C99, not C++, so we have to do + // annoying pointer arithmetic instead. + +public: + struct Handler { + /// A type info value, or null (C++ null, not an LLVM null pointer) + /// for a catch-all. + llvm::Value *Type; + + /// The catch handler for this type. + llvm::BasicBlock *Block; + + /// The unwind destination index for this handler. + unsigned Index; + }; + +private: + friend class EHScopeStack; + + Handler *getHandlers() { + return reinterpret_cast(this+1); + } + + const Handler *getHandlers() const { + return reinterpret_cast(this+1); + } + +public: + static size_t getSizeForNumHandlers(unsigned N) { + return sizeof(EHCatchScope) + N * sizeof(Handler); + } + + EHCatchScope(unsigned NumHandlers) + : EHScope(Catch), NumHandlers(NumHandlers) { + } + + unsigned getNumHandlers() const { + return NumHandlers; + } + + void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) { + setHandler(I, /*catchall*/ 0, Block); + } + + void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) { + assert(I < getNumHandlers()); + getHandlers()[I].Type = Type; + getHandlers()[I].Block = Block; + } + + const Handler &getHandler(unsigned I) const { + assert(I < getNumHandlers()); + return getHandlers()[I]; + } + + typedef const Handler *iterator; + iterator begin() const { return getHandlers(); } + iterator end() const { return getHandlers() + getNumHandlers(); } + + static bool classof(const EHScope *Scope) { + return Scope->getKind() == Catch; + } +}; + +/// A cleanup scope which generates the cleanup blocks lazily. +class EHCleanupScope : public EHScope { + /// Whether this cleanup needs to be run along normal edges. + bool IsNormalCleanup : 1; + + /// Whether this cleanup needs to be run along exception edges. + bool IsEHCleanup : 1; + + /// Whether this cleanup is currently active. + bool IsActive : 1; + + /// Whether the normal cleanup should test the activation flag. + bool TestFlagInNormalCleanup : 1; + + /// Whether the EH cleanup should test the activation flag. + bool TestFlagInEHCleanup : 1; + + /// The amount of extra storage needed by the Cleanup. + /// Always a multiple of the scope-stack alignment. + unsigned CleanupSize : 12; + + /// The number of fixups required by enclosing scopes (not including + /// this one). If this is the top cleanup scope, all the fixups + /// from this index onwards belong to this scope. + unsigned FixupDepth : BitsRemaining - 17; // currently 13 + + /// The nearest normal cleanup scope enclosing this one. + EHScopeStack::stable_iterator EnclosingNormal; + + /// The nearest EH cleanup scope enclosing this one. + EHScopeStack::stable_iterator EnclosingEH; + + /// The dual entry/exit block along the normal edge. This is lazily + /// created if needed before the cleanup is popped. + llvm::BasicBlock *NormalBlock; + + /// The dual entry/exit block along the EH edge. This is lazily + /// created if needed before the cleanup is popped. + llvm::BasicBlock *EHBlock; + + /// An optional i1 variable indicating whether this cleanup has been + /// activated yet. + llvm::AllocaInst *ActiveFlag; + + /// Extra information required for cleanups that have resolved + /// branches through them. This has to be allocated on the side + /// because everything on the cleanup stack has be trivially + /// movable. + struct ExtInfo { + /// The destinations of normal branch-afters and branch-throughs. + llvm::SmallPtrSet Branches; + + /// Normal branch-afters. + llvm::SmallVector, 4> + BranchAfters; + + /// The destinations of EH branch-afters and branch-throughs. + /// TODO: optimize for the extremely common case of a single + /// branch-through. + llvm::SmallPtrSet EHBranches; + + /// EH branch-afters. + llvm::SmallVector, 4> + EHBranchAfters; + }; + mutable struct ExtInfo *ExtInfo; + + struct ExtInfo &getExtInfo() { + if (!ExtInfo) ExtInfo = new struct ExtInfo(); + return *ExtInfo; + } + + const struct ExtInfo &getExtInfo() const { + if (!ExtInfo) ExtInfo = new struct ExtInfo(); + return *ExtInfo; + } + +public: + /// Gets the size required for a lazy cleanup scope with the given + /// cleanup-data requirements. + static size_t getSizeForCleanupSize(size_t Size) { + return sizeof(EHCleanupScope) + Size; + } + + size_t getAllocatedSize() const { + return sizeof(EHCleanupScope) + CleanupSize; + } + + EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive, + unsigned CleanupSize, unsigned FixupDepth, + EHScopeStack::stable_iterator EnclosingNormal, + EHScopeStack::stable_iterator EnclosingEH) + : EHScope(EHScope::Cleanup), + IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), IsActive(IsActive), + TestFlagInNormalCleanup(false), TestFlagInEHCleanup(false), + CleanupSize(CleanupSize), FixupDepth(FixupDepth), + EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), + NormalBlock(0), EHBlock(0), ActiveFlag(0), ExtInfo(0) + { + assert(this->CleanupSize == CleanupSize && "cleanup size overflow"); + } + + ~EHCleanupScope() { + delete ExtInfo; + } + + bool isNormalCleanup() const { return IsNormalCleanup; } + llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } + void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; } + + bool isEHCleanup() const { return IsEHCleanup; } + llvm::BasicBlock *getEHBlock() const { return EHBlock; } + void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; } + + bool isActive() const { return IsActive; } + void setActive(bool A) { IsActive = A; } + + llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; } + void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; } + + void setTestFlagInNormalCleanup() { TestFlagInNormalCleanup = true; } + bool shouldTestFlagInNormalCleanup() const { return TestFlagInNormalCleanup; } + + void setTestFlagInEHCleanup() { TestFlagInEHCleanup = true; } + bool shouldTestFlagInEHCleanup() const { return TestFlagInEHCleanup; } + + unsigned getFixupDepth() const { return FixupDepth; } + EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { + return EnclosingNormal; + } + EHScopeStack::stable_iterator getEnclosingEHCleanup() const { + return EnclosingEH; + } + + size_t getCleanupSize() const { return CleanupSize; } + void *getCleanupBuffer() { return this + 1; } + + EHScopeStack::Cleanup *getCleanup() { + return reinterpret_cast(getCleanupBuffer()); + } + + /// True if this cleanup scope has any branch-afters or branch-throughs. + bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); } + + /// Add a branch-after to this cleanup scope. A branch-after is a + /// branch from a point protected by this (normal) cleanup to a + /// point in the normal cleanup scope immediately containing it. + /// For example, + /// for (;;) { A a; break; } + /// contains a branch-after. + /// + /// Branch-afters each have their own destination out of the + /// cleanup, guaranteed distinct from anything else threaded through + /// it. Therefore branch-afters usually force a switch after the + /// cleanup. + void addBranchAfter(llvm::ConstantInt *Index, + llvm::BasicBlock *Block) { + struct ExtInfo &ExtInfo = getExtInfo(); + if (ExtInfo.Branches.insert(Block)) + ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index)); + } + + /// Return the number of unique branch-afters on this scope. + unsigned getNumBranchAfters() const { + return ExtInfo ? ExtInfo->BranchAfters.size() : 0; + } + + llvm::BasicBlock *getBranchAfterBlock(unsigned I) const { + assert(I < getNumBranchAfters()); + return ExtInfo->BranchAfters[I].first; + } + + llvm::ConstantInt *getBranchAfterIndex(unsigned I) const { + assert(I < getNumBranchAfters()); + return ExtInfo->BranchAfters[I].second; + } + + /// Add a branch-through to this cleanup scope. A branch-through is + /// a branch from a scope protected by this (normal) cleanup to an + /// enclosing scope other than the immediately-enclosing normal + /// cleanup scope. + /// + /// In the following example, the branch through B's scope is a + /// branch-through, while the branch through A's scope is a + /// branch-after: + /// for (;;) { A a; B b; break; } + /// + /// All branch-throughs have a common destination out of the + /// cleanup, one possibly shared with the fall-through. Therefore + /// branch-throughs usually don't force a switch after the cleanup. + /// + /// \return true if the branch-through was new to this scope + bool addBranchThrough(llvm::BasicBlock *Block) { + return getExtInfo().Branches.insert(Block); + } + + /// Determines if this cleanup scope has any branch throughs. + bool hasBranchThroughs() const { + if (!ExtInfo) return false; + return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); + } + + // Same stuff, only for EH branches instead of normal branches. + // It's quite possible that we could find a better representation + // for this. + + bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); } + void addEHBranchAfter(llvm::ConstantInt *Index, + llvm::BasicBlock *Block) { + struct ExtInfo &ExtInfo = getExtInfo(); + if (ExtInfo.EHBranches.insert(Block)) + ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index)); + } + + unsigned getNumEHBranchAfters() const { + return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0; + } + + llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const { + assert(I < getNumEHBranchAfters()); + return ExtInfo->EHBranchAfters[I].first; + } + + llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const { + assert(I < getNumEHBranchAfters()); + return ExtInfo->EHBranchAfters[I].second; + } + + bool addEHBranchThrough(llvm::BasicBlock *Block) { + return getExtInfo().EHBranches.insert(Block); + } + + bool hasEHBranchThroughs() const { + if (!ExtInfo) return false; + return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size()); + } + + static bool classof(const EHScope *Scope) { + return (Scope->getKind() == Cleanup); + } +}; + +/// An exceptions scope which filters exceptions thrown through it. +/// Only exceptions matching the filter types will be permitted to be +/// thrown. +/// +/// This is used to implement C++ exception specifications. +class EHFilterScope : public EHScope { + unsigned NumFilters : BitsRemaining; + + // Essentially ends in a flexible array member: + // llvm::Value *FilterTypes[0]; + + llvm::Value **getFilters() { + return reinterpret_cast(this+1); + } + + llvm::Value * const *getFilters() const { + return reinterpret_cast(this+1); + } + +public: + EHFilterScope(unsigned NumFilters) : + EHScope(Filter), NumFilters(NumFilters) {} + + static size_t getSizeForNumFilters(unsigned NumFilters) { + return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*); + } + + unsigned getNumFilters() const { return NumFilters; } + + void setFilter(unsigned I, llvm::Value *FilterValue) { + assert(I < getNumFilters()); + getFilters()[I] = FilterValue; + } + + llvm::Value *getFilter(unsigned I) const { + assert(I < getNumFilters()); + return getFilters()[I]; + } + + static bool classof(const EHScope *Scope) { + return Scope->getKind() == Filter; + } +}; + +/// An exceptions scope which calls std::terminate if any exception +/// reaches it. +class EHTerminateScope : public EHScope { + unsigned DestIndex : BitsRemaining; +public: + EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {} + static size_t getSize() { return sizeof(EHTerminateScope); } + + unsigned getDestIndex() const { return DestIndex; } + + static bool classof(const EHScope *Scope) { + return Scope->getKind() == Terminate; + } +}; + +/// A non-stable pointer into the scope stack. +class EHScopeStack::iterator { + char *Ptr; + + friend class EHScopeStack; + explicit iterator(char *Ptr) : Ptr(Ptr) {} + +public: + iterator() : Ptr(0) {} + + EHScope *get() const { + return reinterpret_cast(Ptr); + } + + EHScope *operator->() const { return get(); } + EHScope &operator*() const { return *get(); } + + iterator &operator++() { + switch (get()->getKind()) { + case EHScope::Catch: + Ptr += EHCatchScope::getSizeForNumHandlers( + static_cast(get())->getNumHandlers()); + break; + + case EHScope::Filter: + Ptr += EHFilterScope::getSizeForNumFilters( + static_cast(get())->getNumFilters()); + break; + + case EHScope::Cleanup: + Ptr += static_cast(get()) + ->getAllocatedSize(); + break; + + case EHScope::Terminate: + Ptr += EHTerminateScope::getSize(); + break; + } + + return *this; + } + + iterator next() { + iterator copy = *this; + ++copy; + return copy; + } + + iterator operator++(int) { + iterator copy = *this; + operator++(); + return copy; + } + + bool encloses(iterator other) const { return Ptr >= other.Ptr; } + bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; } + + bool operator==(iterator other) const { return Ptr == other.Ptr; } + bool operator!=(iterator other) const { return Ptr != other.Ptr; } +}; + +inline EHScopeStack::iterator EHScopeStack::begin() const { + return iterator(StartOfData); +} + +inline EHScopeStack::iterator EHScopeStack::end() const { + return iterator(EndOfBuffer); +} + +inline void EHScopeStack::popCatch() { + assert(!empty() && "popping exception stack when not empty"); + + assert(isa(*begin())); + StartOfData += EHCatchScope::getSizeForNumHandlers( + cast(*begin()).getNumHandlers()); + + if (empty()) NextEHDestIndex = FirstEHDestIndex; + + assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); + CatchDepth--; +} + +inline void EHScopeStack::popTerminate() { + assert(!empty() && "popping exception stack when not empty"); + + assert(isa(*begin())); + StartOfData += EHTerminateScope::getSize(); + + if (empty()) NextEHDestIndex = FirstEHDestIndex; + + assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); + CatchDepth--; +} + +inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { + assert(sp.isValid() && "finding invalid savepoint"); + assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); + return iterator(EndOfBuffer - sp.Size); +} + +inline EHScopeStack::stable_iterator +EHScopeStack::stabilize(iterator ir) const { + assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer); + return stable_iterator(EndOfBuffer - ir.Ptr); +} + +inline EHScopeStack::stable_iterator +EHScopeStack::getInnermostActiveNormalCleanup() const { + for (EHScopeStack::stable_iterator + I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) { + EHCleanupScope &S = cast(*find(I)); + if (S.isActive()) return I; + I = S.getEnclosingNormalCleanup(); + } + return stable_end(); +} + +inline EHScopeStack::stable_iterator +EHScopeStack::getInnermostActiveEHCleanup() const { + for (EHScopeStack::stable_iterator + I = getInnermostEHCleanup(), E = stable_end(); I != E; ) { + EHCleanupScope &S = cast(*find(I)); + if (S.isActive()) return I; + I = S.getEnclosingEHCleanup(); + } + return stable_end(); +} + +} +} + +#endif Modified: cfe/trunk/lib/CodeGen/CGException.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGException.cpp (original) +++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Jan 28 05:13:47 2011 @@ -20,180 +20,12 @@ #include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CGException.h" +#include "CGCleanup.h" #include "TargetInfo.h" using namespace clang; using namespace CodeGen; -/// Push an entry of the given size onto this protected-scope stack. -char *EHScopeStack::allocate(size_t Size) { - if (!StartOfBuffer) { - unsigned Capacity = 1024; - while (Capacity < Size) Capacity *= 2; - StartOfBuffer = new char[Capacity]; - StartOfData = EndOfBuffer = StartOfBuffer + Capacity; - } else if (static_cast(StartOfData - StartOfBuffer) < Size) { - unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer; - unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer); - - unsigned NewCapacity = CurrentCapacity; - do { - NewCapacity *= 2; - } while (NewCapacity < UsedCapacity + Size); - - char *NewStartOfBuffer = new char[NewCapacity]; - char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity; - char *NewStartOfData = NewEndOfBuffer - UsedCapacity; - memcpy(NewStartOfData, StartOfData, UsedCapacity); - delete [] StartOfBuffer; - StartOfBuffer = NewStartOfBuffer; - EndOfBuffer = NewEndOfBuffer; - StartOfData = NewStartOfData; - } - - assert(StartOfBuffer + Size <= StartOfData); - StartOfData -= Size; - return StartOfData; -} - -EHScopeStack::stable_iterator -EHScopeStack::getEnclosingEHCleanup(iterator it) const { - assert(it != end()); - do { - if (isa(*it)) { - if (cast(*it).isEHCleanup()) - return stabilize(it); - return cast(*it).getEnclosingEHCleanup(); - } - ++it; - } while (it != end()); - return stable_end(); -} - - -void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { - assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); - char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); - bool IsNormalCleanup = Kind & NormalCleanup; - bool IsEHCleanup = Kind & EHCleanup; - bool IsActive = !(Kind & InactiveCleanup); - EHCleanupScope *Scope = - new (Buffer) EHCleanupScope(IsNormalCleanup, - IsEHCleanup, - IsActive, - Size, - BranchFixups.size(), - InnermostNormalCleanup, - InnermostEHCleanup); - if (IsNormalCleanup) - InnermostNormalCleanup = stable_begin(); - if (IsEHCleanup) - InnermostEHCleanup = stable_begin(); - - return Scope->getCleanupBuffer(); -} - -void EHScopeStack::popCleanup() { - assert(!empty() && "popping exception stack when not empty"); - - assert(isa(*begin())); - EHCleanupScope &Cleanup = cast(*begin()); - InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); - InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); - StartOfData += Cleanup.getAllocatedSize(); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - // Destroy the cleanup. - Cleanup.~EHCleanupScope(); - - // Check whether we can shrink the branch-fixups stack. - if (!BranchFixups.empty()) { - // If we no longer have any normal cleanups, all the fixups are - // complete. - if (!hasNormalCleanups()) - BranchFixups.clear(); - - // Otherwise we can still trim out unnecessary nulls. - else - popNullFixups(); - } -} - -EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) { - char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters)); - CatchDepth++; - return new (Buffer) EHFilterScope(NumFilters); -} - -void EHScopeStack::popFilter() { - assert(!empty() && "popping exception stack when not empty"); - - EHFilterScope &Filter = cast(*begin()); - StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters()); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched filter push/pop"); - CatchDepth--; -} - -EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) { - char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers)); - CatchDepth++; - EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers); - for (unsigned I = 0; I != NumHandlers; ++I) - Scope->getHandlers()[I].Index = getNextEHDestIndex(); - return Scope; -} - -void EHScopeStack::pushTerminate() { - char *Buffer = allocate(EHTerminateScope::getSize()); - CatchDepth++; - new (Buffer) EHTerminateScope(getNextEHDestIndex()); -} - -/// Remove any 'null' fixups on the stack. However, we can't pop more -/// fixups than the fixup depth on the innermost normal cleanup, or -/// else fixups that we try to add to that cleanup will end up in the -/// wrong place. We *could* try to shrink fixup depths, but that's -/// actually a lot of work for little benefit. -void EHScopeStack::popNullFixups() { - // We expect this to only be called when there's still an innermost - // normal cleanup; otherwise there really shouldn't be any fixups. - assert(hasNormalCleanups()); - - EHScopeStack::iterator it = find(InnermostNormalCleanup); - unsigned MinSize = cast(*it).getFixupDepth(); - assert(BranchFixups.size() >= MinSize && "fixup stack out of order"); - - while (BranchFixups.size() > MinSize && - BranchFixups.back().Destination == 0) - BranchFixups.pop_back(); -} - -void CodeGenFunction::initFullExprCleanup() { - // Create a variable to decide whether the cleanup needs to be run. - llvm::AllocaInst *active - = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond"); - - // Initialize it to false at a site that's guaranteed to be run - // before each evaluation. - llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); - new llvm::StoreInst(Builder.getFalse(), active, &block->back()); - - // Initialize it to true at the current location. - Builder.CreateStore(Builder.getTrue(), active); - - // Set that as the active flag in the cleanup. - EHCleanupScope &cleanup = cast(*EHStack.begin()); - assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?"); - cleanup.setActiveFlag(active); - - if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup(); - if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup(); -} - static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); @@ -1624,6 +1456,3 @@ return RethrowBlock; } -EHScopeStack::Cleanup::~Cleanup() { - llvm_unreachable("Cleanup is indestructable"); -} Modified: cfe/trunk/lib/CodeGen/CGException.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.h?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGException.h (original) +++ cfe/trunk/lib/CodeGen/CGException.h Fri Jan 28 05:13:47 2011 @@ -15,16 +15,11 @@ #ifndef CLANG_CODEGEN_CGEXCEPTION_H #define CLANG_CODEGEN_CGEXCEPTION_H -/// EHScopeStack is defined in CodeGenFunction.h, but its -/// implementation is in this file and in CGException.cpp. -#include "CodeGenFunction.h" - -namespace llvm { - class Value; - class BasicBlock; -} +#include "llvm/ADT/StringRef.h" namespace clang { +class LangOptions; + namespace CodeGen { /// The exceptions personality for a function. When @@ -54,534 +49,6 @@ llvm::StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; } }; -/// A protected scope for zero-cost EH handling. -class EHScope { - llvm::BasicBlock *CachedLandingPad; - - unsigned K : 2; - -protected: - enum { BitsRemaining = 30 }; - -public: - enum Kind { Cleanup, Catch, Terminate, Filter }; - - EHScope(Kind K) : CachedLandingPad(0), K(K) {} - - Kind getKind() const { return static_cast(K); } - - llvm::BasicBlock *getCachedLandingPad() const { - return CachedLandingPad; - } - - void setCachedLandingPad(llvm::BasicBlock *Block) { - CachedLandingPad = Block; - } -}; - -/// A scope which attempts to handle some, possibly all, types of -/// exceptions. -/// -/// Objective C @finally blocks are represented using a cleanup scope -/// after the catch scope. -class EHCatchScope : public EHScope { - unsigned NumHandlers : BitsRemaining; - - // In effect, we have a flexible array member - // Handler Handlers[0]; - // But that's only standard in C99, not C++, so we have to do - // annoying pointer arithmetic instead. - -public: - struct Handler { - /// A type info value, or null (C++ null, not an LLVM null pointer) - /// for a catch-all. - llvm::Value *Type; - - /// The catch handler for this type. - llvm::BasicBlock *Block; - - /// The unwind destination index for this handler. - unsigned Index; - }; - -private: - friend class EHScopeStack; - - Handler *getHandlers() { - return reinterpret_cast(this+1); - } - - const Handler *getHandlers() const { - return reinterpret_cast(this+1); - } - -public: - static size_t getSizeForNumHandlers(unsigned N) { - return sizeof(EHCatchScope) + N * sizeof(Handler); - } - - EHCatchScope(unsigned NumHandlers) - : EHScope(Catch), NumHandlers(NumHandlers) { - } - - unsigned getNumHandlers() const { - return NumHandlers; - } - - void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) { - setHandler(I, /*catchall*/ 0, Block); - } - - void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) { - assert(I < getNumHandlers()); - getHandlers()[I].Type = Type; - getHandlers()[I].Block = Block; - } - - const Handler &getHandler(unsigned I) const { - assert(I < getNumHandlers()); - return getHandlers()[I]; - } - - typedef const Handler *iterator; - iterator begin() const { return getHandlers(); } - iterator end() const { return getHandlers() + getNumHandlers(); } - - static bool classof(const EHScope *Scope) { - return Scope->getKind() == Catch; - } -}; - -/// A cleanup scope which generates the cleanup blocks lazily. -class EHCleanupScope : public EHScope { - /// Whether this cleanup needs to be run along normal edges. - bool IsNormalCleanup : 1; - - /// Whether this cleanup needs to be run along exception edges. - bool IsEHCleanup : 1; - - /// Whether this cleanup is currently active. - bool IsActive : 1; - - /// Whether the normal cleanup should test the activation flag. - bool TestFlagInNormalCleanup : 1; - - /// Whether the EH cleanup should test the activation flag. - bool TestFlagInEHCleanup : 1; - - /// The amount of extra storage needed by the Cleanup. - /// Always a multiple of the scope-stack alignment. - unsigned CleanupSize : 12; - - /// The number of fixups required by enclosing scopes (not including - /// this one). If this is the top cleanup scope, all the fixups - /// from this index onwards belong to this scope. - unsigned FixupDepth : BitsRemaining - 17; // currently 13 - - /// The nearest normal cleanup scope enclosing this one. - EHScopeStack::stable_iterator EnclosingNormal; - - /// The nearest EH cleanup scope enclosing this one. - EHScopeStack::stable_iterator EnclosingEH; - - /// The dual entry/exit block along the normal edge. This is lazily - /// created if needed before the cleanup is popped. - llvm::BasicBlock *NormalBlock; - - /// The dual entry/exit block along the EH edge. This is lazily - /// created if needed before the cleanup is popped. - llvm::BasicBlock *EHBlock; - - /// An optional i1 variable indicating whether this cleanup has been - /// activated yet. - llvm::AllocaInst *ActiveFlag; - - /// Extra information required for cleanups that have resolved - /// branches through them. This has to be allocated on the side - /// because everything on the cleanup stack has be trivially - /// movable. - struct ExtInfo { - /// The destinations of normal branch-afters and branch-throughs. - llvm::SmallPtrSet Branches; - - /// Normal branch-afters. - llvm::SmallVector, 4> - BranchAfters; - - /// The destinations of EH branch-afters and branch-throughs. - /// TODO: optimize for the extremely common case of a single - /// branch-through. - llvm::SmallPtrSet EHBranches; - - /// EH branch-afters. - llvm::SmallVector, 4> - EHBranchAfters; - }; - mutable struct ExtInfo *ExtInfo; - - struct ExtInfo &getExtInfo() { - if (!ExtInfo) ExtInfo = new struct ExtInfo(); - return *ExtInfo; - } - - const struct ExtInfo &getExtInfo() const { - if (!ExtInfo) ExtInfo = new struct ExtInfo(); - return *ExtInfo; - } - -public: - /// Gets the size required for a lazy cleanup scope with the given - /// cleanup-data requirements. - static size_t getSizeForCleanupSize(size_t Size) { - return sizeof(EHCleanupScope) + Size; - } - - size_t getAllocatedSize() const { - return sizeof(EHCleanupScope) + CleanupSize; - } - - EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive, - unsigned CleanupSize, unsigned FixupDepth, - EHScopeStack::stable_iterator EnclosingNormal, - EHScopeStack::stable_iterator EnclosingEH) - : EHScope(EHScope::Cleanup), - IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), IsActive(IsActive), - TestFlagInNormalCleanup(false), TestFlagInEHCleanup(false), - CleanupSize(CleanupSize), FixupDepth(FixupDepth), - EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), - NormalBlock(0), EHBlock(0), ActiveFlag(0), ExtInfo(0) - { - assert(this->CleanupSize == CleanupSize && "cleanup size overflow"); - } - - ~EHCleanupScope() { - delete ExtInfo; - } - - bool isNormalCleanup() const { return IsNormalCleanup; } - llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } - void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; } - - bool isEHCleanup() const { return IsEHCleanup; } - llvm::BasicBlock *getEHBlock() const { return EHBlock; } - void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; } - - bool isActive() const { return IsActive; } - void setActive(bool A) { IsActive = A; } - - llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; } - void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; } - - void setTestFlagInNormalCleanup() { TestFlagInNormalCleanup = true; } - bool shouldTestFlagInNormalCleanup() const { return TestFlagInNormalCleanup; } - - void setTestFlagInEHCleanup() { TestFlagInEHCleanup = true; } - bool shouldTestFlagInEHCleanup() const { return TestFlagInEHCleanup; } - - unsigned getFixupDepth() const { return FixupDepth; } - EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { - return EnclosingNormal; - } - EHScopeStack::stable_iterator getEnclosingEHCleanup() const { - return EnclosingEH; - } - - size_t getCleanupSize() const { return CleanupSize; } - void *getCleanupBuffer() { return this + 1; } - - EHScopeStack::Cleanup *getCleanup() { - return reinterpret_cast(getCleanupBuffer()); - } - - /// True if this cleanup scope has any branch-afters or branch-throughs. - bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); } - - /// Add a branch-after to this cleanup scope. A branch-after is a - /// branch from a point protected by this (normal) cleanup to a - /// point in the normal cleanup scope immediately containing it. - /// For example, - /// for (;;) { A a; break; } - /// contains a branch-after. - /// - /// Branch-afters each have their own destination out of the - /// cleanup, guaranteed distinct from anything else threaded through - /// it. Therefore branch-afters usually force a switch after the - /// cleanup. - void addBranchAfter(llvm::ConstantInt *Index, - llvm::BasicBlock *Block) { - struct ExtInfo &ExtInfo = getExtInfo(); - if (ExtInfo.Branches.insert(Block)) - ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index)); - } - - /// Return the number of unique branch-afters on this scope. - unsigned getNumBranchAfters() const { - return ExtInfo ? ExtInfo->BranchAfters.size() : 0; - } - - llvm::BasicBlock *getBranchAfterBlock(unsigned I) const { - assert(I < getNumBranchAfters()); - return ExtInfo->BranchAfters[I].first; - } - - llvm::ConstantInt *getBranchAfterIndex(unsigned I) const { - assert(I < getNumBranchAfters()); - return ExtInfo->BranchAfters[I].second; - } - - /// Add a branch-through to this cleanup scope. A branch-through is - /// a branch from a scope protected by this (normal) cleanup to an - /// enclosing scope other than the immediately-enclosing normal - /// cleanup scope. - /// - /// In the following example, the branch through B's scope is a - /// branch-through, while the branch through A's scope is a - /// branch-after: - /// for (;;) { A a; B b; break; } - /// - /// All branch-throughs have a common destination out of the - /// cleanup, one possibly shared with the fall-through. Therefore - /// branch-throughs usually don't force a switch after the cleanup. - /// - /// \return true if the branch-through was new to this scope - bool addBranchThrough(llvm::BasicBlock *Block) { - return getExtInfo().Branches.insert(Block); - } - - /// Determines if this cleanup scope has any branch throughs. - bool hasBranchThroughs() const { - if (!ExtInfo) return false; - return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); - } - - // Same stuff, only for EH branches instead of normal branches. - // It's quite possible that we could find a better representation - // for this. - - bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); } - void addEHBranchAfter(llvm::ConstantInt *Index, - llvm::BasicBlock *Block) { - struct ExtInfo &ExtInfo = getExtInfo(); - if (ExtInfo.EHBranches.insert(Block)) - ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index)); - } - - unsigned getNumEHBranchAfters() const { - return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0; - } - - llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const { - assert(I < getNumEHBranchAfters()); - return ExtInfo->EHBranchAfters[I].first; - } - - llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const { - assert(I < getNumEHBranchAfters()); - return ExtInfo->EHBranchAfters[I].second; - } - - bool addEHBranchThrough(llvm::BasicBlock *Block) { - return getExtInfo().EHBranches.insert(Block); - } - - bool hasEHBranchThroughs() const { - if (!ExtInfo) return false; - return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size()); - } - - static bool classof(const EHScope *Scope) { - return (Scope->getKind() == Cleanup); - } -}; - -/// An exceptions scope which filters exceptions thrown through it. -/// Only exceptions matching the filter types will be permitted to be -/// thrown. -/// -/// This is used to implement C++ exception specifications. -class EHFilterScope : public EHScope { - unsigned NumFilters : BitsRemaining; - - // Essentially ends in a flexible array member: - // llvm::Value *FilterTypes[0]; - - llvm::Value **getFilters() { - return reinterpret_cast(this+1); - } - - llvm::Value * const *getFilters() const { - return reinterpret_cast(this+1); - } - -public: - EHFilterScope(unsigned NumFilters) : - EHScope(Filter), NumFilters(NumFilters) {} - - static size_t getSizeForNumFilters(unsigned NumFilters) { - return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*); - } - - unsigned getNumFilters() const { return NumFilters; } - - void setFilter(unsigned I, llvm::Value *FilterValue) { - assert(I < getNumFilters()); - getFilters()[I] = FilterValue; - } - - llvm::Value *getFilter(unsigned I) const { - assert(I < getNumFilters()); - return getFilters()[I]; - } - - static bool classof(const EHScope *Scope) { - return Scope->getKind() == Filter; - } -}; - -/// An exceptions scope which calls std::terminate if any exception -/// reaches it. -class EHTerminateScope : public EHScope { - unsigned DestIndex : BitsRemaining; -public: - EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {} - static size_t getSize() { return sizeof(EHTerminateScope); } - - unsigned getDestIndex() const { return DestIndex; } - - static bool classof(const EHScope *Scope) { - return Scope->getKind() == Terminate; - } -}; - -/// A non-stable pointer into the scope stack. -class EHScopeStack::iterator { - char *Ptr; - - friend class EHScopeStack; - explicit iterator(char *Ptr) : Ptr(Ptr) {} - -public: - iterator() : Ptr(0) {} - - EHScope *get() const { - return reinterpret_cast(Ptr); - } - - EHScope *operator->() const { return get(); } - EHScope &operator*() const { return *get(); } - - iterator &operator++() { - switch (get()->getKind()) { - case EHScope::Catch: - Ptr += EHCatchScope::getSizeForNumHandlers( - static_cast(get())->getNumHandlers()); - break; - - case EHScope::Filter: - Ptr += EHFilterScope::getSizeForNumFilters( - static_cast(get())->getNumFilters()); - break; - - case EHScope::Cleanup: - Ptr += static_cast(get()) - ->getAllocatedSize(); - break; - - case EHScope::Terminate: - Ptr += EHTerminateScope::getSize(); - break; - } - - return *this; - } - - iterator next() { - iterator copy = *this; - ++copy; - return copy; - } - - iterator operator++(int) { - iterator copy = *this; - operator++(); - return copy; - } - - bool encloses(iterator other) const { return Ptr >= other.Ptr; } - bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; } - - bool operator==(iterator other) const { return Ptr == other.Ptr; } - bool operator!=(iterator other) const { return Ptr != other.Ptr; } -}; - -inline EHScopeStack::iterator EHScopeStack::begin() const { - return iterator(StartOfData); -} - -inline EHScopeStack::iterator EHScopeStack::end() const { - return iterator(EndOfBuffer); -} - -inline void EHScopeStack::popCatch() { - assert(!empty() && "popping exception stack when not empty"); - - assert(isa(*begin())); - StartOfData += EHCatchScope::getSizeForNumHandlers( - cast(*begin()).getNumHandlers()); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); - CatchDepth--; -} - -inline void EHScopeStack::popTerminate() { - assert(!empty() && "popping exception stack when not empty"); - - assert(isa(*begin())); - StartOfData += EHTerminateScope::getSize(); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); - CatchDepth--; -} - -inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { - assert(sp.isValid() && "finding invalid savepoint"); - assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); - return iterator(EndOfBuffer - sp.Size); -} - -inline EHScopeStack::stable_iterator -EHScopeStack::stabilize(iterator ir) const { - assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer); - return stable_iterator(EndOfBuffer - ir.Ptr); -} - -inline EHScopeStack::stable_iterator -EHScopeStack::getInnermostActiveNormalCleanup() const { - for (EHScopeStack::stable_iterator - I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) { - EHCleanupScope &S = cast(*find(I)); - if (S.isActive()) return I; - I = S.getEnclosingNormalCleanup(); - } - return stable_end(); -} - -inline EHScopeStack::stable_iterator -EHScopeStack::getInnermostActiveEHCleanup() const { - for (EHScopeStack::stable_iterator - I = getInnermostEHCleanup(), E = stable_end(); I != E; ) { - EHCleanupScope &S = cast(*find(I)); - if (S.isActive()) return I; - I = S.getEnclosingEHCleanup(); - } - return stable_end(); -} - } } Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 05:13:47 2011 @@ -721,71 +721,6 @@ StoreAnyExprIntoOneUnit(CGF, E, NewPtr); } -bool DominatingValue::saved_type::needsSaving(RValue rv) { - if (rv.isScalar()) - return DominatingLLVMValue::needsSaving(rv.getScalarVal()); - if (rv.isAggregate()) - return DominatingLLVMValue::needsSaving(rv.getAggregateAddr()); - return true; -} - -DominatingValue::saved_type -DominatingValue::saved_type::save(CodeGenFunction &CGF, RValue rv) { - if (rv.isScalar()) { - llvm::Value *V = rv.getScalarVal(); - - // These automatically dominate and don't need to be saved. - if (!DominatingLLVMValue::needsSaving(V)) - return saved_type(V, ScalarLiteral); - - // Everything else needs an alloca. - llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, addr); - return saved_type(addr, ScalarAddress); - } - - if (rv.isComplex()) { - CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); - const llvm::Type *ComplexTy = - llvm::StructType::get(CGF.getLLVMContext(), - V.first->getType(), V.second->getType(), - (void*) 0); - llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex"); - CGF.StoreComplexToAddr(V, addr, /*volatile*/ false); - return saved_type(addr, ComplexAddress); - } - - assert(rv.isAggregate()); - llvm::Value *V = rv.getAggregateAddr(); // TODO: volatile? - if (!DominatingLLVMValue::needsSaving(V)) - return saved_type(V, AggregateLiteral); - - llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, addr); - return saved_type(addr, AggregateAddress); -} - -/// Given a saved r-value produced by SaveRValue, perform the code -/// necessary to restore it to usability at the current insertion -/// point. -RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { - switch (K) { - case ScalarLiteral: - return RValue::get(Value); - case ScalarAddress: - return RValue::get(CGF.Builder.CreateLoad(Value)); - case AggregateLiteral: - return RValue::getAggregate(Value); - case AggregateAddress: - return RValue::getAggregate(CGF.Builder.CreateLoad(Value)); - case ComplexAddress: - return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false)); - } - - llvm_unreachable("bad saved r-value kind"); - return RValue(); -} - namespace { /// A cleanup to call the given 'operator delete' function upon /// abnormal exit from a new expression. Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Fri Jan 28 05:13:47 2011 @@ -17,7 +17,7 @@ #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" -#include "CGException.h" +#include "CGCleanup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Fri Jan 28 05:13:47 2011 @@ -16,7 +16,7 @@ #include "CGRecordLayout.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" -#include "CGException.h" +#include "CGCleanup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=124484&r1=124483&r2=124484&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Jan 28 05:13:47 2011 @@ -28,10 +28,6 @@ using namespace clang; using namespace CodeGen; -static void ResolveAllBranchFixups(CodeGenFunction &CGF, - llvm::SwitchInst *Switch, - llvm::BasicBlock *CleanupEntry); - CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), @@ -692,888 +688,6 @@ return EmitLValue(E).getAddress(); } -/// Pops cleanup blocks until the given savepoint is reached. -void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { - assert(Old.isValid()); - - while (EHStack.stable_begin() != Old) { - EHCleanupScope &Scope = cast(*EHStack.begin()); - - // As long as Old strictly encloses the scope's enclosing normal - // cleanup, we're going to emit another normal cleanup which - // fallthrough can propagate through. - bool FallThroughIsBranchThrough = - Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); - - PopCleanupBlock(FallThroughIsBranchThrough); - } -} - -static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, - EHCleanupScope &Scope) { - assert(Scope.isNormalCleanup()); - llvm::BasicBlock *Entry = Scope.getNormalBlock(); - if (!Entry) { - Entry = CGF.createBasicBlock("cleanup"); - Scope.setNormalBlock(Entry); - } - return Entry; -} - -static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF, - EHCleanupScope &Scope) { - assert(Scope.isEHCleanup()); - llvm::BasicBlock *Entry = Scope.getEHBlock(); - if (!Entry) { - Entry = CGF.createBasicBlock("eh.cleanup"); - Scope.setEHBlock(Entry); - } - return Entry; -} - -/// Transitions the terminator of the given exit-block of a cleanup to -/// be a cleanup switch. -static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF, - llvm::BasicBlock *Block) { - // If it's a branch, turn it into a switch whose default - // destination is its original target. - llvm::TerminatorInst *Term = Block->getTerminator(); - assert(Term && "can't transition block without terminator"); - - if (llvm::BranchInst *Br = dyn_cast(Term)) { - assert(Br->isUnconditional()); - llvm::LoadInst *Load = - new llvm::LoadInst(CGF.getNormalCleanupDestSlot(), "cleanup.dest", Term); - llvm::SwitchInst *Switch = - llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block); - Br->eraseFromParent(); - return Switch; - } else { - return cast(Term); - } -} - -/// Attempts to reduce a cleanup's entry block to a fallthrough. This -/// is basically llvm::MergeBlockIntoPredecessor, except -/// simplified/optimized for the tighter constraints on cleanup blocks. -/// -/// Returns the new block, whatever it is. -static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF, - llvm::BasicBlock *Entry) { - llvm::BasicBlock *Pred = Entry->getSinglePredecessor(); - if (!Pred) return Entry; - - llvm::BranchInst *Br = dyn_cast(Pred->getTerminator()); - if (!Br || Br->isConditional()) return Entry; - assert(Br->getSuccessor(0) == Entry); - - // If we were previously inserting at the end of the cleanup entry - // block, we'll need to continue inserting at the end of the - // predecessor. - bool WasInsertBlock = CGF.Builder.GetInsertBlock() == Entry; - assert(!WasInsertBlock || CGF.Builder.GetInsertPoint() == Entry->end()); - - // Kill the branch. - Br->eraseFromParent(); - - // Merge the blocks. - Pred->getInstList().splice(Pred->end(), Entry->getInstList()); - - // Replace all uses of the entry with the predecessor, in case there - // are phis in the cleanup. - Entry->replaceAllUsesWith(Pred); - - // Kill the entry block. - Entry->eraseFromParent(); - - if (WasInsertBlock) - CGF.Builder.SetInsertPoint(Pred); - - return Pred; -} - -static void EmitCleanup(CodeGenFunction &CGF, - EHScopeStack::Cleanup *Fn, - bool ForEH, - llvm::Value *ActiveFlag) { - // EH cleanups always occur within a terminate scope. - if (ForEH) CGF.EHStack.pushTerminate(); - - // If there's an active flag, load it and skip the cleanup if it's - // false. - llvm::BasicBlock *ContBB = 0; - if (ActiveFlag) { - ContBB = CGF.createBasicBlock("cleanup.done"); - llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action"); - llvm::Value *IsActive - = CGF.Builder.CreateLoad(ActiveFlag, "cleanup.is_active"); - CGF.Builder.CreateCondBr(IsActive, CleanupBB, ContBB); - CGF.EmitBlock(CleanupBB); - } - - // Ask the cleanup to emit itself. - Fn->Emit(CGF, ForEH); - assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?"); - - // Emit the continuation block if there was an active flag. - if (ActiveFlag) - CGF.EmitBlock(ContBB); - - // Leave the terminate scope. - if (ForEH) CGF.EHStack.popTerminate(); -} - -static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit, - llvm::BasicBlock *From, - llvm::BasicBlock *To) { - // Exit is the exit block of a cleanup, so it always terminates in - // an unconditional branch or a switch. - llvm::TerminatorInst *Term = Exit->getTerminator(); - - if (llvm::BranchInst *Br = dyn_cast(Term)) { - assert(Br->isUnconditional() && Br->getSuccessor(0) == From); - Br->setSuccessor(0, To); - } else { - llvm::SwitchInst *Switch = cast(Term); - for (unsigned I = 0, E = Switch->getNumSuccessors(); I != E; ++I) - if (Switch->getSuccessor(I) == From) - Switch->setSuccessor(I, To); - } -} - -/// Pops a cleanup block. If the block includes a normal cleanup, the -/// current insertion point is threaded through the cleanup, as are -/// any branch fixups on the cleanup. -void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { - assert(!EHStack.empty() && "cleanup stack is empty!"); - assert(isa(*EHStack.begin()) && "top not a cleanup!"); - EHCleanupScope &Scope = cast(*EHStack.begin()); - assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); - - // Remember activation information. - bool IsActive = Scope.isActive(); - llvm::Value *NormalActiveFlag = - Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : 0; - llvm::Value *EHActiveFlag = - Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : 0; - - // Check whether we need an EH cleanup. This is only true if we've - // generated a lazy EH cleanup block. - bool RequiresEHCleanup = Scope.hasEHBranches(); - - // Check the three conditions which might require a normal cleanup: - - // - whether there are branch fix-ups through this cleanup - unsigned FixupDepth = Scope.getFixupDepth(); - bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth; - - // - whether there are branch-throughs or branch-afters - bool HasExistingBranches = Scope.hasBranches(); - - // - whether there's a fallthrough - llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); - bool HasFallthrough = (FallthroughSource != 0 && IsActive); - - // Branch-through fall-throughs leave the insertion point set to the - // end of the last cleanup, which points to the current scope. The - // rest of IR gen doesn't need to worry about this; it only happens - // during the execution of PopCleanupBlocks(). - bool HasPrebranchedFallthrough = - (FallthroughSource && FallthroughSource->getTerminator()); - - // If this is a normal cleanup, then having a prebranched - // fallthrough implies that the fallthrough source unconditionally - // jumps here. - assert(!Scope.isNormalCleanup() || !HasPrebranchedFallthrough || - (Scope.getNormalBlock() && - FallthroughSource->getTerminator()->getSuccessor(0) - == Scope.getNormalBlock())); - - bool RequiresNormalCleanup = false; - if (Scope.isNormalCleanup() && - (HasFixups || HasExistingBranches || HasFallthrough)) { - RequiresNormalCleanup = true; - } - - // Even if we don't need the normal cleanup, we might still have - // prebranched fallthrough to worry about. - if (Scope.isNormalCleanup() && !RequiresNormalCleanup && - HasPrebranchedFallthrough) { - assert(!IsActive); - - llvm::BasicBlock *NormalEntry = Scope.getNormalBlock(); - - // If we're branching through this cleanup, just forward the - // prebranched fallthrough to the next cleanup, leaving the insert - // point in the old block. - if (FallthroughIsBranchThrough) { - EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); - llvm::BasicBlock *EnclosingEntry = - CreateNormalEntry(*this, cast(S)); - - ForwardPrebranchedFallthrough(FallthroughSource, - NormalEntry, EnclosingEntry); - assert(NormalEntry->use_empty() && - "uses of entry remain after forwarding?"); - delete NormalEntry; - - // Otherwise, we're branching out; just emit the next block. - } else { - EmitBlock(NormalEntry); - SimplifyCleanupEntry(*this, NormalEntry); - } - } - - // If we don't need the cleanup at all, we're done. - if (!RequiresNormalCleanup && !RequiresEHCleanup) { - EHStack.popCleanup(); // safe because there are no fixups - assert(EHStack.getNumBranchFixups() == 0 || - EHStack.hasNormalCleanups()); - return; - } - - // Copy the cleanup emission data out. Note that SmallVector - // guarantees maximal alignment for its buffer regardless of its - // type parameter. - llvm::SmallVector CleanupBuffer; - CleanupBuffer.reserve(Scope.getCleanupSize()); - memcpy(CleanupBuffer.data(), - Scope.getCleanupBuffer(), Scope.getCleanupSize()); - CleanupBuffer.set_size(Scope.getCleanupSize()); - EHScopeStack::Cleanup *Fn = - reinterpret_cast(CleanupBuffer.data()); - - // We want to emit the EH cleanup after the normal cleanup, but go - // ahead and do the setup for the EH cleanup while the scope is still - // alive. - llvm::BasicBlock *EHEntry = 0; - llvm::SmallVector EHInstsToAppend; - if (RequiresEHCleanup) { - EHEntry = CreateEHEntry(*this, Scope); - - // Figure out the branch-through dest if necessary. - llvm::BasicBlock *EHBranchThroughDest = 0; - if (Scope.hasEHBranchThroughs()) { - assert(Scope.getEnclosingEHCleanup() != EHStack.stable_end()); - EHScope &S = *EHStack.find(Scope.getEnclosingEHCleanup()); - EHBranchThroughDest = CreateEHEntry(*this, cast(S)); - } - - // If we have exactly one branch-after and no branch-throughs, we - // can dispatch it without a switch. - if (!Scope.hasEHBranchThroughs() && - Scope.getNumEHBranchAfters() == 1) { - assert(!EHBranchThroughDest); - - // TODO: remove the spurious eh.cleanup.dest stores if this edge - // never went through any switches. - llvm::BasicBlock *BranchAfterDest = Scope.getEHBranchAfterBlock(0); - EHInstsToAppend.push_back(llvm::BranchInst::Create(BranchAfterDest)); - - // Otherwise, if we have any branch-afters, we need a switch. - } else if (Scope.getNumEHBranchAfters()) { - // The default of the switch belongs to the branch-throughs if - // they exist. - llvm::BasicBlock *Default = - (EHBranchThroughDest ? EHBranchThroughDest : getUnreachableBlock()); - - const unsigned SwitchCapacity = Scope.getNumEHBranchAfters(); - - llvm::LoadInst *Load = - new llvm::LoadInst(getEHCleanupDestSlot(), "cleanup.dest"); - llvm::SwitchInst *Switch = - llvm::SwitchInst::Create(Load, Default, SwitchCapacity); - - EHInstsToAppend.push_back(Load); - EHInstsToAppend.push_back(Switch); - - for (unsigned I = 0, E = Scope.getNumEHBranchAfters(); I != E; ++I) - Switch->addCase(Scope.getEHBranchAfterIndex(I), - Scope.getEHBranchAfterBlock(I)); - - // Otherwise, we have only branch-throughs; jump to the next EH - // cleanup. - } else { - assert(EHBranchThroughDest); - EHInstsToAppend.push_back(llvm::BranchInst::Create(EHBranchThroughDest)); - } - } - - if (!RequiresNormalCleanup) { - EHStack.popCleanup(); - } else { - // If we have a fallthrough and no other need for the cleanup, - // emit it directly. - if (HasFallthrough && !HasPrebranchedFallthrough && - !HasFixups && !HasExistingBranches) { - - // Fixups can cause us to optimistically create a normal block, - // only to later have no real uses for it. Just delete it in - // this case. - // TODO: we can potentially simplify all the uses after this. - if (Scope.getNormalBlock()) { - Scope.getNormalBlock()->replaceAllUsesWith(getUnreachableBlock()); - delete Scope.getNormalBlock(); - } - - EHStack.popCleanup(); - - EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag); - - // Otherwise, the best approach is to thread everything through - // the cleanup block and then try to clean up after ourselves. - } else { - // Force the entry block to exist. - llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope); - - // I. Set up the fallthrough edge in. - - // If there's a fallthrough, we need to store the cleanup - // destination index. For fall-throughs this is always zero. - if (HasFallthrough) { - if (!HasPrebranchedFallthrough) - Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot()); - - // Otherwise, clear the IP if we don't have fallthrough because - // the cleanup is inactive. We don't need to save it because - // it's still just FallthroughSource. - } else if (FallthroughSource) { - assert(!IsActive && "source without fallthrough for active cleanup"); - Builder.ClearInsertionPoint(); - } - - // II. Emit the entry block. This implicitly branches to it if - // we have fallthrough. All the fixups and existing branches - // should already be branched to it. - EmitBlock(NormalEntry); - - // III. Figure out where we're going and build the cleanup - // epilogue. - - bool HasEnclosingCleanups = - (Scope.getEnclosingNormalCleanup() != EHStack.stable_end()); - - // Compute the branch-through dest if we need it: - // - if there are branch-throughs threaded through the scope - // - if fall-through is a branch-through - // - if there are fixups that will be optimistically forwarded - // to the enclosing cleanup - llvm::BasicBlock *BranchThroughDest = 0; - if (Scope.hasBranchThroughs() || - (FallthroughSource && FallthroughIsBranchThrough) || - (HasFixups && HasEnclosingCleanups)) { - assert(HasEnclosingCleanups); - EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); - BranchThroughDest = CreateNormalEntry(*this, cast(S)); - } - - llvm::BasicBlock *FallthroughDest = 0; - llvm::SmallVector InstsToAppend; - - // If there's exactly one branch-after and no other threads, - // we can route it without a switch. - if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough && - Scope.getNumBranchAfters() == 1) { - assert(!BranchThroughDest || !IsActive); - - // TODO: clean up the possibly dead stores to the cleanup dest slot. - llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); - InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter)); - - // Build a switch-out if we need it: - // - if there are branch-afters threaded through the scope - // - if fall-through is a branch-after - // - if there are fixups that have nowhere left to go and - // so must be immediately resolved - } else if (Scope.getNumBranchAfters() || - (HasFallthrough && !FallthroughIsBranchThrough) || - (HasFixups && !HasEnclosingCleanups)) { - - llvm::BasicBlock *Default = - (BranchThroughDest ? BranchThroughDest : getUnreachableBlock()); - - // TODO: base this on the number of branch-afters and fixups - const unsigned SwitchCapacity = 10; - - llvm::LoadInst *Load = - new llvm::LoadInst(getNormalCleanupDestSlot(), "cleanup.dest"); - llvm::SwitchInst *Switch = - llvm::SwitchInst::Create(Load, Default, SwitchCapacity); - - InstsToAppend.push_back(Load); - InstsToAppend.push_back(Switch); - - // Branch-after fallthrough. - if (FallthroughSource && !FallthroughIsBranchThrough) { - FallthroughDest = createBasicBlock("cleanup.cont"); - if (HasFallthrough) - Switch->addCase(Builder.getInt32(0), FallthroughDest); - } - - for (unsigned I = 0, E = Scope.getNumBranchAfters(); I != E; ++I) { - Switch->addCase(Scope.getBranchAfterIndex(I), - Scope.getBranchAfterBlock(I)); - } - - // If there aren't any enclosing cleanups, we can resolve all - // the fixups now. - if (HasFixups && !HasEnclosingCleanups) - ResolveAllBranchFixups(*this, Switch, NormalEntry); - } else { - // We should always have a branch-through destination in this case. - assert(BranchThroughDest); - InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest)); - } - - // IV. Pop the cleanup and emit it. - EHStack.popCleanup(); - assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); - - EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag); - - // Append the prepared cleanup prologue from above. - llvm::BasicBlock *NormalExit = Builder.GetInsertBlock(); - for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I) - NormalExit->getInstList().push_back(InstsToAppend[I]); - - // Optimistically hope that any fixups will continue falling through. - for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); - I < E; ++I) { - BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I); - if (!Fixup.Destination) continue; - if (!Fixup.OptimisticBranchBlock) { - new llvm::StoreInst(Builder.getInt32(Fixup.DestinationIndex), - getNormalCleanupDestSlot(), - Fixup.InitialBranch); - Fixup.InitialBranch->setSuccessor(0, NormalEntry); - } - Fixup.OptimisticBranchBlock = NormalExit; - } - - // V. Set up the fallthrough edge out. - - // Case 1: a fallthrough source exists but shouldn't branch to - // the cleanup because the cleanup is inactive. - if (!HasFallthrough && FallthroughSource) { - assert(!IsActive); - - // If we have a prebranched fallthrough, that needs to be - // forwarded to the right block. - if (HasPrebranchedFallthrough) { - llvm::BasicBlock *Next; - if (FallthroughIsBranchThrough) { - Next = BranchThroughDest; - assert(!FallthroughDest); - } else { - Next = FallthroughDest; - } - - ForwardPrebranchedFallthrough(FallthroughSource, NormalEntry, Next); - } - Builder.SetInsertPoint(FallthroughSource); - - // Case 2: a fallthrough source exists and should branch to the - // cleanup, but we're not supposed to branch through to the next - // cleanup. - } else if (HasFallthrough && FallthroughDest) { - assert(!FallthroughIsBranchThrough); - EmitBlock(FallthroughDest); - - // Case 3: a fallthrough source exists and should branch to the - // cleanup and then through to the next. - } else if (HasFallthrough) { - // Everything is already set up for this. - - // Case 4: no fallthrough source exists. - } else { - Builder.ClearInsertionPoint(); - } - - // VI. Assorted cleaning. - - // Check whether we can merge NormalEntry into a single predecessor. - // This might invalidate (non-IR) pointers to NormalEntry. - llvm::BasicBlock *NewNormalEntry = - SimplifyCleanupEntry(*this, NormalEntry); - - // If it did invalidate those pointers, and NormalEntry was the same - // as NormalExit, go back and patch up the fixups. - if (NewNormalEntry != NormalEntry && NormalEntry == NormalExit) - for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); - I < E; ++I) - CGF.EHStack.getBranchFixup(I).OptimisticBranchBlock = NewNormalEntry; - } - } - - assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0); - - // Emit the EH cleanup if required. - if (RequiresEHCleanup) { - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - - EmitBlock(EHEntry); - EmitCleanup(*this, Fn, /*ForEH*/ true, EHActiveFlag); - - // Append the prepared cleanup prologue from above. - llvm::BasicBlock *EHExit = Builder.GetInsertBlock(); - for (unsigned I = 0, E = EHInstsToAppend.size(); I != E; ++I) - EHExit->getInstList().push_back(EHInstsToAppend[I]); - - Builder.restoreIP(SavedIP); - - SimplifyCleanupEntry(*this, EHEntry); - } -} - -/// Terminate the current block by emitting a branch which might leave -/// the current cleanup-protected scope. The target scope may not yet -/// be known, in which case this will require a fixup. -/// -/// As a side-effect, this method clears the insertion point. -void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { - assert(Dest.getScopeDepth().encloses(EHStack.getInnermostNormalCleanup()) - && "stale jump destination"); - - if (!HaveInsertPoint()) - return; - - // Create the branch. - llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); - - // Calculate the innermost active normal cleanup. - EHScopeStack::stable_iterator - TopCleanup = EHStack.getInnermostActiveNormalCleanup(); - - // If we're not in an active normal cleanup scope, or if the - // destination scope is within the innermost active normal cleanup - // scope, we don't need to worry about fixups. - if (TopCleanup == EHStack.stable_end() || - TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid - Builder.ClearInsertionPoint(); - return; - } - - // If we can't resolve the destination cleanup scope, just add this - // to the current cleanup scope as a branch fixup. - if (!Dest.getScopeDepth().isValid()) { - BranchFixup &Fixup = EHStack.addBranchFixup(); - Fixup.Destination = Dest.getBlock(); - Fixup.DestinationIndex = Dest.getDestIndex(); - Fixup.InitialBranch = BI; - Fixup.OptimisticBranchBlock = 0; - - Builder.ClearInsertionPoint(); - return; - } - - // Otherwise, thread through all the normal cleanups in scope. - - // Store the index at the start. - llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); - new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI); - - // Adjust BI to point to the first cleanup block. - { - EHCleanupScope &Scope = - cast(*EHStack.find(TopCleanup)); - BI->setSuccessor(0, CreateNormalEntry(*this, Scope)); - } - - // Add this destination to all the scopes involved. - EHScopeStack::stable_iterator I = TopCleanup; - EHScopeStack::stable_iterator E = Dest.getScopeDepth(); - if (E.strictlyEncloses(I)) { - while (true) { - EHCleanupScope &Scope = cast(*EHStack.find(I)); - assert(Scope.isNormalCleanup()); - I = Scope.getEnclosingNormalCleanup(); - - // If this is the last cleanup we're propagating through, tell it - // that there's a resolved jump moving through it. - if (!E.strictlyEncloses(I)) { - Scope.addBranchAfter(Index, Dest.getBlock()); - break; - } - - // Otherwise, tell the scope that there's a jump propoagating - // through it. If this isn't new information, all the rest of - // the work has been done before. - if (!Scope.addBranchThrough(Dest.getBlock())) - break; - } - } - - Builder.ClearInsertionPoint(); -} - -void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) { - // We should never get invalid scope depths for an UnwindDest; that - // implies that the destination wasn't set up correctly. - assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?"); - - if (!HaveInsertPoint()) - return; - - // Create the branch. - llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); - - // Calculate the innermost active cleanup. - EHScopeStack::stable_iterator - InnermostCleanup = EHStack.getInnermostActiveEHCleanup(); - - // If the destination is in the same EH cleanup scope as us, we - // don't need to thread through anything. - if (InnermostCleanup.encloses(Dest.getScopeDepth())) { - Builder.ClearInsertionPoint(); - return; - } - assert(InnermostCleanup != EHStack.stable_end()); - - // Store the index at the start. - llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); - new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI); - - // Adjust BI to point to the first cleanup block. - { - EHCleanupScope &Scope = - cast(*EHStack.find(InnermostCleanup)); - BI->setSuccessor(0, CreateEHEntry(*this, Scope)); - } - - // Add this destination to all the scopes involved. - for (EHScopeStack::stable_iterator - I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) { - assert(E.strictlyEncloses(I)); - EHCleanupScope &Scope = cast(*EHStack.find(I)); - assert(Scope.isEHCleanup()); - I = Scope.getEnclosingEHCleanup(); - - // If this is the last cleanup we're propagating through, add this - // as a branch-after. - if (I == E) { - Scope.addEHBranchAfter(Index, Dest.getBlock()); - break; - } - - // Otherwise, add it as a branch-through. If this isn't new - // information, all the rest of the work has been done before. - if (!Scope.addEHBranchThrough(Dest.getBlock())) - break; - } - - Builder.ClearInsertionPoint(); -} - -/// All the branch fixups on the EH stack have propagated out past the -/// outermost normal cleanup; resolve them all by adding cases to the -/// given switch instruction. -static void ResolveAllBranchFixups(CodeGenFunction &CGF, - llvm::SwitchInst *Switch, - llvm::BasicBlock *CleanupEntry) { - llvm::SmallPtrSet CasesAdded; - - for (unsigned I = 0, E = CGF.EHStack.getNumBranchFixups(); I != E; ++I) { - // Skip this fixup if its destination isn't set. - BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I); - if (Fixup.Destination == 0) continue; - - // If there isn't an OptimisticBranchBlock, then InitialBranch is - // still pointing directly to its destination; forward it to the - // appropriate cleanup entry. This is required in the specific - // case of - // { std::string s; goto lbl; } - // lbl: - // i.e. where there's an unresolved fixup inside a single cleanup - // entry which we're currently popping. - if (Fixup.OptimisticBranchBlock == 0) { - new llvm::StoreInst(CGF.Builder.getInt32(Fixup.DestinationIndex), - CGF.getNormalCleanupDestSlot(), - Fixup.InitialBranch); - Fixup.InitialBranch->setSuccessor(0, CleanupEntry); - } - - // Don't add this case to the switch statement twice. - if (!CasesAdded.insert(Fixup.Destination)) continue; - - Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex), - Fixup.Destination); - } - - CGF.EHStack.clearFixups(); -} - -void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { - assert(Block && "resolving a null target block"); - if (!EHStack.getNumBranchFixups()) return; - - assert(EHStack.hasNormalCleanups() && - "branch fixups exist with no normal cleanups on stack"); - - llvm::SmallPtrSet ModifiedOptimisticBlocks; - bool ResolvedAny = false; - - for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) { - // Skip this fixup if its destination doesn't match. - BranchFixup &Fixup = EHStack.getBranchFixup(I); - if (Fixup.Destination != Block) continue; - - Fixup.Destination = 0; - ResolvedAny = true; - - // If it doesn't have an optimistic branch block, LatestBranch is - // already pointing to the right place. - llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock; - if (!BranchBB) - continue; - - // Don't process the same optimistic branch block twice. - if (!ModifiedOptimisticBlocks.insert(BranchBB)) - continue; - - llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB); - - // Add a case to the switch. - Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), Block); - } - - if (ResolvedAny) - EHStack.popNullFixups(); -} - -static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, - EHScopeStack::stable_iterator C) { - // If we needed a normal block for any reason, that counts. - if (cast(*EHStack.find(C)).getNormalBlock()) - return true; - - // Check whether any enclosed cleanups were needed. - for (EHScopeStack::stable_iterator - I = EHStack.getInnermostNormalCleanup(); - I != C; ) { - assert(C.strictlyEncloses(I)); - EHCleanupScope &S = cast(*EHStack.find(I)); - if (S.getNormalBlock()) return true; - I = S.getEnclosingNormalCleanup(); - } - - return false; -} - -static bool IsUsedAsEHCleanup(EHScopeStack &EHStack, - EHScopeStack::stable_iterator C) { - // If we needed an EH block for any reason, that counts. - if (cast(*EHStack.find(C)).getEHBlock()) - return true; - - // Check whether any enclosed cleanups were needed. - for (EHScopeStack::stable_iterator - I = EHStack.getInnermostEHCleanup(); I != C; ) { - assert(C.strictlyEncloses(I)); - EHCleanupScope &S = cast(*EHStack.find(I)); - if (S.getEHBlock()) return true; - I = S.getEnclosingEHCleanup(); - } - - return false; -} - -enum ForActivation_t { - ForActivation, - ForDeactivation -}; - -/// The given cleanup block is changing activation state. Configure a -/// cleanup variable if necessary. -/// -/// It would be good if we had some way of determining if there were -/// extra uses *after* the change-over point. -static void SetupCleanupBlockActivation(CodeGenFunction &CGF, - EHScopeStack::stable_iterator C, - ForActivation_t Kind) { - EHCleanupScope &Scope = cast(*CGF.EHStack.find(C)); - - // We always need the flag if we're activating the cleanup, because - // we have to assume that the current location doesn't necessarily - // dominate all future uses of the cleanup. - bool NeedFlag = (Kind == ForActivation); - - // Calculate whether the cleanup was used: - - // - as a normal cleanup - if (Scope.isNormalCleanup() && IsUsedAsNormalCleanup(CGF.EHStack, C)) { - Scope.setTestFlagInNormalCleanup(); - NeedFlag = true; - } - - // - as an EH cleanup - if (Scope.isEHCleanup() && IsUsedAsEHCleanup(CGF.EHStack, C)) { - Scope.setTestFlagInEHCleanup(); - NeedFlag = true; - } - - // If it hasn't yet been used as either, we're done. - if (!NeedFlag) return; - - llvm::AllocaInst *Var = Scope.getActiveFlag(); - if (!Var) { - Var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive"); - Scope.setActiveFlag(Var); - - // Initialize to true or false depending on whether it was - // active up to this point. - CGF.InitTempAlloca(Var, CGF.Builder.getInt1(Kind == ForDeactivation)); - } - - CGF.Builder.CreateStore(CGF.Builder.getInt1(Kind == ForActivation), Var); -} - -/// Activate a cleanup that was created in an inactivated state. -void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C) { - assert(C != EHStack.stable_end() && "activating bottom of stack?"); - EHCleanupScope &Scope = cast(*EHStack.find(C)); - assert(!Scope.isActive() && "double activation"); - - SetupCleanupBlockActivation(*this, C, ForActivation); - - Scope.setActive(true); -} - -/// Deactive a cleanup that was created in an active state. -void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C) { - assert(C != EHStack.stable_end() && "deactivating bottom of stack?"); - EHCleanupScope &Scope = cast(*EHStack.find(C)); - assert(Scope.isActive() && "double deactivation"); - - // If it's the top of the stack, just pop it. - if (C == EHStack.stable_begin()) { - // If it's a normal cleanup, we need to pretend that the - // fallthrough is unreachable. - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - PopCleanupBlock(); - Builder.restoreIP(SavedIP); - return; - } - - // Otherwise, follow the general case. - SetupCleanupBlockActivation(*this, C, ForDeactivation); - - Scope.setActive(false); -} - -llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() { - if (!NormalCleanupDest) - NormalCleanupDest = - CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); - return NormalCleanupDest; -} - -llvm::Value *CodeGenFunction::getEHCleanupDestSlot() { - if (!EHCleanupDest) - EHCleanupDest = - CreateTempAlloca(Builder.getInt32Ty(), "eh.cleanup.dest.slot"); - return EHCleanupDest; -} - void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init) { assert (Init && "Invalid DeclRefExpr initializer!"); From thakis at chromium.org Fri Jan 28 08:29:39 2011 From: thakis at chromium.org (Nico Weber) Date: Fri, 28 Jan 2011 08:29:39 -0800 Subject: [cfe-commits] [patch] Support -plugin-arg- with -add-plugin Message-ID: Hi, the attached patch makes -plugin-arg work with -add-plugin. On a related note, the plugin stuff doesn't seem to have any test coverage. What do you think about adding a test plugin that prints diagnostics in response to certain events? Then the normal test framework (expected-note etc) could be used to test plugins. Nico -------------- next part -------------- A non-text attachment was scrubbed... Name: clang-add-plugin-arg.patch Type: application/octet-stream Size: 2681 bytes Desc: not available URL: From carl.norum at apple.com Fri Jan 28 10:15:21 2011 From: carl.norum at apple.com (Carl Norum) Date: Fri, 28 Jan 2011 10:15:21 -0800 Subject: [cfe-commits] Building EFI with Clang on Mac OS X In-Reply-To: <68DAF2F3-1F63-4ACC-BAA1-03B286E754A8@apple.com> References: <68DAF2F3-1F63-4ACC-BAA1-03B286E754A8@apple.com> Message-ID: On Jan 27, 2011, at 12:02 PM, Carl Norum wrote: > Let me know what you think! > Any feedback from out there? If things look good, I guess I need a volunteer with commit privileges to commit these changes. -- Carl From benny.kra at googlemail.com Fri Jan 28 10:28:30 2011 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Fri, 28 Jan 2011 18:28:30 -0000 Subject: [cfe-commits] r124494 - /cfe/trunk/test/Driver/freebsd.c Message-ID: <20110128182830.519B02A6C12C@llvm.org> Author: d0k Date: Fri Jan 28 12:28:30 2011 New Revision: 124494 URL: http://llvm.org/viewvc/llvm-project?rev=124494&view=rev Log: Make the FreeBSD driver test more robust so it doesn't fail when there's a single lib32 path. Modified: cfe/trunk/test/Driver/freebsd.c Modified: cfe/trunk/test/Driver/freebsd.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/freebsd.c?rev=124494&r1=124493&r2=124494&view=diff ============================================================================== --- cfe/trunk/test/Driver/freebsd.c (original) +++ cfe/trunk/test/Driver/freebsd.c Fri Jan 28 12:28:30 2011 @@ -16,4 +16,4 @@ // RUN: %clang -ccc-host-triple x86_64-pc-freebsd8 -m32 -print-search-dirs %s > %t // RUN: FileCheck --check-prefix=CHECK-LIB32PATHS < %t %s // -// CHECK-LIB32PATHS: libraries: ={{.*}}:/usr/lib32 +// CHECK-LIB32PATHS: libraries: ={{.*:?}}/usr/lib32 From hhinnant at apple.com Fri Jan 28 12:00:37 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Fri, 28 Jan 2011 20:00:37 -0000 Subject: [cfe-commits] [libcxx] r124502 - in /libcxx/trunk: include/type_traits test/utilities/meta/meta.rel/is_base_of.pass.cpp test/utilities/meta/meta.rel/is_convertible.pass.cpp Message-ID: <20110128200037.93BAA2A6C12C@llvm.org> Author: hhinnant Date: Fri Jan 28 14:00:37 2011 New Revision: 124502 URL: http://llvm.org/viewvc/llvm-project?rev=124502&view=rev Log: minor corrections to test, and hook is_base_of up to clang intrinsic Modified: libcxx/trunk/include/type_traits libcxx/trunk/test/utilities/meta/meta.rel/is_base_of.pass.cpp libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=124502&r1=124501&r2=124502&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Fri Jan 28 14:00:37 2011 @@ -709,6 +709,14 @@ // is_base_of +#ifdef __clang__ + +template +struct _LIBCPP_VISIBLE is_base_of + : public integral_constant {}; + +#else // __clang__ + // (C) Copyright Rani Sharoni 2003. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -755,6 +763,8 @@ { }; +#endif // __clang__ + // is_empty template Modified: libcxx/trunk/test/utilities/meta/meta.rel/is_base_of.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.rel/is_base_of.pass.cpp?rev=124502&r1=124501&r2=124502&view=diff ============================================================================== --- libcxx/trunk/test/utilities/meta/meta.rel/is_base_of.pass.cpp (original) +++ libcxx/trunk/test/utilities/meta/meta.rel/is_base_of.pass.cpp Fri Jan 28 14:00:37 2011 @@ -46,5 +46,4 @@ test_is_not_base_of(); test_is_not_base_of(); test_is_not_base_of(); - test_is_not_base_of(); } Modified: libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp?rev=124502&r1=124501&r2=124502&view=diff ============================================================================== --- libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp (original) +++ libcxx/trunk/test/utilities/meta/meta.rel/is_convertible.pass.cpp Fri Jan 28 14:00:37 2011 @@ -70,8 +70,7 @@ static_assert((!std::is_convertible::value), ""); - static_assert((!std::is_convertible::value), ""); - static_assert((!std::is_convertible::value), ""); + static_assert(( std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); @@ -98,7 +97,6 @@ static_assert((!std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); - static_assert(( std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); @@ -185,7 +183,7 @@ static_assert((!std::is_convertible::value), ""); static_assert(( std::is_convertible::value), ""); static_assert((!std::is_convertible::value), ""); - static_assert((!std::is_convertible::value), ""); + static_assert(( std::is_convertible::value), ""); static_assert((!std::is_convertible::value), ""); static_assert((!std::is_convertible::value), ""); From hhinnant at apple.com Fri Jan 28 12:09:05 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Fri, 28 Jan 2011 15:09:05 -0500 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> Message-ID: <8929F4A5-B529-4AE0-B0F2-77B275D91D3E@apple.com> On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: > > On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: > >> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >> >>> AMDG >>> >>> The attached patch implements __is_base_of and __is_convertible_to. >>> These are the last intrinsics required to compile the header >>> that ships with MSVC 10.0. >>> >>> In Christ, >>> Steven Watanabe >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >> >> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. > > I've updated the patch and committed it as r124425. Thanks, Steven! I just hooked up is_base_of and believe I'm seeing some minor corner-case failures: struct B {}; struct B1 : B {}; struct B2 : B {}; struct D : private B1, private B2 {}; __is_base_of(B&, D&) answers true, but should be false. Rationale: B& and D& are not class types. __is_base_of(B[3], D[3]) answers true, but should be false. Rationale: B[3] and D[3] are not class types. __is_base_of(int, int) answers true, but should be false. Rationale: int is not a class type. Reference: [meta.rel] Table 50: > Base is a base class of Derived (10) without regard to cv-qualifiers or Base and Derived are not unions and name the same class type without regard to cv-qualifiers -Howard From rjmccall at apple.com Fri Jan 28 12:10:46 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 20:10:46 -0000 Subject: [cfe-commits] r124503 - /cfe/trunk/lib/CodeGen/CMakeLists.txt Message-ID: <20110128201046.C73DC2A6C12C@llvm.org> Author: rjmccall Date: Fri Jan 28 14:10:46 2011 New Revision: 124503 URL: http://llvm.org/viewvc/llvm-project?rev=124503&view=rev Log: Add my new file to the CMake lists, sorry about that. Modified: cfe/trunk/lib/CodeGen/CMakeLists.txt Modified: cfe/trunk/lib/CodeGen/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CMakeLists.txt?rev=124503&r1=124502&r2=124503&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CMakeLists.txt (original) +++ cfe/trunk/lib/CodeGen/CMakeLists.txt Fri Jan 28 14:10:46 2011 @@ -10,6 +10,7 @@ CGClass.cpp CGCXX.cpp CGCXXABI.cpp + CGCleanup.cpp CGDebugInfo.cpp CGDecl.cpp CGDeclCXX.cpp From rjmccall at apple.com Fri Jan 28 14:02:36 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 22:02:36 -0000 Subject: [cfe-commits] r124505 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/CXXInheritance.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/type-traits.cpp Message-ID: <20110128220236.9D87D2A6C12C@llvm.org> Author: rjmccall Date: Fri Jan 28 16:02:36 2011 New Revision: 124505 URL: http://llvm.org/viewvc/llvm-project?rev=124505&view=rev Log: Fix some corner cases in the __is_base_of logic. Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/lib/AST/CXXInheritance.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/SemaCXX/type-traits.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=124505&r1=124504&r2=124505&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Jan 28 16:02:36 2011 @@ -811,7 +811,7 @@ /// \param Base the base class we are searching for. /// /// \returns true if this class is derived from Base, false otherwise. - bool isDerivedFrom(CXXRecordDecl *Base) const; + bool isDerivedFrom(const CXXRecordDecl *Base) const; /// \brief Determine whether this class is derived from the type \p Base. /// @@ -829,7 +829,7 @@ /// /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than /// tangling input and output in \p Paths - bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const; + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; /// \brief Determine whether this class is virtually derived from /// the class \p Base. Modified: cfe/trunk/lib/AST/CXXInheritance.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXInheritance.cpp?rev=124505&r1=124504&r2=124505&view=diff ============================================================================== --- cfe/trunk/lib/AST/CXXInheritance.cpp (original) +++ cfe/trunk/lib/AST/CXXInheritance.cpp Fri Jan 28 16:02:36 2011 @@ -76,18 +76,21 @@ std::swap(DetectedVirtual, Other.DetectedVirtual); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, /*DetectVirtual=*/false); return isDerivedFrom(Base, Paths); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, + CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; Paths.setOrigin(const_cast(this)); - return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); + return lookupInBases(&FindBaseClass, + const_cast(Base->getCanonicalDecl()), + Paths); } bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const { Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124505&r1=124504&r2=124505&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 28 16:02:36 2011 @@ -2487,17 +2487,36 @@ "Cannot evaluate traits for dependent types."); switch(BTT) { - case BTT_IsBaseOf: + case BTT_IsBaseOf: { // C++0x [meta.rel]p2 - // Base is a base class of Derived without regard to cv-qualifiers or + // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. - if (Self.IsDerivedFrom(RhsT, LhsT) || - (!LhsT->isUnionType() && !RhsT->isUnionType() - && LhsT->getAsCXXRecordDecl() == RhsT->getAsCXXRecordDecl())) - return true; - return false; + const RecordType *lhsRecord = LhsT->getAs(); + if (!lhsRecord) return false; + + const RecordType *rhsRecord = RhsT->getAs(); + if (!rhsRecord) return false; + + assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) + == (lhsRecord == rhsRecord)); + + if (lhsRecord == rhsRecord) + return !lhsRecord->getDecl()->isUnion(); + + // C++0x [meta.rel]p2: + // If Base and Derived are class types and are different types + // (ignoring possible cv-qualifiers) then Derived shall be a + // complete type. + if (Self.RequireCompleteType(KeyLoc, RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + return cast(rhsRecord->getDecl()) + ->isDerivedFrom(cast(lhsRecord->getDecl())); + } + case BTT_TypeCompatible: return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), RhsT.getUnqualifiedType()); @@ -2560,19 +2579,7 @@ QualType LhsT = LhsTSInfo->getType(); QualType RhsT = RhsTSInfo->getType(); - if (BTT == BTT_IsBaseOf) { - // C++0x [meta.rel]p2 - // If Base and Derived are class types and are different types - // (ignoring possible cv-qualifiers) then Derived shall be a complete - // type. [] - CXXRecordDecl *LhsDecl = LhsT->getAsCXXRecordDecl(); - CXXRecordDecl *RhsDecl = RhsT->getAsCXXRecordDecl(); - if (!LhsT->isDependentType() && !RhsT->isDependentType() && - LhsDecl && RhsDecl && LhsT != RhsT && - RequireCompleteType(KWLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) - return ExprError(); - } else if (BTT == BTT_TypeCompatible) { + if (BTT == BTT_TypeCompatible) { if (getLangOptions().CPlusPlus) { Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus) << SourceRange(KWLoc, RParen); Modified: cfe/trunk/test/SemaCXX/type-traits.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=124505&r1=124504&r2=124505&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) +++ cfe/trunk/test/SemaCXX/type-traits.cpp Fri Jan 28 16:02:36 2011 @@ -469,6 +469,9 @@ int t[F(__is_base_of(Base, Derived))]; }; +template class DerivedTemp : Base {}; +template class NonderivedTemp {}; +template class UndefinedTemp; // expected-note {{declared here}} void is_base_of() { int t01[T(__is_base_of(Base, Derived))]; @@ -486,7 +489,14 @@ int t13[F(__is_base_of(Union, Union))]; int t14[T(__is_base_of(Empty, Empty))]; int t15[T(__is_base_of(class_forward, class_forward))]; - int t16[F(__is_base_of(Empty, class_forward))]; // expected-error {{incomplete type 'class_forward' used in type trait expression}} + int t16[F(__is_base_of(Empty, class_forward))]; // expected-error {{incomplete type 'class_forward' used in type trait expression}} + int t17[F(__is_base_of(Base&, Derived&))]; + int t18[F(__is_base_of(Base[10], Derived[10]))]; + int t19[F(__is_base_of(int, int))]; + int t20[F(__is_base_of(long, int))]; + int t21[T(__is_base_of(Base, DerivedTemp))]; + int t22[F(__is_base_of(Base, NonderivedTemp))]; + int t23[F(__is_base_of(Base, UndefinedTemp))]; // expected-error {{implicit instantiation of undefined template 'UndefinedTemp'}} isBaseOfT(); isBaseOfF(); From jyasskin at google.com Fri Jan 28 15:41:54 2011 From: jyasskin at google.com (Jeffrey Yasskin) Date: Fri, 28 Jan 2011 23:41:54 -0000 Subject: [cfe-commits] r124506 - /cfe/trunk/docs/InternalsManual.html Message-ID: <20110128234154.E79A72A6C12C@llvm.org> Author: jyasskin Date: Fri Jan 28 17:41:54 2011 New Revision: 124506 URL: http://llvm.org/viewvc/llvm-project?rev=124506&view=rev Log: Document how to add an attribute to clang. This should be reviewed by someone who actually knows how it works. Modified: cfe/trunk/docs/InternalsManual.html Modified: cfe/trunk/docs/InternalsManual.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/InternalsManual.html?rev=124506&r1=124505&r2=124506&view=diff ============================================================================== --- cfe/trunk/docs/InternalsManual.html (original) +++ cfe/trunk/docs/InternalsManual.html Fri Jan 28 17:41:54 2011 @@ -69,6 +69,11 @@
    • The Index Library
    • +
    • Howto guides + +
    @@ -1711,7 +1716,78 @@ + +

    How to change Clang

    + + + +

    How to add an attribute

    + + +

    To add an attribute, you'll have to add it to the list of attributes, add it +to the parsing phase, and look for it in the AST scan. +r124217 +has a good example of adding a warning attribute.

    + +

    (Beware that this hasn't been reviewed/fixed by the people who designed the +attributes system yet.)

    + +

    include/clang/Basic/Attr.td

    + +

    Each attribute gets a def inheriting from Attr or one of +its subclasses. InheritableAttr means that the attribute also applies +to subsequent declarations of the same name.

    + +

    Spellings lists the strings that can appear in +__attribute__((here)) or [[here]]. All such strings +will be synonymous. If you want to allow the [[]] C++0x +syntax, you have to define a list of Namespaces, which will +let users write [[namespace:spelling]]. Using the empty +string for a namespace will allow users to write just the spelling +with no ":".

    + +

    Subjects restricts what kinds of AST node to which this attribute +can appertain (roughly, attach).

    + +

    Args names the arguments the attribute takes, in order. If +Args is [StringArgument<"Arg1">, IntArgument<"Arg2">] +then __attribute__((myattribute("Hello", 3))) will be a valid use.

    + +

    Boilerplate

    + +

    Add an element to the AttributeList::Kind enum in include/clang/Sema/AttributeList.h +named AT_lower_with_underscores. That is, a CamelCased +AttributeName in Attr.td name should become +AT_attribute_name.

    + +

    Add a case to the StringSwitch in AttributeList::getKind() +in lib/Sema/AttributeList.cpp +for each spelling of your attribute. Less common attributes should come toward +the end of that list.

    + +

    Write a new HandleYourAttr() function in lib/Sema/SemaDeclAttr.cpp, +and add a case to the switch in ProcessNonInheritableDeclAttr() or +ProcessInheritableDeclAttr() forwarding to it.

    + +

    If your attribute causes extra warnings to fire, define a DiagGroup +in include/clang/Basic/DiagnosticGroups.td +named after the attribute's Spelling with "_"s replaced by "-"s. If +you're only defining one diagnostic, you can skip DiagnosticGroups.td +and use InGroup<DiagGroup<"your-attribute">> directly in DiagnosticSemaKinds.td

    + +

    The meat of your attribute

    + +

    Find an appropriate place in Clang to do whatever your attribute needs to do. +Check for the attribute's presence using Decl::getAttr<YourAttr>().

    +

    Update the Clang Language Extensions +document to describe your new attribute.

    From fjahanian at apple.com Fri Jan 28 15:42:29 2011 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 28 Jan 2011 23:42:29 -0000 Subject: [cfe-commits] r124507 - in /cfe/trunk: lib/CodeGen/CGCXX.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CGVTables.cpp test/CodeGenCXX/apple-kext-indirect-call-2.C Message-ID: <20110128234229.E58832A6C12C@llvm.org> Author: fjahanian Date: Fri Jan 28 17:42:29 2011 New Revision: 124507 URL: http://llvm.org/viewvc/llvm-project?rev=124507&view=rev Log: More work to support -fapple-kext regarding indirect vf calls and addition of extra entry at bottom of vtbls. Added: cfe/trunk/test/CodeGenCXX/apple-kext-indirect-call-2.C Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/CGVTables.cpp Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=124507&r1=124506&r2=124507&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCXX.cpp Fri Jan 28 17:42:29 2011 @@ -329,7 +329,9 @@ assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); MD = MD->getCanonicalDecl(); uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); - VTableIndex += 2; + uint64_t AddressPoint = + CGM.getVTables().getAddressPoint(BaseSubobject(RD, 0), RD); + VTableIndex += AddressPoint; llvm::Value *VFuncPtr = CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); return CGF.Builder.CreateLoad(VFuncPtr); Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124507&r1=124506&r2=124507&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 17:42:29 2011 @@ -195,6 +195,7 @@ Callee = BuildVirtualCall(MD, This, Ty); } else { if (getContext().getLangOptions().AppleKext && + MD->isVirtual() && ME->hasQualifier()) Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), This, Ty); else Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124507&r1=124506&r2=124507&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Jan 28 17:42:29 2011 @@ -2758,7 +2758,14 @@ // Add the VTable layout. uint64_t NumVTableComponents = Builder.getNumVTableComponents(); + // -fapple-kext adds an extra entry at end of vtbl. + bool IsAppleKext = CGM.getContext().getLangOptions().AppleKext; + if (IsAppleKext) + NumVTableComponents += 1; + uint64_t *LayoutData = new uint64_t[NumVTableComponents + 1]; + if (IsAppleKext) + LayoutData[NumVTableComponents] = 0; Entry.setPointer(LayoutData); // Store the number of components. Added: cfe/trunk/test/CodeGenCXX/apple-kext-indirect-call-2.C URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/apple-kext-indirect-call-2.C?rev=124507&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/apple-kext-indirect-call-2.C (added) +++ cfe/trunk/test/CodeGenCXX/apple-kext-indirect-call-2.C Fri Jan 28 17:42:29 2011 @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZTV1A = unnamed_addr constant [4 x i8*] [i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK1A3abcEv to i8*), i8* null] +// CHECK: @_ZTV4Base = unnamed_addr constant [4 x i8*] [i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK4Base3abcEv to i8*), i8* null] +// CHECK: @_ZTV8Derived2 = unnamed_addr constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK8Derived23efgEv to i8*), i8* null] +// CHECK: @_ZTV2D2 = unnamed_addr constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK2D23abcEv to i8*), i8* null] + +struct A { + virtual const char* abc(void) const; +}; + +const char* A::abc(void) const {return "A"; }; + +struct B : virtual A { + virtual void VF(); +}; + +void B::VF() {} + +void FUNC(B* p) { +// CHECK: [[T1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([4 x i8*]* @_ZTV1A to i8* (%struct.A*)**), i64 2) +// CHECK-NEXT: [[T2:%.*]] = call i8* [[T1]] + const char* c = p->A::abc(); +} + + +// Test2 +struct Base { virtual char* abc(void) const; }; + +char* Base::abc() const { return 0; } + +struct Derived : public Base { +}; + +void FUNC1(Derived* p) { +// CHECK: [[U1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([4 x i8*]* @_ZTV4Base to i8* (%struct.A*)**), i64 2) +// CHECK-NEXT: [[U2:%.*]] = call i8* [[U1]] + char* c = p->Base::abc(); +} + + +// Test3 +struct Base2 { }; + +struct Derived2 : virtual Base2 { + virtual char* efg(void) const; +}; + +char* Derived2::efg(void) const { return 0; } + +void FUNC2(Derived2* p) { +// CHECK: [[V1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([5 x i8*]* @_ZTV8Derived2 to i8* (%struct.A*)**), i64 3) +// CHECK-NEXT: [[V2:%.*]] = call i8* [[V1]] + char* c = p->Derived2::efg(); +} + +// Test4 +struct Base3 { }; + +struct D1 : virtual Base3 { +}; + +struct D2 : virtual Base3 { + virtual char *abc(void) const; +}; + +struct Sub : D1, D2 { +}; + +char* D2::abc(void) const { return 0; } + +void FUNC3(Sub* p) { +// CHECK: [[W1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([5 x i8*]* @_ZTV2D2 to i8* (%struct.A*)**), i64 3) +// CHECK-NEXT: [[W2:%.*]] = call i8* [[W1]] + char* c = p->D2::abc(); +} + From hhinnant at apple.com Fri Jan 28 15:46:28 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Fri, 28 Jan 2011 23:46:28 -0000 Subject: [cfe-commits] [libcxx] r124508 - in /libcxx/trunk: include/ test/containers/associative/map/map.access/ test/containers/associative/multimap/ test/containers/associative/multiset/ test/containers/associative/set/ test/containers/sequences/array/ test/containers/sequences/deque/ test/containers/sequences/forwardlist/forwardlist.iter/ test/containers/sequences/list/ test/containers/sequences/vector.bool/ test/containers/sequences/vector/ test/containers/unord/unord.map/ test/containers/unord/unord.multimap/ test/contain... Message-ID: <20110128234629.107432A6C12C@llvm.org> Author: hhinnant Date: Fri Jan 28 17:46:28 2011 New Revision: 124508 URL: http://llvm.org/viewvc/llvm-project?rev=124508&view=rev Log: Bug 9096 - list::iterator not default constructible Added: libcxx/trunk/test/containers/sequences/deque/iterators.pass.cpp libcxx/trunk/test/containers/sequences/list/iterators.pass.cpp libcxx/trunk/test/containers/sequences/vector.bool/iterators.pass.cpp libcxx/trunk/test/containers/sequences/vector/iterators.pass.cpp Modified: libcxx/trunk/include/list libcxx/trunk/test/containers/associative/map/map.access/iterator.pass.cpp libcxx/trunk/test/containers/associative/multimap/iterator.pass.cpp libcxx/trunk/test/containers/associative/multiset/iterator.pass.cpp libcxx/trunk/test/containers/associative/set/iterator.pass.cpp libcxx/trunk/test/containers/sequences/array/begin.pass.cpp libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp libcxx/trunk/test/containers/unord/unord.map/iterators.pass.cpp libcxx/trunk/test/containers/unord/unord.multimap/iterators.pass.cpp libcxx/trunk/test/containers/unord/unord.multiset/iterators.pass.cpp libcxx/trunk/test/containers/unord/unord.set/iterators.pass.cpp Modified: libcxx/trunk/include/list URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/list?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/include/list (original) +++ libcxx/trunk/include/list Fri Jan 28 17:46:28 2011 @@ -237,6 +237,8 @@ typedef typename pointer_traits::difference_type difference_type; _LIBCPP_INLINE_VISIBILITY + __list_iterator() {} + _LIBCPP_INLINE_VISIBILITY reference operator*() const {return __ptr_->__value_;} _LIBCPP_INLINE_VISIBILITY pointer operator->() const {return &(operator*());} @@ -290,6 +292,8 @@ typedef typename pointer_traits::difference_type difference_type; _LIBCPP_INLINE_VISIBILITY + __list_const_iterator() {} + _LIBCPP_INLINE_VISIBILITY __list_const_iterator(__list_iterator<_Tp, _VoidPtr> __p) : __ptr_(__p.__ptr_) {} _LIBCPP_INLINE_VISIBILITY Modified: libcxx/trunk/test/containers/associative/map/map.access/iterator.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/associative/map/map.access/iterator.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/associative/map/map.access/iterator.pass.cpp (original) +++ libcxx/trunk/test/containers/associative/map/map.access/iterator.pass.cpp Fri Jan 28 17:46:28 2011 @@ -63,7 +63,8 @@ std::map m(ar, ar+sizeof(ar)/sizeof(ar[0])); assert(std::distance(m.begin(), m.end()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); - std::map::iterator i = m.begin(); + std::map::iterator i; + i = m.begin(); std::map::const_iterator k = i; assert(i == k); for (int j = 1; j <= m.size(); ++j, ++i) @@ -108,7 +109,8 @@ assert(std::distance(m.cbegin(), m.cend()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); assert(std::distance(m.crbegin(), m.crend()) == m.size()); - std::map::const_iterator i = m.begin(); + std::map::const_iterator i; + i = m.begin(); for (int j = 1; j <= m.size(); ++j, ++i) { assert(i->first == j); Modified: libcxx/trunk/test/containers/associative/multimap/iterator.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/associative/multimap/iterator.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/associative/multimap/iterator.pass.cpp (original) +++ libcxx/trunk/test/containers/associative/multimap/iterator.pass.cpp Fri Jan 28 17:46:28 2011 @@ -63,7 +63,8 @@ std::multimap m(ar, ar+sizeof(ar)/sizeof(ar[0])); assert(std::distance(m.begin(), m.end()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); - std::multimap::iterator i = m.begin(); + std::multimap::iterator i; + i = m.begin(); std::multimap::const_iterator k = i; assert(i == k); for (int j = 1; j <= 8; ++j) @@ -109,7 +110,8 @@ assert(std::distance(m.cbegin(), m.cend()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); assert(std::distance(m.crbegin(), m.crend()) == m.size()); - std::multimap::const_iterator i = m.begin(); + std::multimap::const_iterator i; + i = m.begin(); for (int j = 1; j <= 8; ++j) for (double d = 1; d <= 2; d += .5, ++i) { Modified: libcxx/trunk/test/containers/associative/multiset/iterator.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/associative/multiset/iterator.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/associative/multiset/iterator.pass.cpp (original) +++ libcxx/trunk/test/containers/associative/multiset/iterator.pass.cpp Fri Jan 28 17:46:28 2011 @@ -63,7 +63,8 @@ std::multiset m(ar, ar+sizeof(ar)/sizeof(ar[0])); assert(std::distance(m.begin(), m.end()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); - std::multiset::iterator i = m.begin(); + std::multiset::iterator i; + i = m.begin(); std::multiset::const_iterator k = i; assert(i == k); for (int j = 1; j <= 8; ++j) @@ -104,7 +105,8 @@ assert(std::distance(m.cbegin(), m.cend()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); assert(std::distance(m.crbegin(), m.crend()) == m.size()); - std::multiset::const_iterator i = m.begin(); + std::multiset::const_iterator i; + i = m.begin(); for (int j = 1; j <= 8; ++j) for (int k = 0; k < 3; ++k, ++i) assert(*i == j); Modified: libcxx/trunk/test/containers/associative/set/iterator.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/associative/set/iterator.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/associative/set/iterator.pass.cpp (original) +++ libcxx/trunk/test/containers/associative/set/iterator.pass.cpp Fri Jan 28 17:46:28 2011 @@ -63,7 +63,8 @@ std::set m(ar, ar+sizeof(ar)/sizeof(ar[0])); assert(std::distance(m.begin(), m.end()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); - std::set::iterator i = m.begin(); + std::set::iterator i; + i = m.begin(); std::set::const_iterator k = i; assert(i == k); for (int j = 1; j <= m.size(); ++j, ++i) @@ -103,7 +104,8 @@ assert(std::distance(m.cbegin(), m.cend()) == m.size()); assert(std::distance(m.rbegin(), m.rend()) == m.size()); assert(std::distance(m.crbegin(), m.crend()) == m.size()); - std::set::const_iterator i = m.begin(); + std::set::const_iterator i; + i = m.begin(); for (int j = 1; j <= m.size(); ++j, ++i) assert(*i == j); } Modified: libcxx/trunk/test/containers/sequences/array/begin.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/array/begin.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/sequences/array/begin.pass.cpp (original) +++ libcxx/trunk/test/containers/sequences/array/begin.pass.cpp Fri Jan 28 17:46:28 2011 @@ -20,7 +20,8 @@ typedef double T; typedef std::array C; C c = {1, 2, 3.5}; - C::iterator i = c.begin(); + C::iterator i; + i = c.begin(); assert(*i == 1); assert(&*i == c.data()); *i = 5.5; Added: libcxx/trunk/test/containers/sequences/deque/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/deque/iterators.pass.cpp?rev=124508&view=auto ============================================================================== --- libcxx/trunk/test/containers/sequences/deque/iterators.pass.cpp (added) +++ libcxx/trunk/test/containers/sequences/deque/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// Test nested types and default template args: + +// template > +// class deque; + +// iterator, const_iterator + +#include +#include +#include + +int main() +{ + typedef std::deque C; + C c; + C::iterator i; + i = c.begin(); + C::const_iterator j; + j = c.cbegin(); + assert(i == j); +} Modified: libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp (original) +++ libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -67,5 +67,6 @@ typedef int T; typedef std::forward_list C; C::iterator i; + C::const_iterator j; } } Added: libcxx/trunk/test/containers/sequences/list/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/list/iterators.pass.cpp?rev=124508&view=auto ============================================================================== --- libcxx/trunk/test/containers/sequences/list/iterators.pass.cpp (added) +++ libcxx/trunk/test/containers/sequences/list/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// iterator begin(); +// iterator end(); +// const_iterator begin() const; +// const_iterator end() const; +// const_iterator cbegin() const; +// const_iterator cend() const; + +#include +#include +#include + +int main() +{ + { + typedef int T; + typedef std::list C; + C c; + C::iterator i = c.begin(); + C::iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef int T; + typedef std::list C; + const C c; + C::const_iterator i = c.begin(); + C::const_iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef int T; + typedef std::list C; + C c; + C::const_iterator i = c.cbegin(); + C::const_iterator j = c.cend(); + assert(std::distance(i, j) == 0); + assert(i == j); + assert(i == c.end()); + } + { + typedef int T; + typedef std::list C; + const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + C c(std::begin(t), std::end(t)); + C::iterator i = c.begin(); + assert(*i == 0); + ++i; + assert(*i == 1); + *i = 10; + assert(*i == 10); + assert(std::distance(c.begin(), c.end()) == 10); + } + { + typedef int T; + typedef std::list C; + C::iterator i; + C::const_iterator j; + } +} Added: libcxx/trunk/test/containers/sequences/vector.bool/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/vector.bool/iterators.pass.cpp?rev=124508&view=auto ============================================================================== --- libcxx/trunk/test/containers/sequences/vector.bool/iterators.pass.cpp (added) +++ libcxx/trunk/test/containers/sequences/vector.bool/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// iterator begin(); +// iterator end(); +// const_iterator begin() const; +// const_iterator end() const; +// const_iterator cbegin() const; +// const_iterator cend() const; + +#include +#include +#include + +int main() +{ + { + typedef bool T; + typedef std::vector C; + C c; + C::iterator i = c.begin(); + C::iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef bool T; + typedef std::vector C; + const C c; + C::const_iterator i = c.begin(); + C::const_iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef bool T; + typedef std::vector C; + C c; + C::const_iterator i = c.cbegin(); + C::const_iterator j = c.cend(); + assert(std::distance(i, j) == 0); + assert(i == j); + assert(i == c.end()); + } + { + typedef bool T; + typedef std::vector C; + C::iterator i; + C::const_iterator j; + } +} Added: libcxx/trunk/test/containers/sequences/vector/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/vector/iterators.pass.cpp?rev=124508&view=auto ============================================================================== --- libcxx/trunk/test/containers/sequences/vector/iterators.pass.cpp (added) +++ libcxx/trunk/test/containers/sequences/vector/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// iterator begin(); +// iterator end(); +// const_iterator begin() const; +// const_iterator end() const; +// const_iterator cbegin() const; +// const_iterator cend() const; + +#include +#include +#include + +int main() +{ + { + typedef int T; + typedef std::vector C; + C c; + C::iterator i = c.begin(); + C::iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef int T; + typedef std::vector C; + const C c; + C::const_iterator i = c.begin(); + C::const_iterator j = c.end(); + assert(std::distance(i, j) == 0); + assert(i == j); + } + { + typedef int T; + typedef std::vector C; + C c; + C::const_iterator i = c.cbegin(); + C::const_iterator j = c.cend(); + assert(std::distance(i, j) == 0); + assert(i == j); + assert(i == c.end()); + } + { + typedef int T; + typedef std::vector C; + const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + C c(std::begin(t), std::end(t)); + C::iterator i = c.begin(); + assert(*i == 0); + ++i; + assert(*i == 1); + *i = 10; + assert(*i == 10); + assert(std::distance(c.begin(), c.end()) == 10); + } + { + typedef int T; + typedef std::vector C; + C::iterator i; + C::const_iterator j; + } +} Modified: libcxx/trunk/test/containers/unord/unord.map/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/unord/unord.map/iterators.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/unord/unord.map/iterators.pass.cpp (original) +++ libcxx/trunk/test/containers/unord/unord.map/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -43,6 +43,7 @@ assert(c.size() == 4); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::iterator i; } { typedef std::unordered_map C; @@ -61,5 +62,6 @@ assert(c.size() == 4); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::const_iterator i; } } Modified: libcxx/trunk/test/containers/unord/unord.multimap/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/unord/unord.multimap/iterators.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/unord/unord.multimap/iterators.pass.cpp (original) +++ libcxx/trunk/test/containers/unord/unord.multimap/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -43,7 +43,8 @@ assert(c.size() == 6); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); - C::iterator i = c.begin(); + C::iterator i; + i = c.begin(); i->second = "ONE"; assert(i->second == "ONE"); } @@ -64,5 +65,6 @@ assert(c.size() == 6); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::const_iterator i; } } Modified: libcxx/trunk/test/containers/unord/unord.multiset/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/unord/unord.multiset/iterators.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/unord/unord.multiset/iterators.pass.cpp (original) +++ libcxx/trunk/test/containers/unord/unord.multiset/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -42,6 +42,7 @@ assert(c.size() == 6); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::iterator i; } { typedef std::unordered_multiset C; @@ -60,5 +61,6 @@ assert(c.size() == 6); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::const_iterator i; } } Modified: libcxx/trunk/test/containers/unord/unord.set/iterators.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/unord/unord.set/iterators.pass.cpp?rev=124508&r1=124507&r2=124508&view=diff ============================================================================== --- libcxx/trunk/test/containers/unord/unord.set/iterators.pass.cpp (original) +++ libcxx/trunk/test/containers/unord/unord.set/iterators.pass.cpp Fri Jan 28 17:46:28 2011 @@ -42,6 +42,7 @@ assert(c.size() == 4); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::iterator i; } { typedef std::unordered_set C; @@ -60,5 +61,6 @@ assert(c.size() == 4); assert(std::distance(c.begin(), c.end()) == c.size()); assert(std::distance(c.cbegin(), c.cend()) == c.size()); + C::const_iterator i; } } From rjmccall at apple.com Fri Jan 28 17:25:32 2011 From: rjmccall at apple.com (John McCall) Date: Fri, 28 Jan 2011 17:25:32 -0800 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <8929F4A5-B529-4AE0-B0F2-77B275D91D3E@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> <8929F4A5-B529-4AE0-B0F2-77B275D91D3E@apple.com> Message-ID: <708D98FC-1FB8-4148-84FF-FEDD608A34EA@apple.com> On Jan 28, 2011, at 12:09 PM, Howard Hinnant wrote: > On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: >> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: >>> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >>>> AMDG >>>> >>>> The attached patch implements __is_base_of and __is_convertible_to. >>>> These are the last intrinsics required to compile the header >>>> that ships with MSVC 10.0. >>>> >>>> In Christ, >>>> Steven Watanabe >>>> >>>> _______________________________________________ >>>> cfe-commits mailing list >>>> cfe-commits at cs.uiuc.edu >>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>> >>> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. >> >> I've updated the patch and committed it as r124425. Thanks, Steven! > > I just hooked up is_base_of and believe I'm seeing some minor corner-case failures: In case you didn't see this, r124505 should fix these cases for you. John. From hhinnant at apple.com Fri Jan 28 17:26:14 2011 From: hhinnant at apple.com (Howard Hinnant) Date: Fri, 28 Jan 2011 20:26:14 -0500 Subject: [cfe-commits] [Patch review request] Binary type traits In-Reply-To: <708D98FC-1FB8-4148-84FF-FEDD608A34EA@apple.com> References: <4C93F2F0.8070508@providere-consulting.com> <23EB9DD3-7E28-4FD6-B6BC-01D709C79A67@apple.com> <8929F4A5-B529-4AE0-B0F2-77B275D91D3E@apple.com> <708D98FC-1FB8-4148-84FF-FEDD608A34EA@apple.com> Message-ID: On Jan 28, 2011, at 8:25 PM, John McCall wrote: > On Jan 28, 2011, at 12:09 PM, Howard Hinnant wrote: >> On Jan 27, 2011, at 3:31 PM, Douglas Gregor wrote: >>> On Jan 27, 2011, at 10:13 AM, Howard Hinnant wrote: >>>> On Sep 17, 2010, at 7:00 PM, Steven Watanabe wrote: >>>>> AMDG >>>>> >>>>> The attached patch implements __is_base_of and __is_convertible_to. >>>>> These are the last intrinsics required to compile the header >>>>> that ships with MSVC 10.0. >>>>> >>>>> In Christ, >>>>> Steven Watanabe >>>>> >>>>> _______________________________________________ >>>>> cfe-commits mailing list >>>>> cfe-commits at cs.uiuc.edu >>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>>> >>>> Ping. What is the status of this patch? libc++ is in desperate need of __is_convertible_to. >>> >>> I've updated the patch and committed it as r124425. Thanks, Steven! >> >> I just hooked up is_base_of and believe I'm seeing some minor corner-case failures: > > In case you didn't see this, r124505 should fix these cases for you. > > John. Saw it. Thanks much John. -Howard From andersca at mac.com Fri Jan 28 19:18:56 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 03:18:56 -0000 Subject: [cfe-commits] r124523 - in /cfe/trunk: lib/CodeGen/CGClass.cpp test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp Message-ID: <20110129031856.540C92A6C12C@llvm.org> Author: andersca Date: Fri Jan 28 21:18:56 2011 New Revision: 124523 URL: http://llvm.org/viewvc/llvm-project?rev=124523&view=rev Log: When doing a derived-to-base class through a virtual class, we don't have to get the vbase offset from the vtable if the derived class is marked final. Added: cfe/trunk/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp Modified: cfe/trunk/lib/CodeGen/CGClass.cpp Modified: cfe/trunk/lib/CodeGen/CGClass.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=124523&r1=124522&r2=124523&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) +++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri Jan 28 21:18:56 2011 @@ -180,8 +180,17 @@ llvm::Value *VirtualOffset = 0; - if (VBase) - VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); + if (VBase) { + if (Derived->hasAttr()) { + VirtualOffset = 0; + + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); + + uint64_t VBaseOffset = Layout.getVBaseClassOffsetInBits(VBase); + NonVirtualOffset += VBaseOffset / 8; + } else + VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); + } // Apply the offsets. Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, Added: cfe/trunk/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp?rev=124523&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp (added) +++ cfe/trunk/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp Fri Jan 28 21:18:56 2011 @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { int i; }; +struct B { int j; }; +struct C : A, B { int k; }; + +struct D final : virtual C { + D(); + virtual void f(); +}; + +// CHECK: define %struct.B* @_Z1fR1D +B &f(D &d) { + // CHECK-NOT: load i8** + return d; +} From andersca at mac.com Fri Jan 28 19:52:02 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 03:52:02 -0000 Subject: [cfe-commits] r124524 - in /cfe/trunk: lib/CodeGen/CGExprCXX.cpp test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Message-ID: <20110129035202.1E4F72A6C12C@llvm.org> Author: andersca Date: Fri Jan 28 21:52:01 2011 New Revision: 124524 URL: http://llvm.org/viewvc/llvm-project?rev=124524&view=rev Log: When calling a virtual member function on a base class and the most derived class is marked 'final', we can devirtualize the call. Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124524&r1=124523&r2=124524&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 21:52:01 2011 @@ -53,16 +53,39 @@ Callee, ReturnValue, Args, MD); } +static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { + QualType DerivedType = Base->IgnoreParenCasts()->getType(); + if (const PointerType *PTy = DerivedType->getAs()) + DerivedType = PTy->getPointeeType(); + + return cast(DerivedType->castAs()->getDecl()); +} + /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, const Expr *Base, const CXXMethodDecl *MD) { - // Cannot divirtualize in kext mode. + // When building with -fapple-kext, all calls must go through the vtable since + // the kernel linker can do runtime patching of vtables. if (Context.getLangOptions().AppleKext) return false; + // If the most derived class is marked final, we know that no subclass can + // override this member function and so we can devirtualize it. For example: + // + // struct A { virtual void f(); } + // struct B final : A { }; + // + // void f(B *b) { + // b->f(); + // } + // + const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base); + if (MostDerivedClassDecl->hasAttr()) + return true; + // If the member function is marked 'final', we know that it can't be // overridden and can therefore devirtualize it. if (MD->hasAttr()) Modified: cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp?rev=124524&r1=124523&r2=124524&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp (original) +++ cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Fri Jan 28 21:52:01 2011 @@ -23,3 +23,17 @@ return a->f(); } } + +namespace Test3 { + struct A { + virtual int f(); + }; + + struct B final : A { }; + + // CHECK: define i32 @_ZN5Test31fEPNS_1BE + int f(B *b) { + // CHECK: call i32 @_ZN5Test31A1fEv + return b->f(); + } +} From andersca at mac.com Fri Jan 28 21:04:11 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 05:04:11 -0000 Subject: [cfe-commits] r124528 - in /cfe/trunk: lib/CodeGen/CGExprCXX.cpp test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Message-ID: <20110129050411.3D7E02A6C12D@llvm.org> Author: andersca Date: Fri Jan 28 23:04:11 2011 New Revision: 124528 URL: http://llvm.org/viewvc/llvm-project?rev=124528&view=rev Log: When trying to get the most derived class, don't assume that we can ignore all casts. We can only ignore derived-to-base and no-op casts. Fixes selfhost. Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124528&r1=124527&r2=124528&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 23:04:11 2011 @@ -54,7 +54,23 @@ } static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { - QualType DerivedType = Base->IgnoreParenCasts()->getType(); + const Expr *E = Base; + + while (true) { + E = E->IgnoreParens(); + if (const CastExpr *CE = dyn_cast(E)) { + if (CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + + break; + } + + QualType DerivedType = E->getType(); if (const PointerType *PTy = DerivedType->getAs()) DerivedType = PTy->getPointeeType(); Modified: cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp?rev=124528&r1=124527&r2=124528&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp (original) +++ cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Fri Jan 28 23:04:11 2011 @@ -36,4 +36,16 @@ // CHECK: call i32 @_ZN5Test31A1fEv return b->f(); } + + // CHECK: define i32 @_ZN5Test31fERNS_1BE + int f(B &b) { + // CHECK: call i32 @_ZN5Test31A1fEv + return b.f(); + } + + // CHECK: define i32 @_ZN5Test31fEPv + int f(void *v) { + // CHECK: call i32 @_ZN5Test31A1fEv + return static_cast(v)->f(); + } } From andersca at mac.com Fri Jan 28 21:26:32 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 05:26:32 -0000 Subject: [cfe-commits] r124529 - in /cfe/trunk/lib/CodeGen: CGRTTI.cpp CGVTables.cpp CodeGenModule.cpp CodeGenModule.h Message-ID: <20110129052632.BFB142A6C12C@llvm.org> Author: andersca Date: Fri Jan 28 23:26:32 2011 New Revision: 124529 URL: http://llvm.org/viewvc/llvm-project?rev=124529&view=rev Log: Remove IsDefinition from CodeGenModule::setTypeVisibility; it is always true. Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124529&r1=124528&r2=124529&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Fri Jan 28 23:26:32 2011 @@ -644,7 +644,7 @@ // compatibility. if (const RecordType *RT = dyn_cast(Ty)) CGM.setTypeVisibility(GV, cast(RT->getDecl()), - /*ForRTTI*/ true, /*ForDefinition*/ true); + /*ForRTTI=*/true); else if (Hidden || (CGM.getCodeGenOpts().HiddenWeakVTables && Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124529&r1=124528&r2=124529&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Jan 28 23:26:32 2011 @@ -3019,7 +3019,7 @@ VTable->setLinkage(Linkage); // Set the right visibility. - CGM.setTypeVisibility(VTable, RD, /*ForRTTI*/ false, /*ForDef*/ true); + CGM.setTypeVisibility(VTable, RD, /*ForRTTI=*/false); } llvm::GlobalVariable * Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124529&r1=124528&r2=124529&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan 28 23:26:32 2011 @@ -195,9 +195,8 @@ /// associated with the given type. void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *RD, - bool IsForRTTI, - bool IsForDefinition) const { - setGlobalVisibility(GV, RD, IsForDefinition); + bool IsForRTTI) const { + setGlobalVisibility(GV, RD, /*IsForDefinition=*/true); if (!CodeGenOpts.HiddenWeakVTables) return; Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=124529&r1=124528&r2=124529&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Jan 28 23:26:32 2011 @@ -265,7 +265,7 @@ /// setTypeVisibility - Set the visibility for the given global /// value which holds information about a type. void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, - bool IsForRTTI, bool IsForDefinition) const; + bool IsForRTTI) const; llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) From jyasskin at gmail.com Sat Jan 29 01:51:12 2011 From: jyasskin at gmail.com (jyasskin at gmail.com) Date: Sat, 29 Jan 2011 09:51:12 +0000 Subject: [cfe-commits] Add gTest unittests to clang, and write the first one. (issue4063046) Message-ID: <001636e1e9e97ca5ff049af91f9a@google.com> Reviewers: daniel_zuster.org, Message: Please take a look. Description: This doesn't include the cmake build steps, but it should let us start writing library-based tests with the plain makefiles. Please review this at http://codereview.appspot.com/4063046/ Affected files: M Makefile M test/Makefile A test/Unit/lit.cfg A test/Unit/lit.site.cfg.in A unittests/Frontend/FrontendActionTest.cpp A unittests/Frontend/Makefile A unittests/Makefile From 5591boy at gmail.com Sat Jan 29 02:18:48 2011 From: 5591boy at gmail.com (5591boy at gmail.com) Date: Sat, 29 Jan 2011 10:18:48 +0000 Subject: [cfe-commits] Add gTest unittests to clang, and write the first one. (issue4063046) Message-ID: <90e6ba6e8eb034f2f8049af982f4@google.com> On 2011/01/29 09:51:12, Jeffrey Yasskin wrote: > Please take a look. http://codereview.appspot.com/4063046/ From kd at kendyck.com Sat Jan 29 09:53:12 2011 From: kd at kendyck.com (Ken Dyck) Date: Sat, 29 Jan 2011 17:53:12 -0000 Subject: [cfe-commits] r124536 - /cfe/trunk/lib/CodeGen/CodeGenModule.cpp Message-ID: <20110129175312.4F6E02A6C12C@llvm.org> Author: kjdyck Date: Sat Jan 29 11:53:12 2011 New Revision: 124536 URL: http://llvm.org/viewvc/llvm-project?rev=124536&view=rev Log: Replace a literal '8' with getCharWidth(). Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124536&r1=124535&r2=124536&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 11:53:12 2011 @@ -1717,15 +1717,16 @@ /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { + const ASTContext &Context = getContext(); const ConstantArrayType *CAT = - getContext().getAsConstantArrayType(E->getType()); + Context.getAsConstantArrayType(E->getType()); assert(CAT && "String isn't pointer or array!"); // Resize the string to the right size. uint64_t RealLen = CAT->getSize().getZExtValue(); if (E->isWide()) - RealLen *= getContext().Target.getWCharWidth()/8; + RealLen *= Context.Target.getWCharWidth() / Context.getCharWidth(); std::string Str = E->getString().str(); Str.resize(RealLen, '\0'); From andersca at mac.com Sat Jan 29 10:20:20 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 18:20:20 -0000 Subject: [cfe-commits] r124537 - in /cfe/trunk/lib/CodeGen: CodeGenModule.cpp CodeGenModule.h Message-ID: <20110129182020.411E32A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 12:20:20 2011 New Revision: 124537 URL: http://llvm.org/viewvc/llvm-project?rev=124537&view=rev Log: Add a new function, to be used by CGRTTI, CGVTables and CGVTT (which each has their own copy of this code). Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124537&r1=124536&r2=124537&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 12:20:20 2011 @@ -985,6 +985,45 @@ } +llvm::GlobalVariable * +CodeGenModule::CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, + const llvm::Type *Ty, + llvm::GlobalValue::LinkageTypes Linkage) { + llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name); + llvm::GlobalVariable *OldGV = 0; + + + if (GV) { + // Check if the variable has the right type. + if (GV->getType()->getElementType() == Ty) + return GV; + + // Because C++ name mangling, the only way we can end up with an already + // existing global with the same name is if it has been declared extern "C". + assert(GV->isDeclaration() && "Declaration has wrong type!"); + OldGV = GV; + } + + // Create a new variable. + GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true, + Linkage, 0, Name); + + if (OldGV) { + // Replace occurrences of the old variable if needed. + GV->takeName(OldGV); + + if (!OldGV->use_empty()) { + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); + } + + OldGV->eraseFromParent(); + } + + return GV; +} + /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=124537&r1=124536&r2=124537&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sat Jan 29 12:20:20 2011 @@ -280,6 +280,14 @@ return GetAddrOfGlobalVar(cast(GD.getDecl())); } + /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the given + /// type. If a variable with a different type already exists then a new + /// variable with the right type will be created and all uses of the old + /// variable will be replaced with a bitcast to the new variable. + llvm::GlobalVariable * + CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, const llvm::Type *Ty, + llvm::GlobalValue::LinkageTypes Linkage); + /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the From andersca at mac.com Sat Jan 29 10:25:07 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 18:25:07 -0000 Subject: [cfe-commits] r124538 - in /cfe/trunk/lib/CodeGen: CGVTables.cpp CodeGenModule.cpp Message-ID: <20110129182507.452C82A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 12:25:07 2011 New Revision: 124538 URL: http://llvm.org/viewvc/llvm-project?rev=124538&view=rev Log: Use CGM.CreateOrReplaceCXXRuntimeVariable in CGVTables.cpp Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124538&r1=124537&r2=124538&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sat Jan 29 12:25:07 2011 @@ -2932,49 +2932,6 @@ return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size()); } -/// GetGlobalVariable - Will return a global variable of the given type. -/// If a variable with a different type already exists then a new variable -/// with the right type will be created. -/// FIXME: We should move this to CodeGenModule and rename it to something -/// better and then use it in CGVTT and CGRTTI. -static llvm::GlobalVariable * -GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, - const llvm::Type *Ty, - llvm::GlobalValue::LinkageTypes Linkage) { - - llvm::GlobalVariable *GV = Module.getNamedGlobal(Name); - llvm::GlobalVariable *OldGV = 0; - - if (GV) { - // Check if the variable has the right type. - if (GV->getType()->getElementType() == Ty) - return GV; - - assert(GV->isDeclaration() && "Declaration has wrong type!"); - - OldGV = GV; - } - - // Create a new variable. - GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true, - Linkage, 0, Name); - - if (OldGV) { - // Replace occurrences of the old variable if needed. - GV->takeName(OldGV); - - if (!OldGV->use_empty()) { - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); - } - - OldGV->eraseFromParent(); - } - - return GV; -} - llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { llvm::SmallString<256> OutName; CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, OutName); @@ -2987,8 +2944,8 @@ llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD)); llvm::GlobalVariable *GV = - GetGlobalVariable(CGM.getModule(), Name, ArrayType, - llvm::GlobalValue::ExternalLinkage); + CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, + llvm::GlobalValue::ExternalLinkage); GV->setUnnamedAddr(true); return GV; } @@ -3050,8 +3007,8 @@ // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = - GetGlobalVariable(CGM.getModule(), Name, ArrayType, - llvm::GlobalValue::InternalLinkage); + CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, + llvm::GlobalValue::InternalLinkage); // Add the thunks. VTableThunksTy VTableThunks; Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124538&r1=124537&r2=124538&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 12:25:07 2011 @@ -1000,7 +1000,7 @@ // Because C++ name mangling, the only way we can end up with an already // existing global with the same name is if it has been declared extern "C". - assert(GV->isDeclaration() && "Declaration has wrong type!"); + assert(GV->isDeclaration() && "Declaration has wrong type!"); OldGV = GV; } From andersca at mac.com Sat Jan 29 11:16:52 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 19:16:52 -0000 Subject: [cfe-commits] r124539 - in /cfe/trunk: lib/CodeGen/CGClass.cpp lib/CodeGen/CGRTTI.cpp lib/CodeGen/CGVTT.cpp lib/CodeGen/CGVTables.cpp lib/CodeGen/CGVTables.h test/CodeGenCXX/mangle-subst-std.cpp Message-ID: <20110129191652.280AF2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 13:16:51 2011 New Revision: 124539 URL: http://llvm.org/viewvc/llvm-project?rev=124539&view=rev Log: Make emitting a VTT a two-step process, much like emitting a VTable. You first get the address of the VTT, and then pass it to EmitVTTDefinition. Modified: cfe/trunk/lib/CodeGen/CGClass.cpp cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/lib/CodeGen/CGVTT.cpp cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CGVTables.h cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Modified: cfe/trunk/lib/CodeGen/CGClass.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sat Jan 29 13:16:51 2011 @@ -318,7 +318,7 @@ VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); } else { // We're the complete constructor, so get the VTT by name. - VTT = CGF.CGM.getVTables().getVTT(RD); + VTT = CGF.CGM.getVTables().GetAddrOfVTT(RD); VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); } Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sat Jan 29 13:16:51 2011 @@ -522,7 +522,7 @@ llvm::SmallString<256> OutName; CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); - + llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); if (OldGV && !OldGV->isDeclaration()) return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); Modified: cfe/trunk/lib/CodeGen/CGVTT.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTT.cpp?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTT.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTT.cpp Sat Jan 29 13:16:51 2011 @@ -366,58 +366,47 @@ } -llvm::GlobalVariable * -CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD) { - // Only classes that have virtual bases need a VTT. - if (RD->getNumVBases() == 0) - return 0; +void +CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + const llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); + + llvm::Constant *Init = + llvm::ConstantArray::get(ArrayType, Builder.getVTTComponents().data(), + Builder.getVTTComponents().size()); + + VTT->setInitializer(Init); + + // Set the correct linkage. + VTT->setLinkage(Linkage); +} + +llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { + assert(RD->getNumVBases() && "Only classes with virtual bases need a VTT"); llvm::SmallString<256> OutName; CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); - D1(printf("vtt %s\n", RD->getNameAsCString())); + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); - if (GV == 0 || GV->isDeclaration()) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - VTTBuilder Builder(CGM, RD, GenerateDefinition); - - const llvm::ArrayType *Type = - llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); - - llvm::Constant *Init = 0; - if (GenerateDefinition) - Init = llvm::ConstantArray::get(Type, Builder.getVTTComponents().data(), - Builder.getVTTComponents().size()); - - llvm::GlobalVariable *OldGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, - Linkage, Init, Name); - CGM.setGlobalVisibility(GV, RD, /*ForDefinition*/ GenerateDefinition); - GV->setUnnamedAddr(true); - - if (OldGV) { - GV->takeName(OldGV); - llvm::Constant *NewPtr = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtr); - OldGV->eraseFromParent(); - } - } - + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + const llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); + + llvm::GlobalVariable *GV = + CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, + llvm::GlobalValue::ExternalLinkage); + GV->setUnnamedAddr(true); return GV; } -llvm::GlobalVariable *CodeGenVTables::getVTT(const CXXRecordDecl *RD) { - return GenerateVTT(llvm::GlobalValue::ExternalLinkage, - /*GenerateDefinition=*/false, RD); -} - bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { const CXXMethodDecl *MD = cast(GD.getDecl()); Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sat Jan 29 13:16:51 2011 @@ -3040,7 +3040,10 @@ VTable = GetAddrOfVTable(RD); EmitVTableDefinition(VTable, Linkage, RD); - GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + if (RD->getNumVBases()) { + llvm::GlobalVariable *VTT = GetAddrOfVTT(RD); + EmitVTTDefinition(VTT, Linkage, RD); + } // If this is the magic class __cxxabiv1::__fundamental_type_info, // we will emit the typeinfo for the fundamental types. This is the Modified: cfe/trunk/lib/CodeGen/CGVTables.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.h (original) +++ cfe/trunk/lib/CodeGen/CGVTables.h Sat Jan 29 13:16:51 2011 @@ -182,10 +182,6 @@ void ComputeMethodVTableIndices(const CXXRecordDecl *RD); - llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD); - /// EmitThunk - Emit a single thunk. void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk); @@ -257,8 +253,15 @@ GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, bool BaseIsVirtual, VTableAddressPointsMapTy& AddressPoints); - - llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); + + + /// GetAddrOfVTable - Get the address of the VTT for the given record decl. + llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD); + + /// EmitVTTDefinition - Emit the definition of the given vtable. + void EmitVTTDefinition(llvm::GlobalVariable *VTT, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); /// EmitThunks - Emit the associated thunks for the given global decl. void EmitThunks(GlobalDecl GD); Modified: cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp?rev=124539&r1=124538&r2=124539&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Sat Jan 29 13:16:51 2011 @@ -3,14 +3,14 @@ // Check mangling of Vtables, VTTs, and construction vtables that // involve standard substitutions. +// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant // CHECK: @_ZTVSd = linkonce_odr unnamed_addr constant // CHECK: @_ZTCSd0_Si = internal constant // CHECK: @_ZTCSd16_So = internal constant -// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant -// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant -// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant namespace std { struct A { A(); }; From andersca at mac.com Sat Jan 29 11:34:20 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 19:34:20 -0000 Subject: [cfe-commits] r124540 - in /cfe/trunk: lib/CodeGen/CGVTT.cpp test/CodeGenCXX/vtable-linkage.cpp Message-ID: <20110129193420.13F1B2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 13:34:19 2011 New Revision: 124540 URL: http://llvm.org/viewvc/llvm-project?rev=124540&view=rev Log: Give VTTs the right visibility. Modified: cfe/trunk/lib/CodeGen/CGVTT.cpp cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp Modified: cfe/trunk/lib/CodeGen/CGVTT.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTT.cpp?rev=124540&r1=124539&r2=124540&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTT.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTT.cpp Sat Jan 29 13:34:19 2011 @@ -384,6 +384,9 @@ // Set the correct linkage. VTT->setLinkage(Linkage); + + // Set the right visibility. + CGM.setTypeVisibility(VTT, RD, /*ForRTTI=*/false); } llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { Modified: cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp?rev=124540&r1=124539&r2=124540&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp Sat Jan 29 13:34:19 2011 @@ -32,7 +32,7 @@ B::B() { } -struct C { +struct C : virtual B { C(); virtual void f() { } }; @@ -106,9 +106,11 @@ // CHECK-2: @_ZTV1C = linkonce_odr unnamed_addr constant // CHECK-2: @_ZTS1C = linkonce_odr constant // CHECK-2: @_ZTI1C = linkonce_odr unnamed_addr constant +// CHECK-2: @_ZTT1C = linkonce_odr unnamed_addr constant // CHECK-2-HIDDEN: @_ZTV1C = linkonce_odr hidden unnamed_addr constant // CHECK-2-HIDDEN: @_ZTS1C = linkonce_odr constant // CHECK-2-HIDDEN: @_ZTI1C = linkonce_odr hidden unnamed_addr constant +// CHECK-2-HIDDEN: @_ZTT1C = linkonce_odr hidden unnamed_addr constant // D has a key function that is defined in this translation unit so its vtable is // defined in the translation unit. From andersca at mac.com Sat Jan 29 11:39:23 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 19:39:23 -0000 Subject: [cfe-commits] r124541 - in /cfe/trunk/lib/CodeGen: CGVTables.cpp CodeGenModule.cpp CodeGenModule.h Message-ID: <20110129193923.6DDDE2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 13:39:23 2011 New Revision: 124541 URL: http://llvm.org/viewvc/llvm-project?rev=124541&view=rev Log: Get rid of an unneeded parameter from setGlobalVisibility. Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124541&r1=124540&r2=124541&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sat Jan 29 13:39:23 2011 @@ -2505,7 +2505,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, const ThunkInfo &Thunk, llvm::Function *Fn) { - CGM.setGlobalVisibility(Fn, MD, /*ForDef*/ true); + CGM.setGlobalVisibility(Fn, MD); if (!CGM.getCodeGenOpts().HiddenWeakVTables) return; Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124541&r1=124540&r2=124541&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 13:39:23 2011 @@ -176,8 +176,7 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, - const NamedDecl *D, - bool IsForDefinition) const { + const NamedDecl *D) const { // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -186,8 +185,7 @@ // Set visibility for definitions. NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility(); - if (LV.visibilityExplicit() || - (IsForDefinition && !GV->hasAvailableExternallyLinkage())) + if (LV.visibilityExplicit() || !GV->hasAvailableExternallyLinkage()) GV->setVisibility(GetLLVMVisibility(LV.visibility())); } @@ -196,7 +194,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *RD, bool IsForRTTI) const { - setGlobalVisibility(GV, RD, /*IsForDefinition=*/true); + setGlobalVisibility(GV, RD); if (!CodeGenOpts.HiddenWeakVTables) return; @@ -460,7 +458,7 @@ void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { if (isa(D)) - setGlobalVisibility(GV, cast(D), /*ForDef*/ true); + setGlobalVisibility(GV, cast(D)); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -1415,7 +1413,7 @@ setFunctionLinkage(D, Fn); // FIXME: this is redundant with part of SetFunctionDefinitionAttributes - setGlobalVisibility(Fn, D, /*ForDef*/ true); + setGlobalVisibility(Fn, D); CodeGenFunction(*this).GenerateCode(D, Fn); Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=124541&r1=124540&r2=124541&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sat Jan 29 13:39:23 2011 @@ -259,8 +259,7 @@ /// setGlobalVisibility - Set the visibility for the given LLVM /// GlobalValue. - void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D, - bool IsForDefinition) const; + void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; /// setTypeVisibility - Set the visibility for the given global /// value which holds information about a type. From andersca at mac.com Sat Jan 29 11:41:00 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 19:41:00 -0000 Subject: [cfe-commits] r124542 - /cfe/trunk/lib/CodeGen/CodeGenModule.cpp Message-ID: <20110129194100.C8EBF2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 13:41:00 2011 New Revision: 124542 URL: http://llvm.org/viewvc/llvm-project?rev=124542&view=rev Log: Replace an isa/cast with a dyn_cast. Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124542&r1=124541&r2=124542&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 13:41:00 2011 @@ -457,8 +457,8 @@ void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { - if (isa(D)) - setGlobalVisibility(GV, cast(D)); + if (const NamedDecl *ND = dyn_cast(D)) + setGlobalVisibility(GV, ND); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); From andersca at mac.com Sat Jan 29 11:52:22 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 19:52:22 -0000 Subject: [cfe-commits] r124543 - /cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Message-ID: <20110129195222.A22632A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 13:52:22 2011 New Revision: 124543 URL: http://llvm.org/viewvc/llvm-project?rev=124543&view=rev Log: Add a test for RTTI visibility. Added: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Added: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp?rev=124543&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp (added) +++ cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Sat Jan 29 13:52:22 2011 @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden +// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2-HIDDEN %s < %t.hidden + +#include + +namespace Test1 { + // A is explicitly marked hidden, so all RTTI data should also be marked hidden. + // CHECK-TEST1: @_ZTSN5Test11AE = linkonce_odr hidden constant + // CHECK-TEST1: @_ZTIN5Test11AE = linkonce_odr hidden unnamed_addr constant + // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr hidden constant + // CHECK-TEST1: @_ZTIPN5Test11AE = linkonce_odr hidden unnamed_addr constant + struct __attribute__((visibility("hidden"))) A { }; + + void f() { + (void)typeid(A); + (void)typeid(A *); + } +} + +namespace Test2 { + // A is weak, so its linkage should be linkoce_odr, but not marked hidden. + // CHECK-TEST2: @_ZTSN5Test21AE = linkonce_odr constant + // CHECK-TEST2: @_ZTIN5Test21AE = linkonce_odr unnamed_addr constant + struct A { }; + + // With -fhidden-weak-vtables, the typeinfo for A is marked hidden, but not its name. + // CHECK-TEST2-HIDDEN: _ZTSN5Test21AE = linkonce_odr constant + // CHECK-TEST2-HIDDEN: @_ZTIN5Test21AE = linkonce_odr hidden unnamed_addr constant + void f() { + (void)typeid(A); + } +} From andersca at mac.com Sat Jan 29 12:24:48 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 20:24:48 -0000 Subject: [cfe-commits] r124546 - in /cfe/trunk/lib/CodeGen: CGRTTI.cpp CGVTT.cpp CGVTables.cpp CodeGenModule.cpp CodeGenModule.h Message-ID: <20110129202448.78D7F2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 14:24:48 2011 New Revision: 124546 URL: http://llvm.org/viewvc/llvm-project?rev=124546&view=rev Log: Change CodeGenModule::setTypeVisibility to take a TypeVisibilityKind enum instead of an "IsForRTTI" flag. Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/lib/CodeGen/CGVTT.cpp cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124546&r1=124545&r2=124546&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sat Jan 29 14:24:48 2011 @@ -644,7 +644,7 @@ // compatibility. if (const RecordType *RT = dyn_cast(Ty)) CGM.setTypeVisibility(GV, cast(RT->getDecl()), - /*ForRTTI=*/true); + CodeGenModule::TVK_ForRTTI); else if (Hidden || (CGM.getCodeGenOpts().HiddenWeakVTables && Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { Modified: cfe/trunk/lib/CodeGen/CGVTT.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTT.cpp?rev=124546&r1=124545&r2=124546&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTT.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTT.cpp Sat Jan 29 14:24:48 2011 @@ -386,7 +386,7 @@ VTT->setLinkage(Linkage); // Set the right visibility. - CGM.setTypeVisibility(VTT, RD, /*ForRTTI=*/false); + CGM.setTypeVisibility(VTT, RD, CodeGenModule::TVK_ForVTT); } llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124546&r1=124545&r2=124546&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sat Jan 29 14:24:48 2011 @@ -2976,7 +2976,7 @@ VTable->setLinkage(Linkage); // Set the right visibility. - CGM.setTypeVisibility(VTable, RD, /*ForRTTI=*/false); + CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable); } llvm::GlobalVariable * Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124546&r1=124545&r2=124546&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 14:24:48 2011 @@ -193,7 +193,7 @@ /// associated with the given type. void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *RD, - bool IsForRTTI) const { + TypeVisibilityKind TVK) const { setGlobalVisibility(GV, RD); if (!CodeGenOpts.HiddenWeakVTables) @@ -242,9 +242,10 @@ // If there's a key function, there may be translation units // that don't have the key function's definition. But ignore // this if we're emitting RTTI under -fno-rtti. - if (!IsForRTTI || Features.RTTI) + if (!(TVK != TVK_ForRTTI) || Features.RTTI) { if (Context.getKeyFunction(RD)) return; + } // Otherwise, drop the visibility to hidden. GV->setVisibility(llvm::GlobalValue::HiddenVisibility); Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=124546&r1=124545&r2=124546&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sat Jan 29 14:24:48 2011 @@ -261,10 +261,19 @@ /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; + /// TypeVisibilityKind - The kind of global variable that is passed to + /// setTypeVisibility + enum TypeVisibilityKind { + TVK_ForVTT, + TVK_ForVTable, + TVK_ForRTTI, + TVK_ForRTTIName + }; + /// setTypeVisibility - Set the visibility for the given global /// value which holds information about a type. void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, - bool IsForRTTI) const; + TypeVisibilityKind TVK) const; llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) From andersca at mac.com Sat Jan 29 12:36:11 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 20:36:11 -0000 Subject: [cfe-commits] r124548 - in /cfe/trunk/lib/CodeGen: CGRTTI.cpp CodeGenModule.cpp Message-ID: <20110129203611.4BD062A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 14:36:11 2011 New Revision: 124548 URL: http://llvm.org/viewvc/llvm-project?rev=124548&view=rev Log: Add RTTIBuilder::GetAddrOfTypeName which uses the newly added CreateOrReplaceCXXRuntimeVariable. Set the visibility for typeinfo names. Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124548&r1=124547&r2=124548&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sat Jan 29 14:36:11 2011 @@ -30,6 +30,10 @@ /// Fields - The fields of the RTTI descriptor currently being built. llvm::SmallVector Fields; + /// GetAddrOfTypeName - Returns the mangled type name of the given type. + llvm::GlobalVariable * + GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage); + /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI /// descriptor of the given type. llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); @@ -162,6 +166,26 @@ }; } +llvm::GlobalVariable * +RTTIBuilder::GetAddrOfTypeName(QualType Ty, + llvm::GlobalVariable::LinkageTypes Linkage) { + llvm::SmallString<256> OutName; + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName); + llvm::StringRef Name = OutName.str(); + + // We know that the mangled name of the type starts at index 4 of the + // mangled name of the typename, so we can just index into it in order to + // get the mangled name of the type. + llvm::Constant *Init = llvm::ConstantArray::get(VMContext, Name.substr(4)); + + llvm::GlobalVariable *GV = + CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage); + + GV->setInitializer(Init); + + return GV; +} + llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { // Mangle the RTTI name. llvm::SmallString<256> OutName; @@ -543,8 +567,14 @@ BuildVTablePointer(cast(Ty)); // And the name. + llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + llvm::Constant *TypeNameAsInt8Ptr = + llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy); + bool Hidden = DecideHidden(Ty); - Fields.push_back(BuildName(Ty, Hidden, Linkage)); + Fields.push_back(TypeNameAsInt8Ptr); switch (Ty->getTypeClass()) { #define TYPE(Class, Base) @@ -642,10 +672,13 @@ // type_infos themselves, so we can emit these as hidden symbols. // But don't do this if we're worried about strict visibility // compatibility. - if (const RecordType *RT = dyn_cast(Ty)) - CGM.setTypeVisibility(GV, cast(RT->getDecl()), - CodeGenModule::TVK_ForRTTI); - else if (Hidden || + if (const RecordType *RT = dyn_cast(Ty)) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + + CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI); + CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName); + + } else if (Hidden || (CGM.getCodeGenOpts().HiddenWeakVTables && Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { GV->setVisibility(llvm::GlobalValue::HiddenVisibility); Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124548&r1=124547&r2=124548&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 14:36:11 2011 @@ -199,6 +199,10 @@ if (!CodeGenOpts.HiddenWeakVTables) return; + // We never want to drop the visibility for RTTI names. + if (TVK == TVK_ForRTTIName) + return; + // We want to drop the visibility to hidden for weak type symbols. // This isn't possible if there might be unresolved references // elsewhere that rely on this symbol being visible. From andersca at mac.com Sat Jan 29 12:57:16 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 20:57:16 -0000 Subject: [cfe-commits] r124549 - in /cfe/trunk/test/CodeGenCXX: rtti-linkage.cpp rtti-visibility.cpp Message-ID: <20110129205716.73A122A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 14:57:16 2011 New Revision: 124549 URL: http://llvm.org/viewvc/llvm-project?rev=124549&view=rev Log: Update tests. I'm still not sure if having the typenames be visible with -hidden-weak-vtables, but I think it makes sense. Modified: cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Modified: cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp?rev=124549&r1=124548&r2=124549&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp Sat Jan 29 14:57:16 2011 @@ -4,7 +4,7 @@ #include // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant -// CHECK-WITH-HIDDEN: @_ZTSPK2T4 = linkonce_odr hidden constant +// CHECK-WITH-HIDDEN: @_ZTSPK2T4 = linkonce_odr constant // CHECK-WITH-HIDDEN: @_ZTS2T4 = linkonce_odr hidden constant // CHECK-WITH-HIDDEN: @_ZTI2T4 = linkonce_odr hidden unnamed_addr constant // CHECK-WITH-HIDDEN: @_ZTIPK2T4 = linkonce_odr hidden unnamed_addr constant Modified: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp?rev=124549&r1=124548&r2=124549&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Sat Jan 29 14:57:16 2011 @@ -10,7 +10,7 @@ // A is explicitly marked hidden, so all RTTI data should also be marked hidden. // CHECK-TEST1: @_ZTSN5Test11AE = linkonce_odr hidden constant // CHECK-TEST1: @_ZTIN5Test11AE = linkonce_odr hidden unnamed_addr constant - // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr hidden constant + // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr constant // CHECK-TEST1: @_ZTIPN5Test11AE = linkonce_odr hidden unnamed_addr constant struct __attribute__((visibility("hidden"))) A { }; From andersca at mac.com Sat Jan 29 12:59:35 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 20:59:35 -0000 Subject: [cfe-commits] r124550 - in /cfe/trunk/lib/CodeGen: CodeGenModule.cpp CodeGenModule.h Message-ID: <20110129205935.B314B2A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 14:59:35 2011 New Revision: 124550 URL: http://llvm.org/viewvc/llvm-project?rev=124550&view=rev Log: Move GetLLVMVisibility to CodeGenModule. Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124550&r1=124549&r2=124550&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Jan 29 14:59:35 2011 @@ -164,17 +164,6 @@ getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } -static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { - switch (V) { - case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; - case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility; - case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility; - } - llvm_unreachable("unknown visibility!"); - return llvm::GlobalValue::DefaultVisibility; -} - - void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const { // Internal definitions always have default visibility. Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=124550&r1=124549&r2=124550&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sat Jan 29 14:59:35 2011 @@ -275,6 +275,16 @@ void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, TypeVisibilityKind TVK) const; + static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { + switch (V) { + case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; + case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility; + case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility; + } + llvm_unreachable("unknown visibility!"); + return llvm::GlobalValue::DefaultVisibility; + } + llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) return GetAddrOfCXXConstructor(cast(GD.getDecl()), From thakis at chromium.org Sat Jan 29 13:24:26 2011 From: thakis at chromium.org (Nico Weber) Date: Sat, 29 Jan 2011 13:24:26 -0800 Subject: [cfe-commits] [patch] Support -plugin-arg- with -add-plugin In-Reply-To: References: Message-ID: On Fri, Jan 28, 2011 at 8:29 AM, Nico Weber wrote: > Hi, > > the attached patch makes -plugin-arg work with -add-plugin. Since it's a very simple patch, I'll submit this. If you see any issues with it, I'll happily revert it again. > On a related note, the plugin stuff doesn't seem to have any test > coverage. What do you think about adding a test plugin that prints > diagnostics in response to certain events? Then the normal test > framework (expected-note etc) could be used to test plugins. I'd still love to hear opinions on this question. Nico From nicolasweber at gmx.de Sat Jan 29 13:21:49 2011 From: nicolasweber at gmx.de (Nico Weber) Date: Sat, 29 Jan 2011 21:21:49 -0000 Subject: [cfe-commits] r124551 - in /cfe/trunk: include/clang/Frontend/FrontendOptions.h lib/Frontend/CompilerInvocation.cpp lib/Frontend/FrontendAction.cpp Message-ID: <20110129212149.B18342A6C12C@llvm.org> Author: nico Date: Sat Jan 29 15:21:49 2011 New Revision: 124551 URL: http://llvm.org/viewvc/llvm-project?rev=124551&view=rev Log: Support for -plugin-arg- with -add-plugin Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/Frontend/FrontendAction.cpp Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=124551&r1=124550&r2=124551&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original) +++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Sat Jan 29 15:21:49 2011 @@ -100,12 +100,15 @@ /// The name of the action to run when using a plugin action. std::string ActionName; - /// Arg to pass to the plugin + /// Args to pass to the plugin std::vector PluginArgs; /// The list of plugin actions to run in addition to the normal action. std::vector AddPluginActions; + /// Args to pass to the additional plugins + std::vector > AddPluginArgs; + /// The list of plugins to load. std::vector Plugins; Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=124551&r1=124550&r2=124551&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Sat Jan 29 15:21:49 2011 @@ -438,6 +438,10 @@ for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { Res.push_back("-add-plugin"); Res.push_back(Opts.AddPluginActions[i]); + for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) { + Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i]); + Res.push_back(Opts.AddPluginArgs[i][ai]); + } } for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { Res.push_back("-ast-merge"); @@ -1106,6 +1110,14 @@ } Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); + Opts.AddPluginArgs.resize(Opts.AddPluginActions.size()); + for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { + for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), + end = Args.filtered_end(); it != end; ++it) { + if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) + Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); + } + } if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=124551&r1=124550&r2=124551&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/FrontendAction.cpp (original) +++ cfe/trunk/lib/Frontend/FrontendAction.cpp Sat Jan 29 15:21:49 2011 @@ -112,7 +112,7 @@ if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) { llvm::OwningPtr P(it->instantiate()); FrontendAction* c = P.get(); - if (P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) + if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i])) Consumers.push_back(c->CreateASTConsumer(CI, InFile)); } } From andersca at mac.com Sat Jan 29 14:10:33 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 22:10:33 -0000 Subject: [cfe-commits] r124553 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp test/CodeGenCXX/rtti-linkage.cpp test/CodeGenCXX/rtti-visibility.cpp Message-ID: <20110129221033.0D4F32A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 16:10:32 2011 New Revision: 124553 URL: http://llvm.org/viewvc/llvm-project?rev=124553&view=rev Log: When emitting RTTI for a non-class type, compute the visibility of the RTTI data based on the explicit visibility of the type. Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124553&r1=124552&r2=124553&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sat Jan 29 16:10:32 2011 @@ -570,11 +570,7 @@ llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - llvm::Constant *TypeNameAsInt8Ptr = - llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy); - - bool Hidden = DecideHidden(Ty); - Fields.push_back(TypeNameAsInt8Ptr); + Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy)); switch (Ty->getTypeClass()) { #define TYPE(Class, Base) @@ -677,12 +673,21 @@ CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI); CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName); - - } else if (Hidden || - (CGM.getCodeGenOpts().HiddenWeakVTables && - Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { - GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + } else { + Visibility TypeInfoVisibility = DefaultVisibility; + if (CGM.getCodeGenOpts().HiddenWeakVTables && + Linkage == llvm::GlobalValue::LinkOnceODRLinkage) + TypeInfoVisibility = HiddenVisibility; + + // The type name should have the same visibility as the type itself. + Visibility ExplicitVisibility = Ty->getVisibility(); + TypeName->setVisibility(CodeGenModule:: + GetLLVMVisibility(ExplicitVisibility)); + + TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility()); + GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility)); } + GV->setUnnamedAddr(true); return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); Modified: cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp?rev=124553&r1=124552&r2=124553&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rtti-linkage.cpp Sat Jan 29 16:10:32 2011 @@ -4,7 +4,7 @@ #include // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant -// CHECK-WITH-HIDDEN: @_ZTSPK2T4 = linkonce_odr constant +// CHECK-WITH-HIDDEN: @_ZTSPK2T4 = linkonce_odr hidden constant // CHECK-WITH-HIDDEN: @_ZTS2T4 = linkonce_odr hidden constant // CHECK-WITH-HIDDEN: @_ZTI2T4 = linkonce_odr hidden unnamed_addr constant // CHECK-WITH-HIDDEN: @_ZTIPK2T4 = linkonce_odr hidden unnamed_addr constant Modified: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp?rev=124553&r1=124552&r2=124553&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Sat Jan 29 16:10:32 2011 @@ -10,7 +10,7 @@ // A is explicitly marked hidden, so all RTTI data should also be marked hidden. // CHECK-TEST1: @_ZTSN5Test11AE = linkonce_odr hidden constant // CHECK-TEST1: @_ZTIN5Test11AE = linkonce_odr hidden unnamed_addr constant - // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr constant + // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr hidden constant // CHECK-TEST1: @_ZTIPN5Test11AE = linkonce_odr hidden unnamed_addr constant struct __attribute__((visibility("hidden"))) A { }; From andersca at mac.com Sat Jan 29 14:15:18 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 22:15:18 -0000 Subject: [cfe-commits] r124554 - /cfe/trunk/lib/CodeGen/CGRTTI.cpp Message-ID: <20110129221518.456C22A6C12C@llvm.org> Author: andersca Date: Sat Jan 29 16:15:18 2011 New Revision: 124554 URL: http://llvm.org/viewvc/llvm-project?rev=124554&view=rev Log: Remove dead code. Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124554&r1=124553&r2=124554&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sat Jan 29 16:15:18 2011 @@ -63,64 +63,10 @@ void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty); public: - RTTIBuilder(CodeGenModule &cgm) - : CGM(cgm), VMContext(cgm.getModule().getContext()), - Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } - - llvm::Constant *BuildName(QualType Ty, bool Hidden, - llvm::GlobalVariable::LinkageTypes Linkage) { - llvm::SmallString<256> OutName; - CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName); - llvm::StringRef Name = OutName.str(); - - llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name); - if (OGV && !OGV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy); - - llvm::Constant *C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, - C, Name); - if (OGV) { - GV->takeName(OGV); - llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, - OGV->getType()); - OGV->replaceAllUsesWith(NewPtr); - OGV->eraseFromParent(); - } - if (Hidden && Linkage != llvm::GlobalValue::InternalLinkage) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - } - - // FIXME: unify with DecideExtern - bool DecideHidden(QualType Ty) { - // For this type, see if all components are never hidden. - if (const MemberPointerType *MPT = Ty->getAs()) - return (DecideHidden(MPT->getPointeeType()) - && DecideHidden(QualType(MPT->getClass(), 0))); - if (const PointerType *PT = Ty->getAs()) - return DecideHidden(PT->getPointeeType()); - if (const FunctionType *FT = Ty->getAs()) { - if (DecideHidden(FT->getResultType()) == false) - return false; - if (const FunctionProtoType *FPT = Ty->getAs()) { - for (unsigned i = 0; i getNumArgs(); ++i) - if (DecideHidden(FPT->getArgType(i)) == false) - return false; - for (unsigned i = 0; i getNumExceptions(); ++i) - if (DecideHidden(FPT->getExceptionType(i)) == false) - return false; - return true; - } - } - if (const RecordType *RT = Ty->getAs()) - if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) - return RD->getVisibility() == HiddenVisibility; - return false; - } - + RTTIBuilder(CodeGenModule &CGM) : CGM(CGM), + VMContext(CGM.getModule().getContext()), + Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } + // Pointer type info flags. enum { /// PTI_Const - Type has const qualifier. From andersca at mac.com Sat Jan 29 14:39:23 2011 From: andersca at mac.com (Anders Carlsson) Date: Sat, 29 Jan 2011 22:39:23 -0000 Subject: [cfe-commits] r124555 - /cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Message-ID: <20110129223923.C6F142A6C12D@llvm.org> Author: andersca Date: Sat Jan 29 16:39:23 2011 New Revision: 124555 URL: http://llvm.org/viewvc/llvm-project?rev=124555&view=rev Log: Fix test. Modified: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Modified: cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp?rev=124555&r1=124554&r2=124555&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp (original) +++ cfe/trunk/test/CodeGenCXX/rtti-visibility.cpp Sat Jan 29 16:39:23 2011 @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden // RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST2-HIDDEN %s < %t.hidden From rdivacky at freebsd.org Sun Jan 30 00:12:24 2011 From: rdivacky at freebsd.org (Roman Divacky) Date: Sun, 30 Jan 2011 08:12:24 -0000 Subject: [cfe-commits] r124558 - in /cfe/trunk: lib/Driver/Tools.cpp test/Driver/freebsd.c Message-ID: <20110130081224.C99352A6C12C@llvm.org> Author: rdivacky Date: Sun Jan 30 02:12:24 2011 New Revision: 124558 URL: http://llvm.org/viewvc/llvm-project?rev=124558&view=rev Log: Add hardcoded -L/usr/lib after all -L options to the FreeBSD linker invocation. This mimics what gcc does and fixes libtool check for libraries. Modified: cfe/trunk/lib/Driver/Tools.cpp cfe/trunk/test/Driver/freebsd.c Modified: cfe/trunk/lib/Driver/Tools.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=124558&r1=124557&r2=124558&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Tools.cpp (original) +++ cfe/trunk/lib/Driver/Tools.cpp Sun Jan 30 02:12:24 2011 @@ -3164,6 +3164,7 @@ } Args.AddAllArgs(CmdArgs, options::OPT_L); + CmdArgs.push_back("-L/usr/lib"); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Modified: cfe/trunk/test/Driver/freebsd.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/freebsd.c?rev=124558&r1=124557&r2=124558&view=diff ============================================================================== --- cfe/trunk/test/Driver/freebsd.c (original) +++ cfe/trunk/test/Driver/freebsd.c Sun Jan 30 02:12:24 2011 @@ -2,7 +2,7 @@ // RUN: FileCheck --check-prefix=CHECK-PPC < %t %s // // CHECK-PPC: clang{{.*}}" "-cc1" "-triple" "powerpc64-pc-freebsd8" -// CHECK-PPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o" +// CHECK-PPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o" // Check that -m32 properly adjusts the toolchain flags. From andersca at mac.com Sun Jan 30 12:45:55 2011 From: andersca at mac.com (Anders Carlsson) Date: Sun, 30 Jan 2011 20:45:55 -0000 Subject: [cfe-commits] r124565 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CGVTables.cpp lib/CodeGen/CodeGenModule.cpp lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/vtable-available-externally.cpp Message-ID: <20110130204555.287382A6C12E@llvm.org> Author: andersca Date: Sun Jan 30 14:45:54 2011 New Revision: 124565 URL: http://llvm.org/viewvc/llvm-project?rev=124565&view=rev Log: When building with optimizations, emit vtables where the key is not in the current translation unit as available_externally. This helps devirtualize the second example in PR3100, comment 18: struct S { S() {}; virtual void xyzzy(); }; inline void foo(S *s) { s->xyzzy(); } void bar() { S s; foo(&s); } This involved four major changes: 1. In DefineUsedVTables, always mark virtual member functions as referenced for non-template classes and class template specializations. 2. In CodeGenVTables::ShouldEmitVTableInThisTU return true if optimizations are enabled, even if the key function is not implemented in this translation unit. We don't ever do this for code compiled with -fapple-kext, because we don't ever want to devirtualize virtual member function calls in that case. 3. Give the correct linkage for vtables where the key function is not defined. 4. Update the linkage for RTTI structures when necessary. Added: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp cfe/trunk/lib/CodeGen/CGVTables.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124565&r1=124564&r2=124565&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sun Jan 30 14:45:54 2011 @@ -484,6 +484,58 @@ Fields.push_back(VTable); } +// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures +// from available_externally to the correct linkage if necessary. An example of +// this is: +// +// struct A { +// virtual void f(); +// }; +// +// const std::type_info &g() { +// return typeid(A); +// } +// +// void A::f() { } +// +// When we're generating the typeid(A) expression, we do not yet know that +// A's key function is defined in this translation unit, so we will give the +// typeinfo and typename structures available_externally linkage. When A::f +// forces the vtable to be generated, we need to change the linkage of the +// typeinfo and typename structs, otherwise we'll end up with undefined +// externals when linking. +static void +maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV, + QualType Ty) { + // We're only interested in globals with available_externally linkage. + if (!GV->hasAvailableExternallyLinkage()) + return; + + // Get the real linkage for the type. + llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty); + + // If variable is supposed to have available_externally linkage, we don't + // need to do anything. + if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) + return; + + // Update the typeinfo linkage. + GV->setLinkage(Linkage); + + // Get the typename global. + llvm::SmallString<256> OutName; + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName); + llvm::StringRef Name = OutName.str(); + + llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name); + + assert(TypeNameGV->hasAvailableExternallyLinkage() && + "Type name has different linkage from type info!"); + + // And update its linkage. + TypeNameGV->setLinkage(Linkage); +} + llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); @@ -494,8 +546,11 @@ llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); - if (OldGV && !OldGV->isDeclaration()) + if (OldGV && !OldGV->isDeclaration()) { + maybeUpdateRTTILinkage(CGM, OldGV, Ty); + return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); + } // Check if there is already an external RTTI descriptor for this type. bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty); Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124565&r1=124564&r2=124565&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sun Jan 30 14:45:54 2011 @@ -2374,6 +2374,12 @@ TSK == TSK_ExplicitInstantiationDefinition) return true; + // If we're building with optimization, we always emit VTables since that + // allows for virtual function calls to be devirtualized. + // (We don't want to do this in -fapple-kext mode however). + if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOptions().AppleKext) + return true; + return KeyFunction->hasBody(); } Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124565&r1=124564&r2=124565&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Jan 30 14:45:54 2011 @@ -1082,6 +1082,12 @@ switch (KeyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: + // When compiling with optimizations turned on, we emit all vtables, + // even if the key function is not defined in the current translation + // unit. If this is the case, use available_externally linkage. + if (!Def && CodeGenOpts.OptimizationLevel) + return llvm::GlobalVariable::AvailableExternallyLinkage; + if (KeyFunction->isInlined()) return llvm::GlobalVariable::LinkOnceODRLinkage; Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124565&r1=124564&r2=124565&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Jan 30 14:45:54 2011 @@ -7110,6 +7110,13 @@ switch (KeyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: + // The key function is in another translation unit. Mark all of the + // virtual members of this class as referenced so that we can build a + // vtable anyway (in order to do devirtualization when optimizations + // are turned on for example. + MarkVirtualMembersReferenced(Loc, Class); + continue; + case TSK_ExplicitInstantiationDeclaration: // The key function is in another translation unit. continue; Added: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp?rev=124565&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp (added) +++ cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp Sun Jan 30 14:45:54 2011 @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t +// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t + +#include + +// Test1::A's key function (f) is not defined in this translation unit, but in +// order to devirtualize calls, we emit the class related data with +// available_externally linkage. + +// CHECK-TEST1: @_ZTVN5Test11AE = available_externally +// CHECK-TEST1: @_ZTSN5Test11AE = available_externally +// CHECK-TEST1: @_ZTIN5Test11AE = available_externally +namespace Test1 { + +struct A { + A(); + virtual void f(); + virtual ~A() { } +}; + +A::A() { } + +void f(A* a) { + a->f(); +}; + +// CHECK: define void @_ZN5Test11gEv +// CHECK: call void @_ZN5Test11A1fEv +void g() { + A a; + f(&a); +} + +} + +// Test2::A's key function (f) is defined in this translation unit, but when +// we're doing codegen for the typeid(A) call, we don't know that yet. +// This tests mainly that the typeinfo and typename constants have their linkage +// updated correctly. + +// CHECK-TEST2: @_ZTSN5Test21AE = constant +// CHECK-TEST2: @_ZTIN5Test21AE = unnamed_addr constant +// CHECK-TEST2: @_ZTVN5Test21AE = unnamed_addr constant +namespace Test2 { + struct A { + virtual void f(); + }; + + const std::type_info &g() { + return typeid(A); + }; + + void A::f() { } +} From pichet2000 at gmail.com Sun Jan 30 20:54:32 2011 From: pichet2000 at gmail.com (Francois Pichet) Date: Mon, 31 Jan 2011 04:54:32 -0000 Subject: [cfe-commits] r124573 - in /cfe/trunk: lib/Parse/ParseDecl.cpp test/Parser/MicrosoftExtensions.cpp Message-ID: <20110131045432.BF93F2A6C12C@llvm.org> Author: fpichet Date: Sun Jan 30 22:54:32 2011 New Revision: 124573 URL: http://llvm.org/viewvc/llvm-project?rev=124573&view=rev Log: Allow Microsoft attributes in a constructor's parameter list. This fixes a few compile errors when parsing from MSVC 2008 with clang. Modified: cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/test/Parser/MicrosoftExtensions.cpp Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124573&r1=124572&r2=124573&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Sun Jan 30 22:54:32 2011 @@ -2512,6 +2512,10 @@ if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) DeclScopeObj.EnterDeclaratorScope(); + // Optionally skip Microsoft attributes. + ParsedAttributes Attrs; + MaybeParseMicrosoftAttributes(Attrs); + // Check whether the next token(s) are part of a declaration // specifier, in which case we have the start of a parameter and, // therefore, we know that this is a constructor. Modified: cfe/trunk/test/Parser/MicrosoftExtensions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/MicrosoftExtensions.cpp?rev=124573&r1=124572&r2=124573&view=diff ============================================================================== --- cfe/trunk/test/Parser/MicrosoftExtensions.cpp (original) +++ cfe/trunk/test/Parser/MicrosoftExtensions.cpp Sun Jan 30 22:54:32 2011 @@ -22,6 +22,14 @@ int foo5([SA_Post(attr=1)] void *param); } +class class_attr { +public: + class_attr([SA_Pre(Null=SA_No,NullTerminated=SA_Yes)] int a) + { + } +}; + + void uuidof_test1() { From akyrtzi at gmail.com Sun Jan 30 23:04:24 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:24 -0000 Subject: [cfe-commits] r124574 - /cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp Message-ID: <20110131070424.87C862A6C12C@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:24 2011 New Revision: 124574 URL: http://llvm.org/viewvc/llvm-project?rev=124574&view=rev Log: Fix test that didn't actually test what it wanted to test. Modified: cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp Modified: cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp?rev=124574&r1=124573&r2=124574&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp (original) +++ cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp Mon Jan 31 01:04:24 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s struct A { union { @@ -67,7 +67,7 @@ }; A::A() : callback(0), callback_value(0) {} - // CHECK: define void @ZN5test31AC2Ev( + // CHECK: define void @_ZN5test31AC2Ev( // CHECK: [[THIS:%.*]] = load // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 @@ -75,8 +75,8 @@ // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]] // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 - // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 - // CHECK-NEXT: store i8* null, void i8** [[CVALUE]] + // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 1 + // CHECK-NEXT: store i8* null, i8** [[CVALUE]] } struct S { From akyrtzi at gmail.com Sun Jan 30 23:04:29 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:29 -0000 Subject: [cfe-commits] r124575 - in /cfe/trunk: include/clang/Sema/Sema.h lib/CodeGen/ItaniumCXXABI.cpp lib/Sema/SemaExpr.cpp test/CodeGenCXX/anonymous-union-member-initializer.cpp Message-ID: <20110131070430.1B3382A6C12D@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:29 2011 New Revision: 124575 URL: http://llvm.org/viewvc/llvm-project?rev=124575&view=rev Log: Amazing that there are still issues with the fields of anonymous struct/unions.. Allow taking the address of such a field for a pointer-to-member constant. Fixes rdar://8818236. Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124575&r1=124574&r2=124575&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Mon Jan 31 01:04:29 2011 @@ -1784,6 +1784,7 @@ const CXXScopeSpec *SS = 0); ExprResult BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + const CXXScopeSpec &SS, IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=124575&r1=124574&r2=124575&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Mon Jan 31 01:04:29 2011 @@ -493,17 +493,41 @@ /*Packed=*/false); } +static uint64_t getFieldOffset(const FieldDecl *FD, CodeGenModule &CGM) { + const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); + const llvm::StructType *ClassLTy = RL.getLLVMType(); + + unsigned FieldNo = RL.getLLVMFieldNo(FD); + return + CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); +} + llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { // Itanium C++ ABI 2.3: // A pointer to data member is an offset from the base address of // the class object containing it, represented as a ptrdiff_t - const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); - const llvm::StructType *ClassLTy = RL.getLLVMType(); - - unsigned FieldNo = RL.getLLVMFieldNo(FD); - uint64_t Offset = - CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + const RecordDecl *parent = FD->getParent(); + if (!parent->isAnonymousStructOrUnion()) + return llvm::ConstantInt::get(getPtrDiffTy(), getFieldOffset(FD, CGM)); + + // Handle a field injected from an anonymous struct or union. + + assert(FD->getDeclName() && "Requested pointer to member with no name!"); + + // Find the record which the field was injected into. + while (parent->isAnonymousStructOrUnion()) + parent = cast(parent->getParent()); + + RecordDecl::lookup_const_result lookup = parent->lookup(FD->getDeclName()); + assert(lookup.first != lookup.second && "Didn't find the field!"); + const IndirectFieldDecl *indirectFD = cast(*lookup.first); + + uint64_t Offset = 0; + for (IndirectFieldDecl::chain_iterator + I= indirectFD->chain_begin(), E= indirectFD->chain_end(); I!=E; ++I) { + Offset += getFieldOffset(cast(*I), CGM); + } return llvm::ConstantInt::get(getPtrDiffTy(), Offset); } Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124575&r1=124574&r2=124575&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 31 01:04:29 2011 @@ -853,6 +853,7 @@ ExprResult Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + const CXXScopeSpec &SS, IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr, SourceLocation OpLoc) { @@ -911,9 +912,21 @@ BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); } - if (!BaseObjectExpr) - return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) - << IndirectField->getDeclName()); + if (!BaseObjectExpr) { + // The field is referenced for a pointer-to-member expression, e.g: + // + // struct S { + // union { + // char c; + // }; + // }; + // char S::*foo = &S::c; + // + FieldDecl *field = IndirectField->getAnonField(); + DeclarationNameInfo NameInfo(field->getDeclName(), Loc); + return BuildDeclRefExpr(field, field->getType().getNonReferenceType(), + VK_LValue, NameInfo, &SS); + } } // Build the implicit member references to the field of the @@ -929,9 +942,6 @@ for (; FI != FEnd; FI++) { FieldDecl *Field = cast(*FI); - // FIXME: the first access can be qualified - CXXScopeSpec SS; - // FIXME: these are somewhat meaningless DeclarationNameInfo MemberNameInfo(Field->getDeclName(), Loc); DeclAccessPair FoundDecl = DeclAccessPair::make(Field, Field->getAccess()); @@ -2035,7 +2045,7 @@ // FIXME: This needs to happen post-isImplicitMemberReference? // FIXME: template-ids inside anonymous structs? if (IndirectFieldDecl *FD = R.getAsSingle()) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); // If this is known to be an instance access, go ahead and build a @@ -2228,7 +2238,7 @@ // Handle anonymous. if (IndirectFieldDecl *FD = dyn_cast(VD)) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); ExprValueKind VK = getValueKindForDecl(Context, VD); @@ -3400,7 +3410,7 @@ if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + return BuildAnonymousStructUnionMemberReference(MemberLoc, SS, FD, BaseExpr, OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { @@ -7346,6 +7356,8 @@ return QualType(); } + while (cast(Ctx)->isAnonymousStructOrUnion()) + Ctx = Ctx->getParent(); return S.Context.getMemberPointerType(op->getType(), S.Context.getTypeDeclType(cast(Ctx)).getTypePtr()); } Modified: cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp?rev=124575&r1=124574&r2=124575&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp (original) +++ cfe/trunk/test/CodeGenCXX/anonymous-union-member-initializer.cpp Mon Jan 31 01:04:29 2011 @@ -1,5 +1,19 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// rdar://8818236 +namespace rdar8818236 { +struct S { + char c2; + union { + char c; + int i; + }; +}; + +// CHECK: @_ZN11rdar88182363fooE = global i64 4 +char S::*foo = &S::c; +} + struct A { union { int a; From akyrtzi at gmail.com Sun Jan 30 23:04:33 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:33 -0000 Subject: [cfe-commits] r124576 - in /cfe/trunk: lib/Sema/SemaExpr.cpp test/SemaCXX/class.cpp Message-ID: <20110131070434.188332A6C12C@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:33 2011 New Revision: 124576 URL: http://llvm.org/viewvc/llvm-project?rev=124576&view=rev Log: Error for use of field from anonymous struct or union should say "invalid use of nonstatic data member" not "call to non-static member function without an object argument". Modified: cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/SemaCXX/class.cpp Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124576&r1=124575&r2=124576&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 31 01:04:33 2011 @@ -1154,7 +1154,7 @@ SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - if (R.getAsSingle()) { + if (R.getAsSingle() || R.getAsSingle()) { if (CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext)) { if (MD->isStatic()) { // "invalid use of member 'x' in static member function" Modified: cfe/trunk/test/SemaCXX/class.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=124576&r1=124575&r2=124576&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/class.cpp (original) +++ cfe/trunk/test/SemaCXX/class.cpp Mon Jan 31 01:04:33 2011 @@ -176,3 +176,15 @@ static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}} expected-error {{in-class initializer is not a constant expression}} }; } + +namespace with_anon { +struct S { + union { + char c; + }; +}; + +void f() { + S::c; // expected-error {{invalid use of nonstatic data member}} +} +} From akyrtzi at gmail.com Sun Jan 30 23:04:38 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:38 -0000 Subject: [cfe-commits] r124577 - in /cfe/trunk: lib/Sema/Sema.cpp test/SemaCXX/unused-with-error.cpp Message-ID: <20110131070438.27CBE2A6C12D@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:37 2011 New Revision: 124577 URL: http://llvm.org/viewvc/llvm-project?rev=124577&view=rev Log: If there were errors, disable 'unused' warnings since they will mostly be noise. Fixes rdar://8736362. Added: cfe/trunk/test/SemaCXX/unused-with-error.cpp Modified: cfe/trunk/lib/Sema/Sema.cpp Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=124577&r1=124576&r2=124577&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Mon Jan 31 01:04:37 2011 @@ -388,25 +388,29 @@ Consumer.CompleteTentativeDefinition(VD); } - - // Output warning for unused file scoped decls. - for (llvm::SmallVectorImpl::iterator - I = UnusedFileScopedDecls.begin(), - E = UnusedFileScopedDecls.end(); I != E; ++I) { - if (const FunctionDecl *FD = dyn_cast(*I)) { - const FunctionDecl *DiagD; - if (!FD->hasBody(DiagD)) - DiagD = FD; - Diag(DiagD->getLocation(), - isa(DiagD) ? diag::warn_unused_member_function - : diag::warn_unused_function) - << DiagD->getDeclName(); - } else { - const VarDecl *DiagD = cast(*I)->getDefinition(); - if (!DiagD) - DiagD = cast(*I); - Diag(DiagD->getLocation(), diag::warn_unused_variable) - << DiagD->getDeclName(); + + // If there were errors, disable 'unused' warnings since they will mostly be + // noise. + if (!Diags.hasErrorOccurred()) { + // Output warning for unused file scoped decls. + for (llvm::SmallVectorImpl::iterator + I = UnusedFileScopedDecls.begin(), + E = UnusedFileScopedDecls.end(); I != E; ++I) { + if (const FunctionDecl *FD = dyn_cast(*I)) { + const FunctionDecl *DiagD; + if (!FD->hasBody(DiagD)) + DiagD = FD; + Diag(DiagD->getLocation(), + isa(DiagD) ? diag::warn_unused_member_function + : diag::warn_unused_function) + << DiagD->getDeclName(); + } else { + const VarDecl *DiagD = cast(*I)->getDefinition(); + if (!DiagD) + DiagD = cast(*I); + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD->getDeclName(); + } } } Added: cfe/trunk/test/SemaCXX/unused-with-error.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unused-with-error.cpp?rev=124577&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/unused-with-error.cpp (added) +++ cfe/trunk/test/SemaCXX/unused-with-error.cpp Mon Jan 31 01:04:37 2011 @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s + +// Make sure 'unused' warnings are disabled when errors occurred. +static void foo(int *X) { // expected-note {{candidate}} +} +void bar(const int *Y) { + foo(Y); // expected-error {{no matching function for call}} +} From akyrtzi at gmail.com Sun Jan 30 23:04:41 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:41 -0000 Subject: [cfe-commits] r124578 - in /cfe/trunk: lib/Sema/SemaDecl.cpp test/Sema/warn-shadow.c Message-ID: <20110131070441.DBD932A6C12C@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:41 2011 New Revision: 124578 URL: http://llvm.org/viewvc/llvm-project?rev=124578&view=rev Log: 'extern' variables in functions don't shadow externs in global scope. Fixes rdar://8883302. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/Sema/warn-shadow.c Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124578&r1=124577&r2=124578&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 31 01:04:41 2011 @@ -3117,6 +3117,19 @@ DeclContext *OldDC = ShadowedDecl->getDeclContext(); + // Don't warn for this case: + // + // @code + // extern int bob; + // void f() { + // extern int bob; + // } + // @endcode + if (D->isExternC() && NewDC->isFunctionOrMethod()) + if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) + if (shadowedVar->isExternC()) + return; + // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. Modified: cfe/trunk/test/Sema/warn-shadow.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-shadow.c?rev=124578&r1=124577&r2=124578&view=diff ============================================================================== --- cfe/trunk/test/Sema/warn-shadow.c (original) +++ cfe/trunk/test/Sema/warn-shadow.c Mon Jan 31 01:04:41 2011 @@ -48,3 +48,9 @@ void test5(int i); void test6(void (*f)(int i)) {} void test7(void *context, void (*callback)(void *context)) {} + +// rdar://8883302 +extern int bob; +void rdar8883302() { + extern int bob; // don't warn for shadowing. +} From akyrtzi at gmail.com Sun Jan 30 23:04:47 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:47 -0000 Subject: [cfe-commits] r124579 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/Sema/private-extern.c Message-ID: <20110131070447.2C5BF2A6C12D@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:46 2011 New Revision: 124579 URL: http://llvm.org/viewvc/llvm-project?rev=124579&view=rev Log: Diagnose if extern local variable is followed by non-extern and vice-versa. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/Sema/private-extern.c Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124579&r1=124578&r2=124579&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 31 01:04:46 2011 @@ -1963,6 +1963,10 @@ "static declaration of %0 follows non-static declaration">; def err_non_static_static : Error< "non-static declaration of %0 follows static declaration">; +def err_extern_non_extern : Error< + "extern declaration of %0 follows non-extern declaration">; +def err_non_extern_extern : Error< + "non-extern declaration of %0 follows extern declaration">; def err_non_thread_thread : Error< "non-thread-local declaration of %0 follows thread-local declaration">; def err_thread_non_thread : Error< Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124579&r1=124578&r2=124579&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 31 01:04:46 2011 @@ -1548,6 +1548,20 @@ return New->setInvalidDecl(); } + // Check if extern is followed by non-extern and vice-versa. + if (New->hasExternalStorage() && + !Old->hasLinkage() && Old->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + if (Old->hasExternalStorage() && + !New->hasLinkage() && New->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still Modified: cfe/trunk/test/Sema/private-extern.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/private-extern.c?rev=124579&r1=124578&r2=124579&view=diff ============================================================================== --- cfe/trunk/test/Sema/private-extern.c (original) +++ cfe/trunk/test/Sema/private-extern.c Mon Jan 31 01:04:46 2011 @@ -19,27 +19,23 @@ static int g5; // expected-error{{static declaration of 'g5' follows non-static declaration}} void f0() { - // FIXME: Diagnose this? - int g6; - extern int g6; + int g6; // expected-note {{previous}} + extern int g6; // expected-error {{extern declaration of 'g6' follows non-extern declaration}} } void f1() { - // FIXME: Diagnose this? - int g7; - __private_extern__ int g7; + int g7; // expected-note {{previous}} + __private_extern__ int g7; // expected-error {{extern declaration of 'g7' follows non-extern declaration}} } void f2() { extern int g8; // expected-note{{previous definition}} - // FIXME: Improve this diagnostic. - int g8; // expected-error{{redefinition of 'g8'}} + int g8; // expected-error {{non-extern declaration of 'g8' follows extern declaration}} } void f3() { __private_extern__ int g9; // expected-note{{previous definition}} - // FIXME: Improve this diagnostic. - int g9; // expected-error{{redefinition of 'g9'}} + int g9; // expected-error {{non-extern declaration of 'g9' follows extern declaration}} } void f4() { From akyrtzi at gmail.com Sun Jan 30 23:04:51 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:51 -0000 Subject: [cfe-commits] r124580 - in /cfe/trunk: lib/Sema/SemaDecl.cpp test/Sema/warn-shadow.c Message-ID: <20110131070451.1D66D2A6C12C@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:50 2011 New Revision: 124580 URL: http://llvm.org/viewvc/llvm-project?rev=124580&view=rev Log: Fix the diagnostic when we are shadowing an external variable and there exists a locally scoped extern with the same name. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/Sema/warn-shadow.c Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124580&r1=124579&r2=124580&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 31 01:04:50 2011 @@ -3129,21 +3129,32 @@ if (!isa(ShadowedDecl) && !isa(ShadowedDecl)) return; - DeclContext *OldDC = ShadowedDecl->getDeclContext(); - - // Don't warn for this case: - // - // @code - // extern int bob; - // void f() { - // extern int bob; - // } - // @endcode - if (D->isExternC() && NewDC->isFunctionOrMethod()) - if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) - if (shadowedVar->isExternC()) + if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) + if (shadowedVar->isExternC()) { + // Don't warn for this case: + // + // @code + // extern int bob; + // void f() { + // extern int bob; + // } + // @endcode + if (D->isExternC()) return; + // For shadowing external vars, make sure that we point to the global + // declaration, not a locally scoped extern declaration. + for (VarDecl::redecl_iterator + I = shadowedVar->redecls_begin(), E = shadowedVar->redecls_end(); + I != E; ++I) + if (I->isFileVarDecl()) { + ShadowedDecl = *I; + break; + } + } + + DeclContext *OldDC = ShadowedDecl->getDeclContext(); + // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. Modified: cfe/trunk/test/Sema/warn-shadow.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-shadow.c?rev=124580&r1=124579&r2=124580&view=diff ============================================================================== --- cfe/trunk/test/Sema/warn-shadow.c (original) +++ cfe/trunk/test/Sema/warn-shadow.c Mon Jan 31 01:04:50 2011 @@ -49,8 +49,13 @@ void test6(void (*f)(int i)) {} void test7(void *context, void (*callback)(void *context)) {} +extern int bob; // expected-note {{previous declaration is here}} + // rdar://8883302 -extern int bob; void rdar8883302() { extern int bob; // don't warn for shadowing. } + +void test8() { + int bob; // expected-warning {{declaration shadows a variable in the global scope}} +} From akyrtzi at gmail.com Sun Jan 30 23:04:54 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:04:54 -0000 Subject: [cfe-commits] r124581 - in /cfe/trunk: lib/Sema/SemaDecl.cpp test/SemaCXX/warn-shadow.cpp Message-ID: <20110131070455.1FEA42A6C12D@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:04:54 2011 New Revision: 124581 URL: http://llvm.org/viewvc/llvm-project?rev=124581&view=rev Log: Don't warn that variables in C++ static member functions shadow fields. Fixes rdar://8900456. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/SemaCXX/warn-shadow.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=124581&r1=124580&r2=124581&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan 31 01:04:54 2011 @@ -3129,6 +3129,12 @@ if (!isa(ShadowedDecl) && !isa(ShadowedDecl)) return; + // Fields are not shadowed by variables in C++ static methods. + if (isa(ShadowedDecl)) + if (CXXMethodDecl *MD = dyn_cast(NewDC)) + if (MD->isStatic()) + return; + if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) if (shadowedVar->isExternC()) { // Don't warn for this case: Modified: cfe/trunk/test/SemaCXX/warn-shadow.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-shadow.cpp?rev=124581&r1=124580&r2=124581&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-shadow.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-shadow.cpp Mon Jan 31 01:04:54 2011 @@ -42,3 +42,16 @@ int data; static int field; }; + +// rdar://8900456 +namespace rdar8900456 { +struct Foo { + static void Baz(); +private: + int Bar; +}; + +void Foo::Baz() { + double Bar = 12; // Don't warn. +} +} From akyrtzi at gmail.com Sun Jan 30 23:05:00 2011 From: akyrtzi at gmail.com (Argyrios Kyrtzidis) Date: Mon, 31 Jan 2011 07:05:00 -0000 Subject: [cfe-commits] r124582 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDeclCXX.cpp test/SemaCXX/destructor.cpp Message-ID: <20110131070500.A155E2A6C12C@llvm.org> Author: akirtzidis Date: Mon Jan 31 01:05:00 2011 New Revision: 124582 URL: http://llvm.org/viewvc/llvm-project?rev=124582&view=rev Log: Warn if the class has virtual methods but non-virtual destructor. Addresses rdar://8756445. Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaCXX/destructor.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=124582&r1=124581&r2=124582&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Jan 31 01:05:00 2011 @@ -80,7 +80,7 @@ def InitializerOverrides : DiagGroup<"initializer-overrides">; def NonNull : DiagGroup<"nonnull">; def : DiagGroup<"nonportable-cfstrings">; -def : DiagGroup<"non-virtual-dtor">; +def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124582&r1=124581&r2=124582&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 31 01:05:00 2011 @@ -2756,6 +2756,9 @@ def warn_exception_caught_by_earlier_handler : Warning< "exception of type %0 will be caught by earlier handler">; def note_previous_exception_handler : Note<"for type %0">; +def warn_non_virtual_dtor : Warning< + "%0 has virtual functions but non-virtual destructor">, + InGroup, DefaultIgnore; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124582&r1=124581&r2=124582&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan 31 01:05:00 2011 @@ -2769,6 +2769,14 @@ } } } + + // Warn if the class has virtual methods but non-virtual destructor. + if (Record->isDynamicClass()) { + CXXDestructorDecl *dtor = Record->getDestructor(); + if (!(dtor && dtor->isVirtual())) + Diag(dtor ? dtor->getLocation() : Record->getLocation(), + diag::warn_non_virtual_dtor) << Context.getRecordType(Record); + } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Modified: cfe/trunk/test/SemaCXX/destructor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=124582&r1=124581&r2=124582&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/destructor.cpp (original) +++ cfe/trunk/test/SemaCXX/destructor.cpp Mon Jan 31 01:05:00 2011 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wnon-virtual-dtor -verify %s class A { public: ~A(); @@ -120,3 +120,31 @@ b->~B(); } } + +namespace nonvirtualdtor { +struct S1 { // expected-warning {{has virtual functions but non-virtual destructor}} + virtual void m(); +}; + +struct S2 { + ~S2(); // expected-warning {{has virtual functions but non-virtual destructor}} + virtual void m(); +}; + +struct S3 : public S1 { // expected-warning {{has virtual functions but non-virtual destructor}} + virtual void m(); +}; + +struct S4 : public S2 { // expected-warning {{has virtual functions but non-virtual destructor}} + virtual void m(); +}; + +struct B { + virtual ~B(); + virtual void m(); +}; + +struct S5 : public B { + virtual void m(); +}; +}