From: Aaron Ballman Date: Wed, 22 May 2013 23:25:32 +0000 (+0000) Subject: Adding in parsing and the start of semantic support for __sptr and __uptr pointer... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa9df09729fb8aee3e645549e95fcb413306a7aa;p=clang Adding in parsing and the start of semantic support for __sptr and __uptr pointer type qualifiers. This patch also fixes the correlated __ptr32 and __ptr64 pointer qualifiers so that they are truly type attributes instead of declaration attributes. For more information about __sptr and __uptr, see MSDN: http://msdn.microsoft.com/en-us/library/aa983399.aspx Patch reviewed by Richard Smith. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182535 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 93c287fd18..c3e86532c3 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -3335,7 +3335,11 @@ public: attr_thiscall, attr_pascal, attr_pnaclcall, - attr_inteloclbicc + attr_inteloclbicc, + attr_ptr32, + attr_ptr64, + attr_sptr, + attr_uptr }; private: @@ -3365,6 +3369,17 @@ public: bool isSugared() const { return true; } QualType desugar() const { return getEquivalentType(); } + bool isMSTypeSpec() const { + switch (getAttrKind()) { + default: return false; + case attr_ptr32: + case attr_ptr64: + case attr_sptr: + case attr_uptr: + return true; + } + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAttrKind(), ModifiedType, EquivalentType); } diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 0490314852..a42b272c72 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -978,6 +978,14 @@ def Ptr64 : InheritableAttr { let Spellings = [Keyword<"__ptr64">]; } +def SPtr : InheritableAttr { + let Spellings = [Keyword<"__sptr">]; +} + +def UPtr : InheritableAttr { + let Spellings = [Keyword<"__uptr">]; +} + class MSInheritanceAttr : InheritableAttr; def SingleInheritance : MSInheritanceAttr { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e12851dc53..7ea87d5fd6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1788,7 +1788,9 @@ def err_attribute_uuid_malformed_guid : Error< def warn_nonnull_pointers_only : Warning< "nonnull attribute only applies to pointer arguments">; def err_attribute_pointers_only : Error< - "'%0' attribute only applies to pointer arguments">; + "%0 attribute only applies to pointer arguments">; +def err_attribute_no_member_pointers : Error< + "%0 attribute cannot be used with pointers to members">; def err_attribute_invalid_implicit_this_argument : Error< "'%0' attribute is invalid for the implicit this argument">; def err_ownership_type : Error< @@ -6192,6 +6194,9 @@ def warn_collection_expr_type : Warning< def err_invalid_conversion_between_ext_vectors : Error< "invalid conversion between ext-vector type %0 and %1">; +def warn_duplicate_attribute_exact : Warning< + "attribute %0 is already applied">, InGroup; + def warn_duplicate_attribute : Warning< "attribute %0 is already applied with different parameters">, InGroup; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 0dbff81d34..c52a02eabb 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -509,6 +509,8 @@ ALIAS("__volatile__" , volatile , KEYALL) // Microsoft extensions which should be disabled in strict conformance mode KEYWORD(__ptr64 , KEYMS) KEYWORD(__ptr32 , KEYMS) +KEYWORD(__sptr , KEYMS) +KEYWORD(__uptr , KEYMS) KEYWORD(__w64 , KEYMS) KEYWORD(__uuidof , KEYMS | KEYBORLAND) KEYWORD(__try , KEYMS | KEYBORLAND) diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 043707622b..56a66f1efc 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1072,6 +1072,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, return printBefore(T->getEquivalentType(), OS); printBefore(T->getModifiedType(), OS); + + if (T->isMSTypeSpec()) { + switch (T->getAttrKind()) { + default: return; + case AttributedType::attr_ptr32: OS << " __ptr32"; break; + case AttributedType::attr_ptr64: OS << " __ptr64"; break; + case AttributedType::attr_sptr: OS << " __sptr"; break; + case AttributedType::attr_uptr: OS << " __uptr"; break; +} + spaceBeforePlaceHolder(OS); + } } void TypePrinter::printAttributedAfter(const AttributedType *T, @@ -1082,8 +1093,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, return printAfter(T->getEquivalentType(), OS); // TODO: not all attributes are GCC-style attributes. + if (T->isMSTypeSpec()) + return; + OS << " __attribute__(("; switch (T->getAttrKind()) { + default: llvm_unreachable("This attribute should have been handled already"); case AttributedType::attr_address_space: OS << "address_space("; OS << T->getEquivalentType().getAddressSpace(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8ad028155a..cb0dc374ae 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -601,7 +601,8 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || - Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { + Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) || + Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, @@ -2711,6 +2712,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; } + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___w64: @@ -4145,6 +4148,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: @@ -4321,6 +4326,8 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, ParseOpenCLQualifiers(DS); break; + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index dff3b64c5b..37e1412be7 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1122,6 +1122,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index be4bd0e3b7..684148879b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -4252,7 +4252,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx); if (!BufferTy->isPointerType()) { S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << AttrName; + << Attr.getName(); } } @@ -4695,15 +4695,7 @@ static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; AttributeList::Kind Kind = Attr.getKind(); - if (Kind == AttributeList::AT_Ptr32) - D->addAttr( - ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_Ptr64) - D->addAttr( - ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_Win64) + if (Kind == AttributeList::AT_Win64) D->addAttr( ::new (S.Context) Win64Attr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -4754,6 +4746,10 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VectorSize: case AttributeList::AT_NeonVectorType: case AttributeList::AT_NeonPolyVectorType: + case AttributeList::AT_Ptr32: + case AttributeList::AT_Ptr64: + case AttributeList::AT_SPtr: + case AttributeList::AT_UPtr: // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; @@ -4946,8 +4942,6 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, handleInheritanceAttr(S, D, Attr); break; case AttributeList::AT_Win64: - case AttributeList::AT_Ptr32: - case AttributeList::AT_Ptr64: handlePortabilityAttr(S, D, Attr); break; case AttributeList::AT_ForceInline: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e4eafc5ee7..39664d0491 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -108,7 +108,14 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_Regparm: \ case AttributeList::AT_Pcs: \ case AttributeList::AT_PnaclCall: \ - case AttributeList::AT_IntelOclBicc \ + case AttributeList::AT_IntelOclBicc + +// Microsoft-specific type qualifiers. +#define MS_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_Ptr32: \ + case AttributeList::AT_Ptr64: \ + case AttributeList::AT_SPtr: \ + case AttributeList::AT_UPtr namespace { /// An object which stores processing state for the entire @@ -292,6 +299,10 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); +static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type); + static bool handleObjCGCTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); @@ -626,6 +637,10 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); break; + MS_TYPE_ATTRS_CASELIST: + // Microsoft type attributes cannot go after the declarator-id. + continue; + default: break; } @@ -3298,6 +3313,14 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_PnaclCall; case AttributedType::attr_inteloclbicc: return AttributeList::AT_IntelOclBicc; + case AttributedType::attr_ptr32: + return AttributeList::AT_Ptr32; + case AttributedType::attr_ptr64: + return AttributeList::AT_Ptr64; + case AttributedType::attr_sptr: + return AttributeList::AT_SPtr; + case AttributedType::attr_uptr: + return AttributeList::AT_UPtr; } llvm_unreachable("unexpected attribute kind!"); } @@ -4174,6 +4197,69 @@ namespace { }; } +static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, + AttributeList &Attr, + QualType &Type) { + Sema &S = State.getSema(); + + AttributeList::Kind Kind = Attr.getKind(); + QualType Desugared = Type; + const AttributedType *AT = dyn_cast(Type); + while (AT) { + AttributedType::Kind CurAttrKind = AT->getAttrKind(); + + // You cannot specify duplicate type attributes, so if the attribute has + // already been applied, flag it. + if (getAttrListKind(CurAttrKind) == Kind) { + S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact) + << Attr.getName(); + return true; + } + + // You cannot have both __sptr and __uptr on the same type, nor can you + // have __ptr32 and __ptr64. + if ((CurAttrKind == AttributedType::attr_ptr32 && + Kind == AttributeList::AT_Ptr64) || + (CurAttrKind == AttributedType::attr_ptr64 && + Kind == AttributeList::AT_Ptr32)) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "'__ptr32'" << "'__ptr64'"; + return true; + } else if ((CurAttrKind == AttributedType::attr_sptr && + Kind == AttributeList::AT_UPtr) || + (CurAttrKind == AttributedType::attr_uptr && + Kind == AttributeList::AT_SPtr)) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "'__sptr'" << "'__uptr'"; + return true; + } + + Desugared = AT->getEquivalentType(); + AT = dyn_cast(Desugared); + } + + // Pointer type qualifiers can only operate on pointer types, but not + // pointer-to-member types. + if (!isa(Desugared)) { + S.Diag(Attr.getLoc(), Type->isMemberPointerType() ? + diag::err_attribute_no_member_pointers : + diag::err_attribute_pointers_only) << Attr.getName(); + return true; + } + + AttributedType::Kind TAK; + switch (Kind) { + default: llvm_unreachable("Unknown attribute kind"); + case AttributeList::AT_Ptr32: TAK = AttributedType::attr_ptr32; break; + case AttributeList::AT_Ptr64: TAK = AttributedType::attr_ptr64; break; + case AttributeList::AT_SPtr: TAK = AttributedType::attr_sptr; break; + case AttributeList::AT_UPtr: TAK = AttributedType::attr_uptr; break; + } + + Type = S.Context.getAttributedType(TAK, Type, Type); + return false; +} + /// Process an individual function attribute. Returns true to /// indicate that the attribute was handled, false if it wasn't. static bool handleFunctionTypeAttr(TypeProcessingState &state, @@ -4576,12 +4662,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, break; case AttributeList::AT_Win64: - case AttributeList::AT_Ptr32: - case AttributeList::AT_Ptr64: - // FIXME: Don't ignore these. We have partial handling for them as - // declaration attributes in SemaDeclAttr.cpp; that should be moved here. attr.setUsedAsTypeAttr(); break; + MS_TYPE_ATTRS_CASELIST: + if (!handleMSPointerTypeQualifierAttr(state, attr, type)) + attr.setUsedAsTypeAttr(); + break; case AttributeList::AT_NSReturnsRetained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c index 35c63d4b55..de933f9e5d 100644 --- a/test/Parser/MicrosoftExtensions.c +++ b/test/Parser/MicrosoftExtensions.c @@ -105,3 +105,14 @@ __declspec() void quux( void ) { struct S7 s; int i = s.t; /* expected-warning {{'t' is deprecated}} */ } + +int * __sptr psp; +int * __uptr pup; +/* Either ordering is acceptable */ +int * __ptr32 __sptr psp32; +int * __ptr32 __uptr pup32; +int * __sptr __ptr64 psp64; +int * __uptr __ptr64 pup64; + +/* Legal to have nested pointer attributes */ +int * __sptr * __ptr32 ppsp32; diff --git a/test/Sema/MicrosoftCompatibility.cpp b/test/Sema/MicrosoftCompatibility.cpp index 15c25586c4..90a45dfaaf 100644 --- a/test/Sema/MicrosoftCompatibility.cpp +++ b/test/Sema/MicrosoftCompatibility.cpp @@ -2,3 +2,9 @@ // PR15845 int foo(xxx); // expected-error{{unknown type name}} + +struct cls { + char *m; +}; + +char * cls::* __uptr wrong2 = &cls::m; // expected-error {{'__uptr' attribute cannot be used with pointers to members}} diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c index 5d7330e3f7..a66d9a9eb0 100644 --- a/test/Sema/MicrosoftExtensions.c +++ b/test/Sema/MicrosoftExtensions.c @@ -102,3 +102,32 @@ void test( void ) { enum DE1 no; // no warning because E1 is not deprecated } + +int __sptr wrong1; // expected-error {{'__sptr' attribute only applies to pointer arguments}} +// The modifier must follow the asterisk +int __sptr *wrong_psp; // expected-error {{'__sptr' attribute only applies to pointer arguments}} +int * __sptr __uptr wrong2; // expected-error {{'__sptr' and '__uptr' attributes are not compatible}} +int * __sptr __sptr wrong3; // expected-warning {{attribute '__sptr' is already applied}} + +// It is illegal to overload based on the type attribute. +void ptr_func(int * __ptr32 i) {} // expected-note {{previous definition is here}} +void ptr_func(int * __ptr64 i) {} // expected-error {{redefinition of 'ptr_func'}} + +// It is also illegal to overload based on the pointer type attribute. +void ptr_func2(int * __sptr __ptr32 i) {} // expected-note {{previous definition is here}} +void ptr_func2(int * __uptr __ptr32 i) {} // expected-error {{redefinition of 'ptr_func2'}} + +int * __sptr __ptr32 __sptr wrong4; // expected-warning {{attribute '__sptr' is already applied}} + +__ptr32 int *wrong5; // expected-error {{'__ptr32' attribute only applies to pointer arguments}} + +int *wrong6 __ptr32; // expected-error {{expected ';' after top level declarator}} expected-warning {{declaration does not declare anything}} + +int * __ptr32 __ptr64 wrong7; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}} + +int * __ptr32 __ptr32 wrong8; // expected-warning {{attribute '__ptr32' is already applied}} + +int *(__ptr32 __sptr wrong9); // expected-error {{'__sptr' attribute only applies to pointer arguments}} // expected-error {{'__ptr32' attribute only applies to pointer arguments}} + +typedef int *T; +T __ptr32 wrong10; // expected-error {{'__ptr32' attribute only applies to pointer arguments}} diff --git a/test/Sema/attr-print.c b/test/Sema/attr-print.c index 2659508e56..b3bdfd72e6 100644 --- a/test/Sema/attr-print.c +++ b/test/Sema/attr-print.c @@ -13,9 +13,22 @@ void foo() __attribute__((const)); // CHECK: void bar() __attribute__((__const)); void bar() __attribute__((__const)); -// FIXME: Print these at a valid location for these attributes. -// CHECK: int *p32 __ptr32; +// CHECK: int * __ptr32 p32; int * __ptr32 p32; -// CHECK: int *p64 __ptr64; +// CHECK: int * __ptr64 p64; int * __ptr64 p64; + +// TODO: the Type Printer has no way to specify the order to print attributes +// in, and so it currently always prints them in reverse order. Fix this. +// CHECK: int * __ptr32 __uptr p32_2; +int * __uptr __ptr32 p32_2; + +// CHECK: int * __ptr64 __sptr p64_2; +int * __sptr __ptr64 p64_2; + +// CHECK: int * __ptr32 __uptr p32_3; +int * __uptr __ptr32 p32_3; + +// CHECK: int * __sptr * __ptr32 ppsp32; +int * __sptr * __ptr32 ppsp32;