[cfe-commits] r107406 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/Type.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/except/except.spec/p14.cpp
Douglas Gregor
dgregor at apple.com
Thu Jul 1 10:48:08 PDT 2010
Author: dgregor
Date: Thu Jul 1 12:48:08 2010
New Revision: 107406
URL: http://llvm.org/viewvc/llvm-project?rev=107406&view=rev
Log:
Provide an exception-specification for an implicitly-declared
copy-assignment operator.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/CXX/except/except.spec/p14.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=107406&r1=107405&r2=107406&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Jul 1 12:48:08 2010
@@ -537,6 +537,18 @@
bool hasConstCopyAssignment(ASTContext &Context,
const CXXMethodDecl *&MD) const;
+ /// \brief Retrieve the copy-assignment operator for this class, if available.
+ ///
+ /// This routine attempts to find the copy-assignment operator for this
+ /// class, using a simplistic form of overload resolution.
+ ///
+ /// \param ArgIsConst Whether the argument to the copy-assignment operator
+ /// is const-qualified.
+ ///
+ /// \returns The copy-assignment operator that can be invoked, or NULL if
+ /// a unique copy-assignment operator could not be found.
+ CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const;
+
/// addedConstructor - Notify the class that another constructor has
/// been added. This routine helps maintain information about the
/// class based on which constructors have been added.
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=107406&r1=107405&r2=107406&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Jul 1 12:48:08 2010
@@ -271,6 +271,8 @@
}
}
+ bool isSupersetOf(Qualifiers Other) const;
+
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
@@ -3369,6 +3371,12 @@
return getFunctionExtInfo(*t);
}
+/// \brief Determine whether this set of qualifiers is a superset of the given
+/// set of qualifiers.
+inline bool Qualifiers::isSupersetOf(Qualifiers Other) const {
+ return Mask != Other.Mask && (Mask | Other.Mask) == Mask;
+}
+
/// isMoreQualifiedThan - Determine whether this type is more
/// qualified than the Other type. For example, "const volatile int"
/// is more qualified than "const int", "volatile int", and
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=107406&r1=107405&r2=107406&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jul 1 12:48:08 2010
@@ -232,6 +232,79 @@
return false;
}
+/// \brief Perform a simplistic form of overload resolution that only considers
+/// cv-qualifiers on a single parameter, and return the best overload candidate
+/// (if there is one).
+static CXXMethodDecl *
+GetBestOverloadCandidateSimple(
+ const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
+ if (Cands.empty())
+ return 0;
+ if (Cands.size() == 1)
+ return Cands[0].first;
+
+ unsigned Best = 0, N = Cands.size();
+ for (unsigned I = 1; I != N; ++I)
+ if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ Best = I;
+
+ for (unsigned I = 1; I != N; ++I)
+ if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ return 0;
+
+ return Cands[Best].first;
+}
+
+CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
+ ASTContext &Context = getASTContext();
+ QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
+ DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+
+ llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
+ DeclContext::lookup_const_iterator Op, OpEnd;
+ for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) {
+ // C++ [class.copy]p9:
+ // A user-declared copy assignment operator is a non-static non-template
+ // member function of class X with exactly one parameter of type X, X&,
+ // const X&, volatile X& or const volatile X&.
+ const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
+ if (!Method || Method->isStatic() || Method->getPrimaryTemplate())
+ continue;
+
+ const FunctionProtoType *FnType
+ = Method->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Overloaded operator has no prototype.");
+ // Don't assert on this; an invalid decl might have been left in the AST.
+ if (FnType->getNumArgs() != 1 || FnType->isVariadic())
+ continue;
+
+ QualType ArgType = FnType->getArgType(0);
+ Qualifiers Quals;
+ if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
+ ArgType = Ref->getPointeeType();
+ // If we have a const argument and we have a reference to a non-const,
+ // this function does not match.
+ if (ArgIsConst && !ArgType.isConstQualified())
+ continue;
+
+ Quals = ArgType.getQualifiers();
+ } else {
+ // By-value copy-assignment operators are treated like const X&
+ // copy-assignment operators.
+ Quals = Qualifiers::fromCVRMask(Qualifiers::Const);
+ }
+
+ if (!Context.hasSameUnqualifiedType(ArgType, Class))
+ continue;
+
+ // Save this copy-assignment operator. It might be "the one".
+ Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals));
+ }
+
+ // Use a simplistic form of overload resolution to find the candidate.
+ return GetBestOverloadCandidateSimple(Found);
+}
+
void
CXXRecordDecl::addedConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=107406&r1=107405&r2=107406&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jul 1 12:48:08 2010
@@ -4626,6 +4626,33 @@
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
+ // C++ [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+ ImplicitExceptionSpecification ExceptSpec(Context);
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ BaseEnd = ClassDecl->bases_end();
+ Base != BaseEnd; ++Base) {
+ const CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *CopyAssign
+ = BaseClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd;
+ ++Field) {
+ QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ const CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (CXXMethodDecl *CopyAssign
+ = FieldClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
+ }
+
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
@@ -4633,8 +4660,10 @@
= CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
- /*FIXME: hasExceptionSpec*/false,
- false, 0, 0,
+ ExceptSpec.hasExceptionSpecification(),
+ ExceptSpec.hasAnyExceptionSpecification(),
+ ExceptSpec.size(),
+ ExceptSpec.data(),
FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false,
/*StorageClassAsWritten=*/FunctionDecl::None,
Modified: cfe/trunk/test/CXX/except/except.spec/p14.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p14.cpp?rev=107406&r1=107405&r2=107406&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p14.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p14.cpp Thu Jul 1 12:48:08 2010
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fexceptions -verify %s
struct A { };
struct B { };
+struct C { };
+// Destructor
struct X0 {
virtual ~X0() throw(A); // expected-note{{overridden virtual function is here}}
};
@@ -10,3 +12,18 @@
};
struct X2 : public X0, public X1 { }; // expected-error 2{{exception specification of overriding function is more lax than base version}}
+// Copy-assignment operator.
+struct CA0 {
+ CA0 &operator=(const CA0&) throw(A);
+};
+struct CA1 {
+ CA1 &operator=(const CA1&) throw(B);
+};
+struct CA2 : CA0, CA1 { };
+
+void test_CA() {
+ CA2 &(CA2::*captr1)(const CA2&) throw(A, B) = &CA2::operator=;
+ CA2 &(CA2::*captr2)(const CA2&) throw(A, B, C) = &CA2::operator=;
+ CA2 &(CA2::*captr3)(const CA2&) throw(A) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
+ CA2 &(CA2::*captr4)(const CA2&) throw(B) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
+}
More information about the cfe-commits
mailing list