[cfe-commits] r93162 - in /cfe/trunk: include/clang/AST/DeclarationName.h lib/AST/DeclarationName.cpp lib/AST/TypePrinter.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaType.cpp
Douglas Gregor
dgregor at apple.com
Mon Jan 11 10:40:56 PST 2010
Author: dgregor
Date: Mon Jan 11 12:40:55 2010
New Revision: 93162
URL: http://llvm.org/viewvc/llvm-project?rev=93162&view=rev
Log:
Implement name lookup for conversion function template specializations
(C++ [temp.mem]p5-6), which involves template argument deduction based
on the type named, e.g., given
struct X { template<typename T> operator T*(); } x;
when we call
x.operator int*();
we perform template argument deduction to determine that T=int. This
template argument deduction is needed for template specialization and
explicit instantiation, e.g.,
template<> X::operator float*() { /* ... */ }
and when calling or otherwise naming a conversion function (as in the
first example).
This fixes PR5742 and PR5762, although there's some remaining ugliness
that's causing out-of-line definitions of conversion function
templates to fail. I'll look into that separately.
Modified:
cfe/trunk/include/clang/AST/DeclarationName.h
cfe/trunk/lib/AST/DeclarationName.cpp
cfe/trunk/lib/AST/TypePrinter.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/AST/DeclarationName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclarationName.h (original)
+++ cfe/trunk/include/clang/AST/DeclarationName.h Mon Jan 11 12:40:55 2010
@@ -190,6 +190,14 @@
/// 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;
Modified: cfe/trunk/lib/AST/DeclarationName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclarationName.cpp (original)
+++ cfe/trunk/lib/AST/DeclarationName.cpp Mon Jan 11 12:40:55 2010
@@ -180,6 +180,11 @@
return Identifier;
}
+bool DeclarationName::isDependentName() const {
+ QualType T = getCXXNameType();
+ return !T.isNull() && T->isDependentType();
+}
+
std::string DeclarationName::getAsString() const {
switch (getNameKind()) {
case Identifier:
Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Jan 11 12:40:55 2010
@@ -271,6 +271,10 @@
S += ")";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+
+
if (T->hasExceptionSpec()) {
S += " throw(";
if (T->hasAnyExceptionSpec())
@@ -287,10 +291,9 @@
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,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Jan 11 12:40:55 2010
@@ -1178,8 +1178,14 @@
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
};
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan 11 12:40:55 2010
@@ -2743,7 +2743,9 @@
<< 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 @@
} else if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
ClassDecl->addConversionFunction(ConversionTemplate);
- else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+ else
ClassDecl->addConversionFunction(Conversion);
return DeclPtrTy::make(Conversion);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 11 12:40:55 2010
@@ -1010,11 +1010,18 @@
// 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 @@
}
}
- 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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Jan 11 12:40:55 2010
@@ -444,10 +444,81 @@
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;
}
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jan 11 12:40:55 2010
@@ -2307,8 +2307,6 @@
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 @@
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");
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan 11 12:40:55 2010
@@ -4540,8 +4540,10 @@
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 @@
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?
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Jan 11 12:40:55 2010
@@ -1312,20 +1312,18 @@
/// \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 @@
/// \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) {
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=93162&r1=93161&r2=93162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jan 11 12:40:55 2010
@@ -897,12 +897,16 @@
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 @@
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);
More information about the cfe-commits
mailing list