From ae519c42a1e0a023be6c07ba1dc10f28e29d6bc3 Mon Sep 17 00:00:00 2001 From: DeLesley Hutchins Date: Thu, 19 Apr 2012 16:10:44 +0000 Subject: [PATCH] Thread safety analysis: split warnings into two groups: attribute warnings which are checked in the parser, and analysis warnings that require the full analysis. This allows attribute syntax to be checked independently of the full thread safety analysis. Also introduces a new warning for the case where a string is used as a lock expression; this allows the analysis to gracefully handle expressions that would otherwise cause a parse error. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155129 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 5 +- include/clang/Basic/DiagnosticSemaKinds.td | 61 +++++++------ lib/Sema/SemaDeclAttr.cpp | 94 ++++++++++----------- test/SemaCXX/warn-thread-safety-parsing.cpp | 24 +++--- 4 files changed, 96 insertions(+), 88 deletions(-) diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index c83985345b..3f6c5c0c0d 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -354,7 +354,10 @@ def Most : DiagGroup<"most", [ ]>; // Thread Safety warnings -def ThreadSafety : DiagGroup<"thread-safety">; +def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">; +def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">; +def ThreadSafety : DiagGroup<"thread-safety", + [ThreadSafetyAttributes, ThreadSafetyAnalysis]>; // Note that putting warnings in -Wall will not disable them by default. If a // warning should be active _only_ when -Wall is passed in, mark it as diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d972774628..986479921d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1656,72 +1656,79 @@ def warn_availability_version_ordering : Warning< "attribute ignored">; // Thread Safety Attributes -// Errors when parsing the attributes +def warn_thread_attribute_ignored : Warning< + "ignoring %0 attribute because its argument is invalid">, + InGroup, DefaultIgnore; +def warn_thread_attribute_argument_not_lockable : Warning< + "%0 attribute requires arguments whose type is annotated " + "with 'lockable' attribute; type here is '%1'">, + InGroup, DefaultIgnore; +def warn_thread_attribute_argument_not_class : Warning< + "%0 attribute requires arguments that are class type or point to" + " class type; type here is '%1'">, + InGroup, DefaultIgnore; +def warn_thread_attribute_decl_not_lockable : Warning< + "%0 attribute can only be applied in a context annotated " + "with 'lockable' attribute">, + InGroup, DefaultIgnore; +def warn_thread_attribute_decl_not_pointer : Warning< + "'%0' only applies to pointer types; type here is %1">, + InGroup, DefaultIgnore; def err_attribute_argument_out_of_range : Error< "%0 attribute parameter %1 is out of bounds: " "%plural{0:no parameters to index into|" "1:can only be 1, since there is one parameter|" ":must be between 1 and %2}2">; -def warn_attribute_argument_not_lockable : Warning< - "%0 attribute requires arguments whose type is annotated " - "with 'lockable' attribute; type here is '%1'">, - InGroup, DefaultIgnore; -def warn_attribute_decl_not_lockable : Warning< - "%0 attribute can only be applied in a context annotated " - "with 'lockable' attribute">, - InGroup, DefaultIgnore; -def warn_attribute_argument_not_class : Warning< - "%0 attribute requires arguments that are class type or point to" - " class type; type here is '%1'">, - InGroup, DefaultIgnore; + +// Thread Safety Analysis def warn_unlock_but_no_lock : Warning< "unlocking '%0' that was not locked">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_double_lock : Warning< "locking '%0' that is already locked">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_no_unlock : Warning< "mutex '%0' is still locked at the end of function">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; // FIXME: improve the error message about locks not in scope def warn_lock_some_predecessors : Warning< "mutex '%0' is not locked on every path through here">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_expecting_lock_held_on_loop : Warning< "expecting mutex '%0' to be locked at start of each loop">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_locked_here : Note<"mutex acquired here">; def warn_lock_exclusive_and_shared : Warning< "mutex '%0' is locked exclusively and shared in the same scope">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_lock_exclusive_and_shared : Note< "the other lock of mutex '%0' is here">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_variable_requires_lock : Warning< "%select{reading|writing}2 variable '%0' requires locking " "%select{'%1'|'%1' exclusively}2">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_var_deref_requires_lock : Warning< "%select{reading|writing}2 the value pointed to by '%0' requires locking " "%select{'%1'|'%1' exclusively}2">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_variable_requires_any_lock : Warning< "%select{reading|writing}1 variable '%0' requires locking " "%select{any mutex|any mutex exclusively}1">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_var_deref_requires_any_lock : Warning< "%select{reading|writing}1 the value pointed to by '%0' requires locking " "%select{any mutex|any mutex exclusively}1">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_fun_requires_lock : Warning< "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_fun_excludes_mutex : Warning< "cannot call function '%0' while mutex '%1' is locked">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_cannot_resolve_lock : Warning< "cannot resolve lock expression">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def warn_impcast_vector_scalar : Warning< diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 5c6ddd2cb9..3770b3c373 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -243,12 +243,13 @@ static bool isIntOrBool(Expr *Exp) { /// Note that this function may produce an error message. /// \return true if the Decl is a pointer type; false otherwise /// -static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) { +static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, + const AttributeList &Attr) { if (const ValueDecl *vd = dyn_cast(D)) { QualType QT = vd->getType(); if (QT->isAnyPointerType()) return true; - S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) << Attr.getName()->getName() << QT; } else { S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl) @@ -271,14 +272,14 @@ static const RecordType *getRecordType(QualType QT) { } /// \brief Thread Safety Analysis: Checks that the passed in RecordType -/// resolves to a lockable object. May flag an error. +/// resolves to a lockable object. static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, QualType Ty) { const RecordType *RT = getRecordType(Ty); // Warn if could not get record type for this argument. if (!RT) { - S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_class) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class) << Attr.getName() << Ty.getAsString(); return; } @@ -287,18 +288,18 @@ static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, return; // Warn if the type is not lockable. if (!RT->getDecl()->getAttr()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_lockable) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) << Attr.getName() << Ty.getAsString(); return; } } /// \brief Thread Safety Analysis: Checks that all attribute arguments, starting -/// from Sidx, resolve to a lockable object. May flag an error. +/// from Sidx, resolve to a lockable object. /// \param Sidx The attribute argument index to start checking with. /// \param ParamIdxOk Whether an argument can be indexing into a function /// parameter list. -static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, +static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, const AttributeList &Attr, SmallVectorImpl &Args, int Sidx = 0, @@ -307,11 +308,19 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, Expr *ArgExp = Attr.getArg(Idx); if (ArgExp->isTypeDependent()) { - // FIXME -- need to processs this again on template instantiation + // FIXME -- need to check this again on template instantiation Args.push_back(ArgExp); continue; } + if (isa(ArgExp)) { + // We allow constant strings to be used as a placeholder for expressions + // that are not valid C++ syntax, but warn that they are ignored. + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) << + Attr.getName(); + continue; + } + QualType ArgTy = ArgExp->getType(); // First see if we can just cast to record type, or point to record type. @@ -329,7 +338,7 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) << Attr.getName() << Idx + 1 << NumParams; - return false; + continue; } ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); } @@ -339,7 +348,6 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, Args.push_back(ArgExp); } - return true; } //===----------------------------------------------------------------------===// @@ -364,7 +372,7 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, return; } - if (pointer && !checkIsPointer(S, D, Attr)) + if (pointer && !threadSafetyCheckIsPointer(S, D, Attr)) return; if (pointer) @@ -380,8 +388,6 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, if (!checkAttributeNumArgs(S, Attr, 1)) return; - Expr *Arg = Attr.getArg(0); - // D must be either a member field or global (potentially shared) variable. if (!mayBeSharedVariable(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -389,12 +395,16 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, return; } - if (pointer && !checkIsPointer(S, D, Attr)) + if (pointer && !threadSafetyCheckIsPointer(S, D, Attr)) return; - if (!Arg->isTypeDependent()) { - checkForLockableRecord(S, D, Attr, Arg->getType()); - } + SmallVector Args; + // check that all arguments are lockable objects + checkAttrArgsAreLockableObjs(S, D, Attr, Args); + unsigned Size = Args.size(); + if (Size != 1) + return; + Expr *Arg = Args[0]; if (pointer) D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), @@ -442,7 +452,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D, } static void handleNoAddressSafetyAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const AttributeList &Attr) { assert(!Attr.isInvalid()); if (!checkAttributeNumArgs(S, Attr, 0)) @@ -473,25 +483,24 @@ static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, return; } - // Check that this attribute only applies to lockable types + // Check that this attribute only applies to lockable types. QualType QT = VD->getType(); if (!QT->isDependentType()) { const RecordType *RT = getRecordType(QT); if (!RT || !RT->getDecl()->getAttr()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_decl_not_lockable) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << Attr.getName(); return; } } SmallVector Args; - // check that all arguments are lockable objects - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) - return; - + // Check that all arguments are lockable objects. + checkAttrArgsAreLockableObjs(S, D, Attr, Args); unsigned Size = Args.size(); - assert(Size == Attr.getNumArgs()); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; + if (Size == 0) + return; + Expr **StartArg = &Args[0]; if (before) D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context, @@ -516,11 +525,8 @@ static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, // check that all arguments are lockable objects SmallVector Args; - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) - return; - + checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); unsigned Size = Args.size(); - assert(Size == Attr.getNumArgs()); Expr **StartArg = Size == 0 ? 0 : &Args[0]; if (exclusive) @@ -540,7 +546,6 @@ static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; @@ -555,9 +560,7 @@ static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, SmallVector Args; // check that all arguments are lockable objects - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1)) - return; - + checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1); unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? 0 : &Args[0]; @@ -588,12 +591,11 @@ static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, // check that all arguments are lockable objects SmallVector Args; - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) - return; - + checkAttrArgsAreLockableObjs(S, D, Attr, Args); unsigned Size = Args.size(); - assert(Size == Attr.getNumArgs()); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; + if (Size == 0) + return; + Expr **StartArg = &Args[0]; if (exclusive) D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(), @@ -619,11 +621,8 @@ static void handleUnlockFunAttr(Sema &S, Decl *D, // check that all arguments are lockable objects SmallVector Args; - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) - return; - + checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); unsigned Size = Args.size(); - assert(Size == Attr.getNumArgs()); Expr **StartArg = Size == 0 ? 0 : &Args[0]; D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context, @@ -668,12 +667,11 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, // check that all arguments are lockable objects SmallVector Args; - if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) - return; - + checkAttrArgsAreLockableObjs(S, D, Attr, Args); unsigned Size = Args.size(); - assert(Size == Attr.getNumArgs()); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; + if (Size == 0) + return; + Expr **StartArg = &Args[0]; D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size)); diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp index c2fa1d77a0..a9e58dd872 100644 --- a/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -343,7 +343,7 @@ int gb_var_arg_8 __attribute__((guarded_by(muPointer))); int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \ // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'int'}} int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \ - // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'const char [3]'}} + // expected-warning {{ignoring 'guarded_by' attribute because its argument is invalid}} int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \ // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'class Mu **'}} int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \ @@ -414,7 +414,7 @@ int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer))); int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \ // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}} int * pgb_var_arg_bad_2 __attribute__((pt_guarded_by("mu"))); // \ - // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'pt_guarded_by' attribute because its argument is invalid}} int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \ // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}} int * pgb_var_arg_bad_4 __attribute__((pt_guarded_by(umu))); // \ @@ -475,7 +475,7 @@ Mu aa_var_arg_8 __attribute__((acquired_after(muPointer))); Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \ // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}} Mu aa_var_arg_bad_2 __attribute__((acquired_after("mu"))); // \ - // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'acquired_after' attribute because its argument is invalid}} Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \ // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}} Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \ @@ -538,7 +538,7 @@ Mu ab_var_arg_8 __attribute__((acquired_before(muPointer))); Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \ // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}} Mu ab_var_arg_bad_2 __attribute__((acquired_before("mu"))); // \ - // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'acquired_before' attribute because its argument is invalid}} Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \ // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}} Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \ @@ -603,7 +603,7 @@ int elf_function_9(Mu x, Mu y) __attribute__((exclusive_lock_function(1,2))); // illegal attribute arguments int elf_function_bad_2() __attribute__((exclusive_lock_function("mu"))); // \ - // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'exclusive_lock_function' attribute because its argument is invalid}} int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \ // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}} int elf_function_bad_4() __attribute__((exclusive_lock_function(umu))); // \ @@ -675,7 +675,7 @@ int slf_function_9(Mu x, Mu y) __attribute__((shared_lock_function(1,2))); // illegal attribute arguments int slf_function_bad_2() __attribute__((shared_lock_function("mu"))); // \ - // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'shared_lock_function' attribute because its argument is invalid}} int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \ // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}} int slf_function_bad_4() __attribute__((shared_lock_function(umu))); // \ @@ -757,7 +757,7 @@ int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePoint // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}} int etf_function_bad_4() __attribute__((exclusive_trylock_function(1, "mu"))); // \ - // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}} int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \ // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}} int etf_function_bad_6() __attribute__((exclusive_trylock_function(1, umu))); // \ @@ -831,7 +831,7 @@ int stf_function_bad_3() __attribute__((shared_trylock_function(muDoublePointer) // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}} int stf_function_bad_4() __attribute__((shared_trylock_function(1, "mu"))); // \ - // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}} int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \ // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}} int stf_function_bad_6() __attribute__((shared_trylock_function(1, umu))); // \ @@ -894,7 +894,7 @@ int uf_function_9(Mu x, Mu y) __attribute__((unlock_function(1,2))); // illegal attribute arguments int uf_function_bad_2() __attribute__((unlock_function("mu"))); // \ - // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'unlock_function' attribute because its argument is invalid}} int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \ // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}} int uf_function_bad_4() __attribute__((unlock_function(umu))); // \ @@ -1037,7 +1037,7 @@ int le_function_8() __attribute__((locks_excluded(muPointer))); int le_function_bad_1() __attribute__((locks_excluded(1))); // \ // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}} int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \ - // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'locks_excluded' attribute because its argument is invalid}} int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \ // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}} int le_function_bad_4() __attribute__((locks_excluded(umu))); // \ @@ -1104,7 +1104,7 @@ int elr_function_8() __attribute__((exclusive_locks_required(muPointer))); int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \ // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}} int elr_function_bad_2() __attribute__((exclusive_locks_required("mu"))); // \ - // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'exclusive_locks_required' attribute because its argument is invalid}} int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \ // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}} int elr_function_bad_4() __attribute__((exclusive_locks_required(umu))); // \ @@ -1172,7 +1172,7 @@ int slr_function_8() __attribute__((shared_locks_required(muPointer))); int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \ // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}} int slr_function_bad_2() __attribute__((shared_locks_required("mu"))); // \ - // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}} + // expected-warning {{ignoring 'shared_locks_required' attribute because its argument is invalid}} int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \ // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}} int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \