[cfe-commits] r57935 - in /cfe/trunk: include/clang/AST/Type.h lib/AST/Expr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaType.cpp test/SemaCXX/decl-expr-ambiguity.cpp test/SemaCXX/qualification-conversion.cpp
Douglas Gregor
doug.gregor at gmail.com
Tue Oct 21 16:43:53 PDT 2008
Author: dgregor
Date: Tue Oct 21 18:43:52 2008
New Revision: 57935
URL: http://llvm.org/viewvc/llvm-project?rev=57935&view=rev
Log:
Initial step toward supporting qualification conversions (C++ 4.4).
Changes:
- Sema::IsQualificationConversion determines whether we have a qualification
conversion.
- Sema::CheckSingleAssignment constraints now follows the C++ rules in C++,
performing an implicit conversion from the right-hand side to the type of
the left-hand side rather than checking based on the C notion of
"compatibility". We now rely on the implicit-conversion code to
determine whether the conversion can happen or
not. Sema::TryCopyInitialization has an ugly reference-related
hack to cope with the initialization of references, for now.
- When building DeclRefExprs, strip away the reference type, since
there are no expressions whose type is a reference. We'll need to
do this throughout Sema.
- Expr::isLvalue now permits functions to be lvalues in C++ (but not
in C).
Added:
cfe/trunk/test/SemaCXX/qualification-conversion.cpp
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Tue Oct 21 18:43:52 2008
@@ -160,6 +160,27 @@
inline QualType getUnqualifiedType() const;
+ /// 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
+ /// "int". However, it is not more qualified than "const volatile
+ /// int".
+ bool isMoreQualifiedThan(QualType Other) const {
+ unsigned MyQuals = this->getCVRQualifiers();
+ unsigned OtherQuals = Other.getCVRQualifiers();
+ return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals;
+ }
+
+ /// isAtLeastAsQualifiedAs - Determine whether this type is at last
+ /// as qualified as the Other type. For example, "const volatile
+ /// int" is at least as qualified as "const int", "volatile int",
+ /// "int", and "const volatile int".
+ bool isAtLeastAsQualifiedAs(QualType Other) const {
+ unsigned MyQuals = this->getCVRQualifiers();
+ unsigned OtherQuals = Other.getCVRQualifiers();
+ return MyQuals | OtherQuals == MyQuals;
+ }
+
/// operator==/!= - Indicate whether the specified types and qualifiers are
/// identical.
bool operator==(const QualType &RHS) const {
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 21 18:43:52 2008
@@ -15,6 +15,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
@@ -334,14 +335,17 @@
/// - reference type [C++ [expr]]
///
Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
- // first, check the type (C99 6.3.2.1)
- if (TR->isFunctionType()) // from isObjectType()
+ // first, check the type (C99 6.3.2.1). Expressions with function
+ // type in C are not lvalues, but they can be lvalues in C++.
+ if (!Ctx.getLangOptions().CPlusPlus && TR->isFunctionType())
return LV_NotObjectType;
// Allow qualified void which is an incomplete type other than void (yuck).
if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
return LV_IncompleteVoidType;
+ /// FIXME: Expressions can't have reference type, so the following
+ /// isn't needed.
if (TR->isReferenceType()) // C++ [expr]
return LV_Valid;
@@ -356,7 +360,11 @@
return LV_Valid;
case DeclRefExprClass: { // C99 6.5.1p2
const Decl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
- if (isa<VarDecl>(RefdDecl) || isa<ImplicitParamDecl>(RefdDecl))
+ if (isa<VarDecl>(RefdDecl) ||
+ isa<ImplicitParamDecl>(RefdDecl) ||
+ // C++ 3.10p2: An lvalue refers to an object or function.
+ isa<FunctionDecl>(RefdDecl) ||
+ isa<OverloadedFunctionDecl>(RefdDecl))
return LV_Valid;
break;
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Oct 21 18:43:52 2008
@@ -259,7 +259,7 @@
QualType ConvertDeclSpecToType(const DeclSpec &DS);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType GetTypeForDeclarator(Declarator &D, Scope *S);
-
+ QualType GetNonReferenceType(QualType Type);
QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
@@ -371,6 +371,7 @@
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
QualType& ConvertedType);
+ bool IsQualificationConversion(QualType FromType, QualType ToType);
ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 21 18:43:52 2008
@@ -450,7 +450,7 @@
}
// If this reference is not in a block or if the referenced variable is
// within the block, create a normal DeclRefExpr.
- return new DeclRefExpr(VD, VD->getType(), Loc);
+ return new DeclRefExpr(VD, GetNonReferenceType(VD->getType()), Loc);
}
Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1565,8 +1565,7 @@
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
// qualifiers of the type *pointed to* by the right;
// FIXME: Handle ASQualType
- if ((lhptee.getCVRQualifiers() & rhptee.getCVRQualifiers()) !=
- rhptee.getCVRQualifiers())
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
ConvTy = CompatiblePointerDiscardsQualifiers;
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
@@ -1766,6 +1765,28 @@
Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
+ if (getLangOptions().CPlusPlus) {
+ if (!lhsType->isRecordType()) {
+ // C++ 5.17p3: If the left operand is not of class type, the
+ // expression is implicitly converted (C++ 4) to the
+ // cv-unqualified type of the left operand.
+ ImplicitConversionSequence ICS
+ = TryCopyInitialization(rExpr, lhsType.getUnqualifiedType());
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ // No implicit conversion available; we cannot perform this
+ // assignment.
+ return Incompatible;
+ } else {
+ // Perform the appropriate cast to the right-handle side.
+ ImpCastExprToType(rExpr, lhsType.getUnqualifiedType());
+ return Compatible;
+ }
+ }
+
+ // FIXME: Currently, we fall through and treat C++ classes like C
+ // structures.
+ }
+
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
if ((lhsType->isPointerType() || lhsType->isObjCQualifiedIdType() ||
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 21 18:43:52 2008
@@ -318,6 +318,32 @@
ICS.Standard.Deprecated = false;
ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr();
+ if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType()) {
+ // FIXME: This is a hack to deal with the initialization of
+ // references the way that the C-centric code elsewhere deals with
+ // references, by only allowing them if the referred-to type is
+ // exactly the same. This means that we're only handling the
+ // direct-binding case. The code will be replaced by an
+ // implementation of C++ 13.3.3.1.4 once we have the
+ // initialization of references implemented.
+ QualType ToPointee = Context.getCanonicalType(ToTypeRef->getPointeeType());
+
+ // Get down to the canonical type that we're converting from.
+ if (const ReferenceType *FromTypeRef = FromType->getAsReferenceType())
+ FromType = FromTypeRef->getPointeeType();
+ FromType = Context.getCanonicalType(FromType);
+
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
+
+ if (FromType != ToPointee)
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+
+ return ICS;
+ }
+
// The first conversion can be an lvalue-to-rvalue conversion,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
@@ -432,10 +458,7 @@
}
// The third conversion can be a qualification conversion (C++ 4p1).
- // FIXME: CheckPointerTypesForAssignment isn't the right way to
- // determine whether we have a qualification conversion.
- if (Context.getCanonicalType(FromType) != Context.getCanonicalType(ToType)
- && CheckPointerTypesForAssignment(ToType, FromType) == Compatible) {
+ if (IsQualificationConversion(FromType, ToType)) {
ICS.Standard.Third = ICK_Qualification;
FromType = ToType;
} else {
@@ -618,6 +641,74 @@
return false;
}
+/// IsQualificationConversion - Determines whether the conversion from
+/// an rvalue of type FromType to ToType is a qualification conversion
+/// (C++ 4.4).
+bool
+Sema::IsQualificationConversion(QualType FromType, QualType ToType)
+{
+ FromType = Context.getCanonicalType(FromType);
+ ToType = Context.getCanonicalType(ToType);
+
+ // If FromType and ToType are the same type, this is not a
+ // qualification conversion.
+ if (FromType == ToType)
+ return false;
+
+ // (C++ 4.4p4):
+ // A conversion can add cv-qualifiers at levels other than the first
+ // in multi-level pointers, subject to the following rules: [...]
+ bool PreviousToQualsIncludeConst = true;
+ bool UnwrappedPointer;
+ bool UnwrappedAnyPointer = false;
+ do {
+ // Within each iteration of the loop, we check the qualifiers to
+ // determine if this still looks like a qualification
+ // conversion. Then, if all is well, we unwrap one more level of
+ // pointers (FIXME: or pointers-to-members) and do it all again
+ // until there are no more pointers or pointers-to-members left to
+ // unwrap.
+ UnwrappedPointer = false;
+
+ // -- the pointer types are similar.
+ const PointerType *FromPtrType = FromType->getAsPointerType(),
+ *ToPtrType = ToType->getAsPointerType();
+ if (FromPtrType && ToPtrType) {
+ // The pointer types appear similar. Look at their pointee types.
+ FromType = FromPtrType->getPointeeType();
+ ToType = ToPtrType->getPointeeType();
+ UnwrappedPointer = true;
+ UnwrappedAnyPointer = true;
+ }
+
+ // FIXME: Cope with pointer-to-member types.
+
+ // -- for every j > 0, if const is in cv 1,j then const is in cv
+ // 2,j, and similarly for volatile.
+ if (FromType.isMoreQualifiedThan(ToType))
+ return false;
+
+ // -- if the cv 1,j and cv 2,j are different, then const is in
+ // every cv for 0 < k < j.
+ if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
+ && !PreviousToQualsIncludeConst)
+ return false;
+
+ // Keep track of whether all prior cv-qualifiers in the "to" type
+ // include const.
+ PreviousToQualsIncludeConst
+ = PreviousToQualsIncludeConst && ToType.isConstQualified();
+ } while (UnwrappedPointer);
+
+ // We are left with FromType and ToType being the pointee types
+ // after unwrapping the original FromType and ToType the same number
+ // of types. If we unwrapped any pointers, and if FromType and
+ // ToType have the same unqualified type (since we checked
+ // qualifiers above), then this is a qualification conversion.
+ return UnwrappedAnyPointer &&
+ FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
+}
+
/// CompareImplicitConversionSequences - Compare two implicit
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2).
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Oct 21 18:43:52 2008
@@ -500,6 +500,23 @@
return T;
}
+/// GetNonReferenceType - If Type is a reference type (e.g., const
+/// int&), returns the type that the reference refers to ("const
+/// int"). Otherwise, returns the type itself. This routine is used
+/// throughout to implement C++ 5p6:
+///
+/// If an expression initially has the type "reference to T" (8.3.2,
+/// 8.5.3), the type is adjusted to "T" prior to any further
+/// analysis, the expression designates the object or function
+/// denoted by the reference, and the expression is an lvalue.
+QualType Sema::GetNonReferenceType(QualType Type)
+{
+ if (const ReferenceType *RefType = Type->getAsReferenceType())
+ return RefType->getPointeeType();
+ else
+ return Type;
+}
+
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
/// declarator
QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) {
Modified: cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp?rev=57935&r1=57934&r2=57935&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp Tue Oct 21 18:43:52 2008
@@ -38,6 +38,6 @@
int g(C);
void foo() {
- fn(1); // expected-error {{incompatible integer to pointer conversion passing 'int', expected 'int (*)(class C)'}}
+ fn(1); // expected-error {{incompatible type passing 'int', expected 'int (*)(class C)'}}
fn(g); // OK
}
Added: cfe/trunk/test/SemaCXX/qualification-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualification-conversion.cpp?rev=57935&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/qualification-conversion.cpp (added)
+++ cfe/trunk/test/SemaCXX/qualification-conversion.cpp Tue Oct 21 18:43:52 2008
@@ -0,0 +1,11 @@
+// RUN: clang -fsyntax-only -pedantic -verify %s
+int* quals1(int const * p);
+int* quals2(int const * const * pp);
+int* quals3(int const * * const * ppp);
+
+void test_quals(int * p, int * * pp, int * * * ppp) {
+ int const * const * pp2 = pp;
+ quals1(p);
+ quals2(pp);
+ quals3(ppp); // expected-error {{ incompatible type passing 'int ***', expected 'int const **const *' }}
+}
More information about the cfe-commits
mailing list