diff options
-rw-r--r-- | include/clang/AST/DeclarationName.h | 8 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 5 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 77 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 18 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 13 |
11 files changed, 135 insertions, 32 deletions
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index fcb4ae52e7..e6f50d5392 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -190,6 +190,14 @@ public: /// getNameKind - Determine what kind of name this is. NameKind getNameKind() const; + /// \brief Determines whether the name itself is dependent, e.g., because it + /// involves a C++ type that is itself dependent. + /// + /// Note that this does not capture all of the notions of "dependent name", + /// because an identifier can be a dependent name if it is used as the + /// callee in a call expression with dependent arguments. + bool isDependentName() const; + /// getName - Retrieve the human-readable string for this name. std::string getAsString() const; diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 60c40e24fb..1fa2010786 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -180,6 +180,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { return Identifier; } +bool DeclarationName::isDependentName() const { + QualType T = getCXXNameType(); + return !T.isNull() && T->isDependentType(); +} + std::string DeclarationName::getAsString() const { switch (getNameKind()) { case Identifier: diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 818657c2a7..00b74bc21a 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -271,6 +271,10 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; + if (T->getNoReturnAttr()) + S += " __attribute__((noreturn))"; + + if (T->hasExceptionSpec()) { S += " throw("; if (T->hasAnyExceptionSpec()) @@ -287,10 +291,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; } - if (T->getNoReturnAttr()) - S += " __attribute__((noreturn))"; - Print(T->getResultType(), S); + AppendTypeQualList(S, T->getTypeQuals()); + Print(T->getResultType(), S); } void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ec08658b5c..f463cbb7c8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1178,8 +1178,14 @@ public: LookupObjCImplementationName }; + /// \brief Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). enum RedeclarationKind { - NotForRedeclaration, + /// \brief The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// \brief The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists. ForRedeclaration }; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8965199c2f..41f0886e76 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2743,7 +2743,9 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - if (Conversion->getPreviousDeclaration()) { + if (Conversion->getPrimaryTemplate()) { + // ignore specializations + } else if (Conversion->getPreviousDeclaration()) { const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration(); if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) @@ -2754,7 +2756,7 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { } else if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) ClassDecl->addConversionFunction(ConversionTemplate); - else if (!Conversion->getPrimaryTemplate()) // ignore specializations + else ClassDecl->addConversionFunction(Conversion); return DeclPtrTy::make(Conversion); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index bf9d099e56..02af661095 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1010,11 +1010,18 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: + // -- an identifier that was declared with a dependent type, + // (note: handled after lookup) + // -- a template-id that is dependent, + // (note: handled in BuildTemplateIdExpr) + // -- a conversion-function-id that specifies a dependent type, // -- a nested-name-specifier that contains a class-name that // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if (SS.isSet() && IsDependentIdExpression(*this, SS)) { + if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) || + (SS.isSet() && IsDependentIdExpression(*this, SS))) { return ActOnDependentIdExpression(SS, Name, NameLoc, isAddressOfOperand, TemplateArgs); @@ -2281,7 +2288,7 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, } } - assert(BaseType->isDependentType()); + assert(BaseType->isDependentType() || Name.isDependentName()); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. @@ -3170,7 +3177,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); - if (Base->getType()->isDependentType()) { + if (Base->getType()->isDependentType() || Name.isDependentName()) { Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 897ce20075..a8c2366c59 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -444,10 +444,81 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { bool Found = false; DeclContext::lookup_const_iterator I, E; - for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) - if (R.isAcceptableDecl(*I)) - R.addDecl(*I), Found = true; + for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { + if (R.isAcceptableDecl(*I)) { + R.addDecl(*I); + Found = true; + } + } + if (R.getLookupName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + !R.getLookupName().getCXXNameType()->isDependentType() && + isa<CXXRecordDecl>(DC)) { + // C++ [temp.mem]p6: + // A specialization of a conversion function template is not found by + // name lookup. Instead, any conversion function templates visible in the + // context of the use are considered. [...] + const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + + const UnresolvedSet *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSet::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); + U != UEnd; ++U) { + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); + if (!ConvTemplate) + continue; + + // When we're performing lookup for the purposes of redeclaration, just + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return + // type of the new declaration with the type of the function template. + if (R.isForRedeclaration()) { + R.addDecl(ConvTemplate); + Found = true; + continue; + } + + // C++ [temp.mem]p6: + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by + // name lookup. + // + // When referencing a conversion function for any purpose other than + // a redeclaration (such that we'll be building an expression with the + // result), perform template argument deduction and place the + // specialization into the result set. We do this to avoid forcing all + // callers to perform special deduction for conversion functions. + Sema::TemplateDeductionInfo Info(R.getSema().Context); + FunctionDecl *Specialization = 0; + + const FunctionProtoType *ConvProto + = ConvTemplate->getTemplatedDecl()->getType() + ->getAs<FunctionProtoType>(); + assert(ConvProto && "Nonsensical conversion function template type"); + + // Compute the type of the function that we would expect the conversion + // function to have, if it were to match the name given. + // FIXME: Calling convention! + QualType ExpectedType + = R.getSema().Context.getFunctionType( + R.getLookupName().getCXXNameType(), + 0, 0, ConvProto->isVariadic(), + ConvProto->getTypeQuals(), + false, false, 0, 0, + ConvProto->getNoReturnAttr()); + + // Perform template argument deduction against the type that we would + // expect the function to have. + if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, + Specialization, Info) + == Sema::TDK_Success) { + R.addDecl(Specialization); + Found = true; + } + } + } + return Found; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 825dabfbc7..3dd85d9880 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2307,8 +2307,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); - assert(!isa<CXXConversionDecl>(Function) && - "Use AddConversionCandidate for conversion functions"); assert(!Function->getDescribedFunctionTemplate() && "Use AddTemplateOverloadCandidate for function templates"); @@ -2509,8 +2507,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); - assert(!isa<CXXConversionDecl>(Method) && - "Use AddConversionCandidate for conversion functions"); assert(!isa<CXXConstructorDecl>(Method) && "Use AddOverloadCandidate for constructors"); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ecb89edcf7..5ca8bfde80 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4540,8 +4540,10 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) { if (Context.hasSameUnqualifiedType(Method->getType(), R)) { Matches.clear(); + Matches.push_back(Method); - break; + if (Method->getTemplateSpecializationKind() == TSK_Undeclared) + break; } } } @@ -4553,7 +4555,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, + = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 40f3507d8b..ea79d9fd78 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1312,20 +1312,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly specified. -/// -/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the explicitly-specified template arguments. -/// -/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the number of explicitly-specified template arguments in -/// @p ExplicitTemplateArguments. This value may be zero. +/// \param ExplicitTemplateArguments the explicit template arguments provided +/// for this call. /// /// \param Args the function call arguments /// /// \param NumArgs the number of arguments in Args /// +/// \param Name the name of the function being called. This is only significant +/// when the function template is a conversion function template, in which +/// case this routine will also perform template argument deduction based on +/// the function to which +/// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by /// template argument deduction. @@ -1336,7 +1334,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 86ad0a0a73..499160d11f 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -897,12 +897,16 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_DestructorName: - case UnqualifiedId::IK_ConversionFunctionId: // Constructors and destructors don't have return types. Use - // "void" instead. Conversion operators will check their return - // types separately. + // "void" instead. T = Context.VoidTy; break; + + case UnqualifiedId::IK_ConversionFunctionId: + // The result type of a conversion function is the type that it + // converts to. + T = GetTypeFromParser(D.getName().ConversionFunctionId); + break; } if (T.isNull()) @@ -1041,7 +1045,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; // C99 6.7.5.3p1: The return type may not be a function or array type. - if (T->isArrayType() || T->isFunctionType()) { + if ((T->isArrayType() || T->isFunctionType()) && + (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; T = Context.IntTy; D.setInvalidType(true); |