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 {
#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"
/// - 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;
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;
}
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);
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,
}
// 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,
// 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
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() ||
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).
}
// 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 {
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).
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) {
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
}
--- /dev/null
+// 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 *' }}
+}