[cfe-commits] r67575 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/SemaType.cpp test/SemaCXX/nested-name-spec.cpp test/SemaTemplate/instantiate-method.cpp
Douglas Gregor
dgregor at apple.com
Mon Mar 23 16:06:20 PDT 2009
Author: dgregor
Date: Mon Mar 23 18:06:20 2009
New Revision: 67575
URL: http://llvm.org/viewvc/llvm-project?rev=67575&view=rev
Log:
Template instantiation for the declarations of member functions within
a class template. At present, we can only instantiation normal
methods, but not constructors, destructors, or conversion operators.
As ever, this contains a bit of refactoring in Sema's type-checking. In
particular:
- Split ActOnFunctionDeclarator into ActOnFunctionDeclarator
(handling the declarator itself) and CheckFunctionDeclaration
(checking for the the function declaration), the latter of which
is also used by template instantiation.
- We were performing the adjustment of function parameter types in
three places; collect those into a single new routine.
- When the type of a parameter is adjusted, allocate an
OriginalParmVarDecl to keep track of the type as it was written.
- Eliminate a redundant check for out-of-line declarations of member
functions; hide more C++-specific checks on function declarations
behind if(getLangOptions().CPlusPlus).
Added:
cfe/trunk/test/SemaTemplate/instantiate-method.cpp
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaCXX/nested-name-spec.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=67575&r1=67574&r2=67575&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 23 18:06:20 2009
@@ -290,6 +290,7 @@
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
+ QualType adjustParameterType(QualType T);
QualType ConvertDeclSpecToType(const DeclSpec &DS);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType BuildPointerType(QualType T, unsigned Quals,
@@ -349,6 +350,9 @@
NamedDecl* PrevDecl,
bool IsFunctionDefinition,
bool& InvalidDecl, bool &Redeclaration);
+ bool CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool &Redeclaration,
+ bool &OverloadableAttrRequired);
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclTy *param,
SourceLocation EqualLoc,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=67575&r1=67574&r2=67575&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar 23 18:06:20 2009
@@ -1437,7 +1437,7 @@
// If there was a previous declaration of this variable, it may be
// in our identifier chain. Update the identifier chain with the new
// declaration.
- if (IdResolver.ReplaceDecl(PrevDecl, ND)) {
+ if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
// The previous declaration was found on the identifer resolver
// chain, so remove it from its scope.
while (S && !S->isDeclScope(PrevDecl))
@@ -2034,23 +2034,6 @@
NewFD->setParams(Context, &Params[0], Params.size());
}
}
-
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
- InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
- else if (isa<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
- Record->setUserDeclaredDestructor(true);
- // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
- // user-defined destructor.
- Record->setPOD(false);
- } else if (CXXConversionDecl *Conversion =
- dyn_cast<CXXConversionDecl>(NewFD))
- ActOnConversionDeclarator(Conversion);
-
- // Extra checking for C++ overloaded operators (C++ [over.oper]).
- if (NewFD->isOverloadedOperator() &&
- CheckOverloadedOperatorDeclaration(NewFD))
- NewFD->setInvalidDecl();
// If name lookup finds a previous declaration that is not in the
// same scope as the new declaration, this may still be an
@@ -2060,19 +2043,130 @@
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
PrevDecl = 0;
+ // Perform semantic checking on the function declaration.
+ bool OverloadableAttrRequired = false; // FIXME: HACK!
+ if (CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired))
+ InvalidDecl = true;
+
+ if (D.getCXXScopeSpec().isSet() && !InvalidDecl) {
+ // An out-of-line member function declaration must also be a
+ // definition (C++ [dcl.meaning]p1).
+ if (!IsFunctionDefinition) {
+ Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+ << D.getCXXScopeSpec().getRange();
+ InvalidDecl = true;
+ } else if (!Redeclaration) {
+ // The user tried to provide an out-of-line definition for a
+ // function that is a member of a class or namespace, but there
+ // was no such member function declared (C++ [class.mfct]p2,
+ // C++ [namespace.memdef]p2). For example:
+ //
+ // class X {
+ // void f() const;
+ // };
+ //
+ // void X::f() { } // ill-formed
+ //
+ // Complain about this problem, and attempt to suggest close
+ // matches (e.g., those that differ only in cv-qualifiers and
+ // whether the parameter types are references).
+ Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
+ << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
+ InvalidDecl = true;
+
+ LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
+ true);
+ assert(!Prev.isAmbiguous() &&
+ "Cannot have an ambiguity in previous-declaration lookup");
+ for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
+ Func != FuncEnd; ++Func) {
+ if (isa<FunctionDecl>(*Func) &&
+ isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
+ Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+ }
+
+ PrevDecl = 0;
+ }
+ }
+
+ // Handle attributes. We need to have merged decls when handling attributes
+ // (for example to check for conflicts, etc).
+ // FIXME: This needs to happen before we merge declarations. Then,
+ // let attribute merging cope with attribute conflicts.
+ ProcessDeclAttributes(NewFD, D);
+ AddKnownFunctionAttributes(NewFD);
+
+ if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
+ // If a function name is overloadable in C, then every function
+ // with that name must be marked "overloadable".
+ Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+ << Redeclaration << NewFD;
+ if (PrevDecl)
+ Diag(PrevDecl->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
+ NewFD->addAttr(::new (Context) OverloadableAttr());
+ }
+
+ // If this is a locally-scoped extern C function, update the
+ // map of such names.
+ if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
+ && !InvalidDecl)
+ RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
+
+ return NewFD;
+}
+
+/// \brief Perform semantic checking of a new function declaration.
+///
+/// Performs semantic analysis of the new function declaration
+/// NewFD. This routine performs all semantic checking that does not
+/// require the actual declarator involved in the declaration, and is
+/// used both for the declaration of functions as they are parsed
+/// (called via ActOnDeclarator) and for the declaration of functions
+/// that have been instantiated via C++ template instantiation (called
+/// via InstantiateDecl).
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool &Redeclaration,
+ bool &OverloadableAttrRequired) {
+ bool InvalidDecl = false;
+
+ // Semantic checking for this function declaration (in isolation).
+ if (getLangOptions().CPlusPlus) {
+ // C++-specific checks.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
+ InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
+ else if (isa<CXXDestructorDecl>(NewFD)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+ Record->setUserDeclaredDestructor(true);
+ // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+ // user-defined destructor.
+ Record->setPOD(false);
+ } else if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>(NewFD))
+ ActOnConversionDeclarator(Conversion);
+
+ // Extra checking for C++ overloaded operators (C++ [over.oper]).
+ if (NewFD->isOverloadedOperator() &&
+ CheckOverloadedOperatorDeclaration(NewFD))
+ InvalidDecl = true;
+ }
+
+ // Check for a previous declaration of this name.
if (!PrevDecl && NewFD->isExternC(Context)) {
// Since we did not find anything by this name and we're declaring
// an extern "C" function, look for a non-visible extern "C"
// declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternalDecls.find(Name);
+ = LocallyScopedExternalDecls.find(NewFD->getDeclName());
if (Pos != LocallyScopedExternalDecls.end())
PrevDecl = Pos->second;
}
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
- bool OverloadableAttrRequired = false;
if (PrevDecl) {
// Determine whether NewFD is an overload of PrevDecl or
// a declaration that requires merging. If it's an overload,
@@ -2086,15 +2180,16 @@
// Functions marked "overloadable" must have a prototype (that
// we can't get through declaration merging).
- if (!R->getAsFunctionProtoType()) {
+ if (!NewFD->getType()->getAsFunctionProtoType()) {
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
<< NewFD;
InvalidDecl = true;
Redeclaration = true;
// Turn this into a variadic function with no parameters.
- R = Context.getFunctionType(R->getAsFunctionType()->getResultType(),
- 0, 0, true, 0);
+ QualType R = Context.getFunctionType(
+ NewFD->getType()->getAsFunctionType()->getResultType(),
+ 0, 0, true, 0);
NewFD->setType(R);
}
}
@@ -2110,99 +2205,24 @@
if (isa<OverloadedFunctionDecl>(PrevDecl))
OldDecl = *MatchedDecl;
- // NewFD and PrevDecl represent declarations that need to be
+ // NewFD and OldDecl represent declarations that need to be
// merged.
if (MergeFunctionDecl(NewFD, OldDecl))
InvalidDecl = true;
- if (!InvalidDecl) {
+ if (!InvalidDecl)
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
-
- // An out-of-line member function declaration must also be a
- // definition (C++ [dcl.meaning]p1).
- if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
- !InvalidDecl) {
- Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
- << D.getCXXScopeSpec().getRange();
- NewFD->setInvalidDecl();
- }
- }
- }
- }
-
- if (D.getCXXScopeSpec().isSet() &&
- (!PrevDecl || !Redeclaration)) {
- // The user tried to provide an out-of-line definition for a
- // function that is a member of a class or namespace, but there
- // was no such member function declared (C++ [class.mfct]p2,
- // C++ [namespace.memdef]p2). For example:
- //
- // class X {
- // void f() const;
- // };
- //
- // void X::f() { } // ill-formed
- //
- // Complain about this problem, and attempt to suggest close
- // matches (e.g., those that differ only in cv-qualifiers and
- // whether the parameter types are references).
- Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
- << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
- InvalidDecl = true;
-
- LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
- true);
- assert(!Prev.isAmbiguous() &&
- "Cannot have an ambiguity in previous-declaration lookup");
- for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
- Func != FuncEnd; ++Func) {
- if (isa<FunctionDecl>(*Func) &&
- isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
- Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
-
- PrevDecl = 0;
}
- // Handle attributes. We need to have merged decls when handling attributes
- // (for example to check for conflicts, etc).
- ProcessDeclAttributes(NewFD, D);
- AddKnownFunctionAttributes(NewFD);
-
- if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
- // If a function name is overloadable in C, then every function
- // with that name must be marked "overloadable".
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- if (PrevDecl)
- Diag(PrevDecl->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(::new (Context) OverloadableAttr());
- }
-
- if (getLangOptions().CPlusPlus) {
+ if (getLangOptions().CPlusPlus && !CurContext->isRecord()) {
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
// during delayed parsing anyway.
- if (!CurContext->isRecord())
- CheckCXXDefaultArguments(NewFD);
-
- // An out-of-line member function declaration must also be a
- // definition (C++ [dcl.meaning]p1).
- if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
- Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
- << D.getCXXScopeSpec().getRange();
- InvalidDecl = true;
- }
+ CheckCXXDefaultArguments(NewFD);
}
- // If this is a locally-scoped extern C function, update the
- // map of such names.
- if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
- && !InvalidDecl)
- RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
-
- return NewFD;
+ return InvalidDecl || NewFD->isInvalidDecl();
}
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
@@ -2588,40 +2608,24 @@
}
}
- // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
- // Doing the promotion here has a win and a loss. The win is the type for
- // both Decl's and DeclRefExpr's will match (a convenient invariant for the
- // code generator). The loss is the orginal type isn't preserved. For example:
- //
- // void func(int parmvardecl[5]) { // convert "int [5]" to "int *"
- // int blockvardecl[5];
- // sizeof(parmvardecl); // size == 4
- // sizeof(blockvardecl); // size == 20
- // }
- //
- // For expressions, all implicit conversions are captured using the
- // ImplicitCastExpr AST node (we have no such mechanism for Decl's).
- //
- // FIXME: If a source translation tool needs to see the original type, then
- // we need to consider storing both types (in ParmVarDecl)...
- //
-
// Parameters can not be abstract class types.
if (RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
diag::err_abstract_type_in_decl,
1 /* parameter type */))
D.setInvalidType(true);
+
+ QualType T = adjustParameterType(parmDeclType);
- if (parmDeclType->isArrayType()) {
- // int x[restrict 4] -> int *restrict
- parmDeclType = Context.getArrayDecayedType(parmDeclType);
- } else if (parmDeclType->isFunctionType())
- parmDeclType = Context.getPointerType(parmDeclType);
-
- ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext,
- D.getIdentifierLoc(), II,
- parmDeclType, StorageClass,
- 0);
+ ParmVarDecl *New;
+ if (T == parmDeclType) // parameter type did not need adjustment
+ New = ParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II,
+ parmDeclType, StorageClass,
+ 0);
+ else // keep track of both the adjusted and unadjusted types
+ New = OriginalParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II, T,
+ parmDeclType, StorageClass, 0);
if (D.getInvalidType())
New->setInvalidDecl();
@@ -2634,7 +2638,7 @@
}
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
- if (parmDeclType->isObjCInterfaceType()) {
+ if (T->isObjCInterfaceType()) {
Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_by_value)
<< "passed";
New->setInvalidDecl();
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=67575&r1=67574&r2=67575&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Mar 23 18:06:20 2009
@@ -43,6 +43,9 @@
Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
+ Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+ Decl *VisitParmVarDecl(ParmVarDecl *D);
+ Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *) {
@@ -192,6 +195,121 @@
return Enum;
}
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // Only handle actual methods; we'll deal with constructors,
+ // destructors, etc. separately.
+ if (D->getKind() != Decl::CXXMethod)
+ return 0;
+
+ QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
+ NumTemplateArgs, D->getLocation(),
+ D->getDeclName());
+ if (T.isNull())
+ return 0;
+
+ // Build the instantiated method declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ D->getDeclName(), T, D->isStatic(),
+ D->isInline());
+ Method->setAccess(D->getAccess());
+ // FIXME: Duplicates some logic in ActOnFunctionDeclarator.
+ if (D->isVirtual()) {
+ Method->setVirtual();
+ Record->setAggregate(false);
+ Record->setPOD(false);
+ Record->setPolymorphic(true);
+ }
+ if (D->isDeleted())
+ Method->setDeleted();
+ if (D->isPure()) {
+ Method->setPure();
+ Record->setAbstract(true);
+ }
+ // FIXME: attributes
+ // FIXME: Method needs a pointer referencing where it came from.
+
+ // Instantiate the function parameters
+ {
+ TemplateDeclInstantiator ParamInstantiator(SemaRef, Method,
+ TemplateArgs, NumTemplateArgs);
+ llvm::SmallVector<ParmVarDecl *, 16> Params;
+ for (FunctionDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P) {
+ if (ParmVarDecl *PInst = (ParmVarDecl *)ParamInstantiator.Visit(*P))
+ Params.push_back(PInst);
+ else
+ Method->setInvalidDecl();
+ }
+ }
+
+ NamedDecl *PrevDecl
+ = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+ // In C++, the previous declaration we find might be a tag type
+ // (class or enum). In this case, the new declaration will hide the
+ // tag type. Note that this does does not apply if we're declaring a
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ if (SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired))
+ Method->setInvalidDecl();
+
+ if (!Method->isInvalidDecl() || !PrevDecl)
+ Owner->addDecl(Method);
+ return Method;
+}
+
+Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
+ QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+ NumTemplateArgs, D->getLocation(),
+ D->getDeclName());
+ if (OrigT.isNull())
+ return 0;
+
+ QualType T = SemaRef.adjustParameterType(OrigT);
+
+ if (D->getDefaultArg()) {
+ // FIXME: Leave a marker for "uninstantiated" default
+ // arguments. They only get instantiated on demand at the call
+ // site.
+ unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning,
+ "sorry, dropping default argument during template instantiation");
+ SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID)
+ << D->getDefaultArg()->getSourceRange();
+ }
+
+ // Allocate the parameter
+ ParmVarDecl *Param = 0;
+ if (T == OrigT)
+ Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), T, D->getStorageClass(),
+ 0);
+ else
+ Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(), D->getIdentifier(),
+ T, OrigT, D->getStorageClass(), 0);
+
+ // Note: we don't try to instantiate function parameters until after
+ // we've instantiated the function's type. Therefore, we don't have
+ // to check for 'void' parameter types here.
+ return Param;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+ // Since parameter types can decay either before or after
+ // instantiation, we simply treat OriginalParmVarDecls as
+ // ParmVarDecls the same way, and create one or the other depending
+ // on what happens after template instantiation.
+ return VisitParmVarDecl(D);
+}
+
Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=67575&r1=67574&r2=67575&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Mar 23 18:06:20 2009
@@ -19,6 +19,30 @@
#include "clang/Parse/DeclSpec.h"
using namespace clang;
+/// \brief Perform adjustment on the parameter type of a function.
+///
+/// This routine adjusts the given parameter type @p T to the actual
+/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
+/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
+QualType Sema::adjustParameterType(QualType T) {
+ // C99 6.7.5.3p7:
+ if (T->isArrayType()) {
+ // C99 6.7.5.3p7:
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ return Context.getArrayDecayedType(T);
+ } else if (T->isFunctionType())
+ // C99 6.7.5.3p8:
+ // A declaration of a parameter as "function returning type"
+ // shall be adjusted to "pointer to function returning type", as
+ // in 6.3.2.1.
+ return Context.getPointerType(T);
+
+ return T;
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param DS the declaration specifiers
@@ -523,12 +547,8 @@
bool Invalid = false;
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
- QualType ParamType = ParamTypes[Idx];
- if (ParamType->isArrayType())
- ParamType = Context.getArrayDecayedType(ParamType);
- else if (ParamType->isFunctionType())
- ParamType = Context.getPointerType(ParamType);
- else if (ParamType->isVoidType()) {
+ QualType ParamType = adjustParameterType(ParamTypes[Idx]);
+ if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
}
@@ -683,29 +703,14 @@
ParmVarDecl *Param = (ParmVarDecl *)FTI.ArgInfo[i].Param;
QualType ArgTy = Param->getType();
assert(!ArgTy.isNull() && "Couldn't parse type?");
- //
- // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
- // This matches the conversion that is done in
- // Sema::ActOnParamDeclarator(). Without this conversion, the
- // argument type in the function prototype *will not* match the
- // type in ParmVarDecl (which makes the code generator unhappy).
- //
- // FIXME: We still apparently need the conversion in
- // Sema::ActOnParamDeclarator(). This doesn't make any sense, since
- // it should be driving off the type being created here.
- //
- // FIXME: If a source translation tool needs to see the original type,
- // then we need to consider storing both types somewhere...
- //
- if (ArgTy->isArrayType()) {
- ArgTy = Context.getArrayDecayedType(ArgTy);
- } else if (ArgTy->isFunctionType())
- ArgTy = Context.getPointerType(ArgTy);
-
+
+ // Adjust the parameter type.
+ ArgTy = adjustParameterType(ArgTy);
+
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
// int(void) as a FunctionProtoType with an empty argument list.
- else if (ArgTy->isVoidType()) {
+ if (ArgTy->isVoidType()) {
// If this is something like 'float(int, void)', reject it. 'void'
// is an incomplete type (C99 6.2.5p19) and function decls cannot
// have arguments of incomplete type.
Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=67575&r1=67574&r2=67575&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Mar 23 18:06:20 2009
@@ -101,8 +101,7 @@
int A2::RC::x; // expected-error{{non-static data member defined out-of-line}}
-void A2::CC::NC::m(); // expected-error{{out-of-line declaration of a member must be a definition}} \
- // expected-error{{out-of-line declaration of a member must be a definition}}
+void A2::CC::NC::m(); // expected-error{{out-of-line declaration of a member must be a definition}}
namespace E {
Added: cfe/trunk/test/SemaTemplate/instantiate-method.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-method.cpp?rev=67575&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-method.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-method.cpp Mon Mar 23 18:06:20 2009
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T>
+class X {
+public:
+ void f(T); // expected-error{{argument may not have 'void' type}}
+ // FIXME: source location isn't very good, because we're
+ // instantiating the type. Could we do better?
+ void g(T*);
+
+ static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
+};
+
+int identity(int x) { return x; }
+
+void test(X<int> *xi, int *ip, X<int(int)> *xf) {
+ xi->f(17);
+ xi->g(ip);
+ xf->f(&identity);
+ xf->g(identity);
+ X<int>::h(17, 25);
+ X<int(int)>::h(identity, &identity);
+}
+
+void test_bad() {
+ X<void> xv; // expected-note{{in instantiation of template class 'class X<void>' requested here}}
+}
+
+template<typename T, typename U>
+class Overloading {
+public:
+ int& f(T, T); // expected-note{{previous declaration is here}}
+ float& f(T, U); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+void test_ovl(Overloading<int, long> *oil, int i, long l) {
+ int &ir = oil->f(i, i);
+ float &fr = oil->f(i, l);
+}
+
+void test_ovl_bad() {
+ Overloading<float, float> off; // expected-note{{in instantiation of template class 'class Overloading<float, float>' requested here}}
+}
More information about the cfe-commits
mailing list