From 54a025488774f15799f57ea3657d02b5149e7f45 Mon Sep 17 00:00:00 2001 From: Alexis Hunt Date: Wed, 25 Nov 2009 04:20:27 +0000 Subject: [PATCH] Parse C++ member check attributes - base_check, hiding, and override. The attributes are currently ignored. llvm-svn: 89837 --- clang/include/clang/AST/Attr.h | 8 + .../clang/Basic/DiagnosticSemaKinds.td | 9 +- clang/include/clang/Parse/AttributeList.h | 3 + clang/lib/Frontend/PCHReaderDecl.cpp | 3 + clang/lib/Frontend/PCHWriter.cpp | 5 + clang/lib/Parse/AttributeList.cpp | 15 +- clang/lib/Parse/ParseDeclCXX.cpp | 7 +- clang/lib/Sema/SemaDeclAttr.cpp | 168 +++++++++++++----- clang/test/SemaCXX/attr-cxx0x.cpp | 12 ++ 9 files changed, 177 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 35f9b330ddd5..f8c2aa9c69ee 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -49,6 +49,7 @@ public: AnalyzerNoReturn, // Clang-specific. Annotate, AsmLabel, // Represent GCC asm label extension. + BaseCheck, Blocks, CDecl, Cleanup, @@ -63,6 +64,7 @@ public: Format, FormatArg, GNUInline, + Hiding, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with Malloc, NoDebug, @@ -72,6 +74,7 @@ public: NoThrow, ObjCException, ObjCNSObject, + Override, CFReturnsRetained, // Clang/Checker-specific. NSReturnsRetained, // Clang/Checker-specific. Overloadable, // Clang-specific @@ -558,6 +561,11 @@ public: DEF_SIMPLE_ATTR(CFReturnsRetained); DEF_SIMPLE_ATTR(NSReturnsRetained); +// C++0x member checking attributes. +DEF_SIMPLE_ATTR(BaseCheck); +DEF_SIMPLE_ATTR(Hiding); +DEF_SIMPLE_ATTR(Override); + #undef DEF_SIMPLE_ATTR } // end namespace clang diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c3b504592fa8..69a22b504aa9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -551,6 +551,9 @@ def err_auto_not_allowed : Error< "|class member|exception declaration|template parameter|block literal}0">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; + +// C++0x attributes +def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; // C++0x [[final]] def err_final_function_overridden : Error< @@ -646,12 +649,14 @@ 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}1 types">; + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}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|" - "virtual method or class|function, method, or parameter}1 types">; + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}1 types">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; diff --git a/clang/include/clang/Parse/AttributeList.h b/clang/include/clang/Parse/AttributeList.h index e273cadff1da..ecaa6aee470b 100644 --- a/clang/include/clang/Parse/AttributeList.h +++ b/clang/include/clang/Parse/AttributeList.h @@ -59,6 +59,7 @@ public: AT_always_inline, AT_analyzer_noreturn, AT_annotate, + AT_base_check, AT_blocks, AT_carries_dependency, AT_cdecl, @@ -75,6 +76,7 @@ public: AT_format, AT_format_arg, AT_gnu_inline, + AT_hiding, AT_malloc, AT_mode, AT_nodebug, @@ -85,6 +87,7 @@ public: AT_nothrow, AT_nsobject, AT_objc_exception, + AT_override, AT_cf_returns_retained, // Clang-specific. AT_ns_returns_retained, // Clang-specific. AT_objc_gc, diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 328bb611badc..03f3b4767994 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -441,6 +441,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(AnalyzerNoReturn); STRING_ATTR(Annotate); STRING_ATTR(AsmLabel); + SIMPLE_ATTR(BaseCheck); case Attr::Blocks: New = ::new (*Context) BlocksAttr( @@ -485,6 +486,7 @@ Attr *PCHReader::ReadAttributes() { } SIMPLE_ATTR(GNUInline); + SIMPLE_ATTR(Hiding); case Attr::IBOutletKind: New = ::new (*Context) IBOutletAttr(); @@ -518,6 +520,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(CFReturnsRetained); SIMPLE_ATTR(NSReturnsRetained); SIMPLE_ATTR(Overloadable); + SIMPLE_ATTR(Override); SIMPLE_ATTR(Packed); UNSIGNED_ATTR(PragmaPack); SIMPLE_ATTR(Pure); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index d60af61bd8b3..06727c4a50d2 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -1764,6 +1764,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { AddString(cast(Attr)->getLabel(), Record); break; + case Attr::BaseCheck: + break; + case Attr::Blocks: Record.push_back(cast(Attr)->getType()); // FIXME: stable break; @@ -1817,6 +1820,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { } case Attr::GNUInline: + case Attr::Hiding: case Attr::IBOutletKind: case Attr::Malloc: case Attr::NoDebug: @@ -1837,6 +1841,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::CFReturnsRetained: case Attr::NSReturnsRetained: case Attr::Overloadable: + case Attr::Override: break; case Attr::PragmaPack: diff --git a/clang/lib/Parse/AttributeList.cpp b/clang/lib/Parse/AttributeList.cpp index 7e2935c2e025..df48e3a7861f 100644 --- a/clang/lib/Parse/AttributeList.cpp +++ b/clang/lib/Parse/AttributeList.cpp @@ -65,11 +65,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("final", AT_final) .Case("cdecl", AT_cdecl) .Case("const", AT_const) - .Case("packed", AT_packed) - .Case("malloc", AT_malloc) - .Case("format", AT_format) - .Case("unused", AT_unused) .Case("blocks", AT_blocks) + .Case("format", AT_format) + .Case("hiding", AT_hiding) + .Case("malloc", AT_malloc) + .Case("packed", AT_packed) + .Case("unused", AT_unused) .Case("aligned", AT_aligned) .Case("cleanup", AT_cleanup) .Case("nodebug", AT_nodebug) @@ -80,15 +81,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("section", AT_section) .Case("stdcall", AT_stdcall) .Case("annotate", AT_annotate) - .Case("noreturn", AT_noreturn) - .Case("noinline", AT_noinline) .Case("fastcall", AT_fastcall) .Case("iboutlet", AT_IBOutlet) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("override", AT_override) .Case("sentinel", AT_sentinel) .Case("NSObject", AT_nsobject) .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) .Case("destructor", AT_destructor) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 2a3b5d665cc4..59cb90d6d054 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1699,9 +1699,12 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { switch(AttributeList::getKind(AttrName)) { // No arguments - case AttributeList::AT_noreturn: + case AttributeList::AT_base_check: + case AttributeList::AT_carries_dependency: case AttributeList::AT_final: - case AttributeList::AT_carries_dependency: { + case AttributeList::AT_hiding: + case AttributeList::AT_noreturn: + case AttributeList::AT_override: { if (Tok.is(tok::l_paren)) { Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) << AttrName->getName(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 2405d52890c9..f40f125683b7 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1825,14 +1825,93 @@ static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 7 /*virtual method or class*/; return; } - - // FIXME: Check that it's not specified more than once in an attribute- - // specifier and that it conforms to the C++0x rules for - // redeclarations. + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final"; + return; + } d->addAttr(::new (S.Context) FinalAttr()); } +//===----------------------------------------------------------------------===// +// C++0x member checking attributes +//===----------------------------------------------------------------------===// + +static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d)) { + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 9 /*class*/; + return; + } + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check"; + return; + } + + d->addAttr(::new (S.Context) BaseCheckAttr()); +} + +static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d->getDeclContext())) { + // FIXME: It's not the type that's the problem + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 11 /*member*/; + return; + } + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding"; + return; + } + + d->addAttr(::new (S.Context) HidingAttr()); +} + +static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d) || !cast(d)->isVirtual()) { + // FIXME: It's not the type that's the problem + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 10 /*virtual method*/; + return; + } + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override"; + return; + } + + d->addAttr(::new (S.Context) OverrideAttr()); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -1894,34 +1973,37 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; - case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; - case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; + case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; + case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; case AttributeList::AT_always_inline: HandleAlwaysInlineAttr (D, Attr, S); break; case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break; case AttributeList::AT_carries_dependency: - HandleDependencyAttr (D, Attr, S); break; - case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; - case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break; - case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break; - case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break; - case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break; - case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break; + HandleDependencyAttr (D, Attr, S); break; + case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; + case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; + case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; + case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; + case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break; + case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break; case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; - case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; - case AttributeList::AT_final: HandleFinalAttr (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_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; - case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; - case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; - case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; - case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; + case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; + case AttributeList::AT_final: HandleFinalAttr (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_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; + case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break; + case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; + case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; + case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; + case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; + case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; + case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break; // Checker-specific. case AttributeList::AT_ns_returns_retained: @@ -1931,18 +2013,18 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_reqd_wg_size: HandleReqdWorkGroupSize(D, Attr, S); break; - case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; - case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; - case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; - case AttributeList::AT_unavailable: HandleUnavailableAttr(D, Attr, S); break; - case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; - case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; - case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break; - case AttributeList::AT_visibility: HandleVisibilityAttr(D, Attr, S); break; + case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; + case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; + case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; + case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; + case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; + case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; + case AttributeList::AT_vector_size: HandleVectorSizeAttr (D, Attr, S); break; + case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break; case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; - case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; - case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break; + case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; case AttributeList::AT_transparent_union: HandleTransparentUnionAttr(D, Attr, S); break; @@ -1950,15 +2032,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, HandleObjCExceptionAttr(D, Attr, S); break; case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; - case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; - case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; - case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; - case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; - case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; - case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; - case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; - case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; - case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; + case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; + case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; + case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; + case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; + case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; + case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; + case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; + case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; + case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; case AttributeList::IgnoredAttribute: case AttributeList::AT_no_instrument_function: // Interacts with -pg. // Just ignore diff --git a/clang/test/SemaCXX/attr-cxx0x.cpp b/clang/test/SemaCXX/attr-cxx0x.cpp index fed0ad42d836..da52d338cfbc 100644 --- a/clang/test/SemaCXX/attr-cxx0x.cpp +++ b/clang/test/SemaCXX/attr-cxx0x.cpp @@ -22,3 +22,15 @@ static_assert(alignof(align_small) == alignof(int), "j's alignment is wrong"); static_assert(alignof(align_multiple) == 8, "l's alignment is wrong"); static_assert(alignof(align_member) == 8, "quuux's alignment is wrong"); static_assert(sizeof(align_member) == 8, "quuux's size is wrong"); + +int bc_fail [[base_check]]; // expected-error {{'base_check' attribute only applies to class types}} +int hiding_fail [[hiding]]; // expected-error {{'hiding' attribute only applies to member types}} +int override_fail [[override]]; // expected-error {{'override' attribute only applies to virtual method types}} + +struct base { + virtual void function(); + virtual void other_function(); +}; + +struct [[base_check, base_check]] bc : base { // expected-error {{'base_check' attribute cannot be repeated}} +}; \ No newline at end of file