Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2298,6 +2298,19 @@ // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + if (DeclaratorInfo.isFunctionDeclarator()) { + auto &Function = DeclaratorInfo.getFunctionTypeInfo(); + auto &MQ = Function.getOrCreateMethodQualifiers(); + for (auto &attr : DeclaratorInfo.getAttributes()) { + if (attr.getKind() == ParsedAttr::AT_AddressSpace) { + auto AU = attr.getArg(0); + MQ.getAttributes().addNew(attr.getName(), attr.getRange(), + attr.getScopeName(), attr.getScopeLoc(), &AU, + attr.getNumArgs(), ParsedAttr::AS_GNU); + attr.setInvalid(); + } + } + } // For compatibility with code written to older Clang, also accept a // virt-specifier *after* the GNU attributes. Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3939,6 +3939,9 @@ return false; } +static bool ProcessAddressSpaceAttribute(Sema &S, const ParsedAttr &Attr, + LangAS &ASIdx, Expr *&ASArgExpr); + static TypeSourceInfo * GetTypeSourceInfoForDeclarator(TypeProcessingState &State, QualType T, TypeSourceInfo *ReturnTypeInfo); @@ -4857,25 +4860,46 @@ state.getDeclarator().getContext() == DeclaratorContext::MemberContext; }; - - if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) { - LangAS ASIdx = LangAS::Default; + if (IsClassMember()) { + auto CheckAS = + state.getSema().getLangOpts().OpenCLCPlusPlus + ? std::function{[&](ParsedAttr + &attr) { + return attr.asOpenCLLangAS(); + }} + : std::function{ + [&](ParsedAttr &attr) { + LangAS AS = LangAS::Default; + if (attr.getKind() == ParsedAttr::AT_AddressSpace) { + Expr *ASArgExpr = nullptr; + ProcessAddressSpaceAttribute(S, attr, AS, + ASArgExpr); + // FIXME: We should extend logic to cover this case + // or at least give an error? + if (ASArgExpr->isValueDependent()) + ; + } + return AS; + }}; + LangAS AS = LangAS::Default; // Take address space attr if any and mark as invalid to avoid adding // them later while creating QualType. if (FTI.MethodQualifiers) for (ParsedAttr &attr : FTI.MethodQualifiers->getAttributes()) { - LangAS ASIdxNew = attr.asOpenCLLangAS(); - if (DiagnoseMultipleAddrSpaceAttributes(S, ASIdx, ASIdxNew, + LangAS ASNew = CheckAS(attr); + if (DiagnoseMultipleAddrSpaceAttributes(S, AS, ASNew, attr.getLoc())) D.setInvalidType(true); else - ASIdx = ASIdxNew; + AS = ASNew; } - // If a class member function's address space is not set, set it to - // __generic. - LangAS AS = - (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx); - EPI.TypeQuals.addAddressSpace(AS); + // For OpenCL if a class member function's address space is not set, + // set it to __generic. + if (state.getSema().getLangOpts().OpenCLCPlusPlus && + AS == LangAS::Default) + AS = LangAS::opencl_generic; + if (AS != LangAS::Default) + EPI.TypeQuals.addAddressSpace(AS); } T = Context.getFunctionType(T, ParamTys, EPI); } @@ -5836,6 +5860,43 @@ return true; } +/// Process the address space and diagnose any issues. On success its numerical +/// value and argument expression will be filled in. Returns value indicating +/// whether any diagnostic occurred. +static bool ProcessAddressSpaceAttribute(Sema &S, const ParsedAttr &Attr, + LangAS &ASIdx, Expr *&ASArgExpr) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return false; + } + + if (Attr.isArgIdent(0)) { + // Special case where the argument is a template id. + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId id; + id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); + + ExprResult AddrSpace = S.ActOnIdExpression(S.getCurScope(), SS, + TemplateKWLoc, id, false, false); + if (AddrSpace.isInvalid()) + return false; + + ASArgExpr = static_cast(AddrSpace.get()); + } else { + ASArgExpr = static_cast(Attr.getArgAsExpr(0)); + } + + if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) { + Attr.setInvalid(); + return false; + } + return true; +} + /// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression /// is uninstantiated. If instantiated it will apply the appropriate address /// space to the type. This function allows dependent template variables to be @@ -5887,9 +5948,8 @@ return; } - LangAS ASIdx; + LangAS ASIdx = LangAS::Default; if (Attr.getKind() == ParsedAttr::AT_AddressSpace) { - // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr @@ -5897,30 +5957,9 @@ Attr.setInvalid(); return; } - - Expr *ASArgExpr; - if (Attr.isArgIdent(0)) { - // Special case where the argument is a template id. - CXXScopeSpec SS; - SourceLocation TemplateKWLoc; - UnqualifiedId id; - id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); - - ExprResult AddrSpace = S.ActOnIdExpression( - S.getCurScope(), SS, TemplateKWLoc, id, false, false); - if (AddrSpace.isInvalid()) - return; - - ASArgExpr = static_cast(AddrSpace.get()); - } else { - ASArgExpr = static_cast(Attr.getArgAsExpr(0)); - } - - LangAS ASIdx; - if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) { - Attr.setInvalid(); + Expr *ASArgExpr = nullptr; + if (!ProcessAddressSpaceAttribute(S, Attr, ASIdx, ASArgExpr)) return; - } ASTContext &Ctx = S.Context; auto *ASAttr = ::new (Ctx) AddressSpaceAttr( Index: test/SemaCXX/address-space-method-overloading.cpp =================================================================== --- /dev/null +++ test/SemaCXX/address-space-method-overloading.cpp @@ -0,0 +1,29 @@ +//RUN: %clang_cc1 %s -pedantic -verify + +struct TestAS1 { + int i; +}; + +struct TestAS2 { + char c; +}; + +struct C { +TestAS1 bar() __attribute__((address_space(1))); // expected-note{{candidate function not viable: address space mismatch in 'this' argument ('__attribute__((address_space(3))) C'), parameter type must be '__attribute__((address_space(1))) C'}} expected-note{{candidate function}} +TestAS2 bar() __attribute__((address_space(2))); // expected-note{{candidate function not viable: address space mismatch in 'this' argument ('__attribute__((address_space(3))) C'), parameter type must be '__attribute__((address_space(2))) C'}} expected-note{{candidate function}} +void multiple_as() __attribute__((address_space(1))) __attribute__((address_space(2))); //expected-error{{multiple address spaces specified for type}} +// FIXME: Parser gets confused here. +//auto bar() __attribute__((address_space(4))) -> decltype(this); +}; + +__attribute__((address_space(1))) C inas1; +__attribute__((address_space(3))) C inas3; +__attribute__((address_space(4))) C inas4; + +void foo() { + C noas; + TestAS1 ret = inas1.bar(); + inas3.bar(); // expected-error{{no matching member function for call to 'bar'}} + //inas4.bar(); + noas.bar(); // expected-error{{call to member function 'bar' is ambiguous}} +}