diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index bb82ca0c861d1b6a3601e09716edf6449cccc9e3..0c1ef72ea4f02ac6b5b4f054d8e98c83f481d0de 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -102,6 +102,9 @@ public: /// Mark this Decl to be BSC's member function. bool isBSCMember = false; + // Used to mark parameters that include 'this'. + bool hasThisParam = false; + /// A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b24dac80502f8090809f6597c84c4559d097d1c0..50cc7ce7aa997809aeab20336e74f3df5093f1f9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6454,6 +6454,8 @@ def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_no_member_overloaded_arrow : Error< "no member named %0 in %1; did you mean to use '->' instead of '.'?">; +def err_no_member_overloaded_colon : Error< + "no member named %0 in %1; did you mean to use '::' instead of '.'?">; def err_member_not_yet_instantiated : Error< "no member %0 in %1; it has not yet been instantiated">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 01da2ad370d897f63cfd3545151f314a598da0ac..f5b8a5272df809581a59b42d1f8555bb8986f035 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2933,7 +2933,8 @@ private: DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc); + SourceLocation &EllipsisLoc, + const Type *typePtr = nullptr); void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index d9d411621f0b9054fa0cf7b5e6b7fb8bb219c62e..9b28e1f614c12c27c8263a83ce66488c787b8f6a 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1923,6 +1923,10 @@ public: ~Declarator() { clear(); } + + // Used to mark parameters that include 'this'. + bool hasThisParam = false; + /// getDeclSpec - Return the declaration-specifier that this declarator was /// declared with. const DeclSpec &getDeclSpec() const { return DS; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 809e488921e67bec4db817088c02e8a225792d3c..3938f8ae152a33537e86ae53da5abb04960940ed 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2674,7 +2674,7 @@ public: Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); - Decl *ActOnParamDeclarator(Scope *S, Declarator &D); + Decl *ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize = 0, const Type *typePtr = nullptr); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); @@ -5293,7 +5293,7 @@ public: CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, - const Scope *S, + const Scope *S, bool IsPeriod = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult @@ -5304,6 +5304,7 @@ public: const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, + bool IsPeriod = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a8eb1643b1b6d733be2e8ffdb4b7fa22f46be7c1..6b535402efdf2cdfc9b8ba1ca9fcc6481ce338b9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1975,6 +1975,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // BSC will enter this for parsing "{YYY}" in "::getA(XXX){YYY}" Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + TheDecl->hasThisParam = D.hasThisParam; // If D has the form "Foo::getA", after parsing `getA`, we add it to struct Foo's // DeclContext. We need to search getA within Foo's DeclContext later. Now it seems // that getA is in both Foo's DeclContext and toplevel Context. Need to be fixed. @@ -6519,12 +6520,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D, MaybeParseCXX11Attributes(FnAttrs); ProhibitAttributes(FnAttrs); } else { - if (Tok.isNot(tok::r_paren)) + if (Tok.isNot(tok::r_paren)) { + const Type *typePtr = nullptr; + if (D.getCXXScopeSpec().isValid()) + typePtr = D.getCXXScopeSpec().getScopeRep()->getAsType(); ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, - EllipsisLoc); + EllipsisLoc, typePtr); + } else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); + if (ParamInfo.size() > 0) + D.hasThisParam = ParamInfo.data()[0].Param->hasThisParam; + HasProto = ParamInfo.size() || getLangOpts().CPlusPlus || getLangOpts().OpenCL; @@ -6775,7 +6783,8 @@ void Parser::ParseParameterDeclarationClause( DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc) { + SourceLocation &EllipsisLoc, + const Type *typePtr) { // Avoid exceeding the maximum function scope depth. // See https://bugs.llvm.org/show_bug.cgi?id=19607 @@ -6895,7 +6904,7 @@ void Parser::ParseParameterDeclarationClause( } // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator, ParamInfo.size(), typePtr); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7c814a1f44996ae360b23506665e966d3d9f1c0b..a9f1552de760a84e34ac59af5e51506bb72572bd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13540,7 +13540,7 @@ void Sema::CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D) { /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. -Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { +Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize, const Type *typePtr) { const DeclSpec &DS = D.getDeclSpec(); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. @@ -13585,6 +13585,22 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); + + bool hasThisParam = false; + if (DeclarationName(II).getAsString() == "this") { + if (ParamSize == 0) { + auto thisTypePtr = parmDeclType.getTypePtr()->getPointeeType()->getCanonicalTypeUnqualified().getTypePtr(); + if (typePtr == nullptr || typePtr != thisTypePtr) { + Diag(D.getBeginLoc(), diag::err_type_unsupported) + << parmDeclType.getAsString(); + } + hasThisParam = true; + } else { + Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) + << GetNameForDeclarator(D).getName(); + } + } + if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration); @@ -13614,6 +13630,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), II, parmDeclType, TInfo, SC); + static_cast(New)->hasThisParam = hasThisParam; if (D.isInvalidType()) New->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index d7ce54dc0a4d98f9fad1bce0122b8cc7fb313435..6c3fa09126258a2843b15c8bcc77d694ab4b46a1 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -747,6 +747,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + bool IsPeroid, ActOnMemberAccessExtraArgs *ExtraArgs) { if (BaseType->isDependentType() || (SS.isSet() && isDependentScopeSpecifier(SS))) @@ -794,7 +795,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, TemplateArgs, S, - false, ExtraArgs); + false, IsPeroid, ExtraArgs); } ExprResult @@ -954,6 +955,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck, + bool IsPeriod, ActOnMemberAccessExtraArgs *ExtraArgs) { QualType BaseType = BaseExprType; if (IsArrow) { @@ -1118,11 +1120,21 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Normally, when we reach here we are dealing sth like foo.getA, getA is MemberDecl, // in C++, getA is definitely a CXXMethodDecl, but now our BSC treats it as FunctionDecl. // Do we need to have some BSCMethodDecl for getA in Foo::getA? + // FIXME: MemberDecl and MemberFn have different addresses? if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { // BSC's member function for struct Foo ExprValueKind valueKind; QualType type; valueKind = VK_LValue; type = MemberFn->getType(); + + DeclContext *DC = (SS.isSet() + ? computeDeclContext(SS, false) + : BaseType->castAs()->getDecl()); + // If the first parameter is not 'this', it cannot be called by the way of '.'. + if (!MemberDecl->hasThisParam && IsPeriod) { + Diag(OpLoc, diag::err_no_member_overloaded_colon) + << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "::"); + } return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, MemberFn, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, type, valueKind, OK_Ordinary); @@ -1719,6 +1731,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, DeclarationName Name = NameInfo.getName(); bool IsArrow = (OpKind == tok::arrow); + bool IsPeriod = (OpKind == tok::period); NamedDecl *FirstQualifierInScope = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep())); @@ -1738,7 +1751,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, - FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs); + FirstQualifierInScope, NameInfo, TemplateArgs, S, IsPeriod, &ExtraArgs); if (!Res.isInvalid() && isa(Res.get())) CheckMemberAccessOfNoDeref(cast(Res.get()));